VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/IEMR3.cpp@ 105440

Last change on this file since 105440 was 105440, checked in by vboxsync, 6 months ago

VMM/IEM: Added some simple TLB tracing (disabled by default). bugref:10727

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 114.3 KB
Line 
1/* $Id: IEMR3.cpp 105440 2024-07-23 10:50:17Z vboxsync $ */
2/** @file
3 * IEM - Interpreted Execution Manager.
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_EM
33#define VMCPU_INCL_CPUM_GST_CTX
34#include <VBox/vmm/iem.h>
35#include <VBox/vmm/cpum.h>
36#include <VBox/vmm/dbgf.h>
37#include <VBox/vmm/mm.h>
38#if defined(VBOX_VMM_TARGET_ARMV8)
39# include "IEMInternal-armv8.h"
40#else
41# include "IEMInternal.h"
42#endif
43#include <VBox/vmm/vm.h>
44#include <VBox/vmm/vmapi.h>
45#include <VBox/err.h>
46#ifdef VBOX_WITH_DEBUGGER
47# include <VBox/dbg.h>
48#endif
49
50#include <iprt/assert.h>
51#include <iprt/getopt.h>
52#ifdef IEM_WITH_TLB_TRACE
53# include <iprt/mem.h>
54#endif
55#include <iprt/string.h>
56
57#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
58# include "IEMN8veRecompiler.h"
59# include "IEMThreadedFunctions.h"
60# include "IEMInline.h"
61#endif
62
63
64/*********************************************************************************************************************************
65* Internal Functions *
66*********************************************************************************************************************************/
67static FNDBGFINFOARGVINT iemR3InfoITlb;
68static FNDBGFINFOARGVINT iemR3InfoDTlb;
69#ifdef IEM_WITH_TLB_TRACE
70static FNDBGFINFOARGVINT iemR3InfoTlbTrace;
71#endif
72#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
73static FNDBGFINFOARGVINT iemR3InfoTb;
74#endif
75#ifdef VBOX_WITH_DEBUGGER
76static void iemR3RegisterDebuggerCommands(void);
77#endif
78
79
80#if !defined(VBOX_VMM_TARGET_ARMV8)
81static const char *iemGetTargetCpuName(uint32_t enmTargetCpu)
82{
83 switch (enmTargetCpu)
84 {
85#define CASE_RET_STR(enmValue) case enmValue: return #enmValue + (sizeof("IEMTARGETCPU_") - 1)
86 CASE_RET_STR(IEMTARGETCPU_8086);
87 CASE_RET_STR(IEMTARGETCPU_V20);
88 CASE_RET_STR(IEMTARGETCPU_186);
89 CASE_RET_STR(IEMTARGETCPU_286);
90 CASE_RET_STR(IEMTARGETCPU_386);
91 CASE_RET_STR(IEMTARGETCPU_486);
92 CASE_RET_STR(IEMTARGETCPU_PENTIUM);
93 CASE_RET_STR(IEMTARGETCPU_PPRO);
94 CASE_RET_STR(IEMTARGETCPU_CURRENT);
95#undef CASE_RET_STR
96 default: return "Unknown";
97 }
98}
99#endif
100
101
102/**
103 * Initializes the interpreted execution manager.
104 *
105 * This must be called after CPUM as we're quering information from CPUM about
106 * the guest and host CPUs.
107 *
108 * @returns VBox status code.
109 * @param pVM The cross context VM structure.
110 */
111VMMR3DECL(int) IEMR3Init(PVM pVM)
112{
113 /*
114 * Read configuration.
115 */
116#if (!defined(VBOX_VMM_TARGET_ARMV8) && !defined(VBOX_WITHOUT_CPUID_HOST_CALL)) || defined(VBOX_WITH_IEM_RECOMPILER)
117 PCFGMNODE const pIem = CFGMR3GetChild(CFGMR3GetRoot(pVM), "IEM");
118 int rc;
119#endif
120
121#if !defined(VBOX_VMM_TARGET_ARMV8) && !defined(VBOX_WITHOUT_CPUID_HOST_CALL)
122 /** @cfgm{/IEM/CpuIdHostCall, boolean, false}
123 * Controls whether the custom VBox specific CPUID host call interface is
124 * enabled or not. */
125# ifdef DEBUG_bird
126 rc = CFGMR3QueryBoolDef(pIem, "CpuIdHostCall", &pVM->iem.s.fCpuIdHostCall, true);
127# else
128 rc = CFGMR3QueryBoolDef(pIem, "CpuIdHostCall", &pVM->iem.s.fCpuIdHostCall, false);
129# endif
130 AssertLogRelRCReturn(rc, rc);
131#endif
132
133#ifdef VBOX_WITH_IEM_RECOMPILER
134 /** @cfgm{/IEM/MaxTbCount, uint32_t, 524288}
135 * Max number of TBs per EMT. */
136 uint32_t cMaxTbs = 0;
137 rc = CFGMR3QueryU32Def(pIem, "MaxTbCount", &cMaxTbs, _512K);
138 AssertLogRelRCReturn(rc, rc);
139 if (cMaxTbs < _16K || cMaxTbs > _8M)
140 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
141 "MaxTbCount value %u (%#x) is out of range (min %u, max %u)", cMaxTbs, cMaxTbs, _16K, _8M);
142
143 /** @cfgm{/IEM/InitialTbCount, uint32_t, 32678}
144 * Initial (minimum) number of TBs per EMT in ring-3. */
145 uint32_t cInitialTbs = 0;
146 rc = CFGMR3QueryU32Def(pIem, "InitialTbCount", &cInitialTbs, RT_MIN(cMaxTbs, _32K));
147 AssertLogRelRCReturn(rc, rc);
148 if (cInitialTbs < _16K || cInitialTbs > _8M)
149 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
150 "InitialTbCount value %u (%#x) is out of range (min %u, max %u)", cInitialTbs, cInitialTbs, _16K, _8M);
151
152 /* Check that the two values makes sense together. Expect user/api to do
153 the right thing or get lost. */
154 if (cInitialTbs > cMaxTbs)
155 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
156 "InitialTbCount value %u (%#x) is higher than the MaxTbCount value %u (%#x)",
157 cInitialTbs, cInitialTbs, cMaxTbs, cMaxTbs);
158
159 /** @cfgm{/IEM/MaxExecMem, uint64_t, 512 MiB}
160 * Max executable memory for recompiled code per EMT. */
161 uint64_t cbMaxExec = 0;
162 rc = CFGMR3QueryU64Def(pIem, "MaxExecMem", &cbMaxExec, _512M);
163 AssertLogRelRCReturn(rc, rc);
164 if (cbMaxExec < _1M || cbMaxExec > 16*_1G64)
165 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
166 "MaxExecMem value %'RU64 (%#RX64) is out of range (min %'RU64, max %'RU64)",
167 cbMaxExec, cbMaxExec, (uint64_t)_1M, 16*_1G64);
168
169 /** @cfgm{/IEM/ExecChunkSize, uint32_t, 0 (auto)}
170 * The executable memory allocator chunk size. */
171 uint32_t cbChunkExec = 0;
172 rc = CFGMR3QueryU32Def(pIem, "ExecChunkSize", &cbChunkExec, 0);
173 AssertLogRelRCReturn(rc, rc);
174 if (cbChunkExec != 0 && cbChunkExec != UINT32_MAX && (cbChunkExec < _1M || cbChunkExec > _256M))
175 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
176 "ExecChunkSize value %'RU32 (%#RX32) is out of range (min %'RU32, max %'RU32)",
177 cbChunkExec, cbChunkExec, _1M, _256M);
178
179 /** @cfgm{/IEM/InitialExecMemSize, uint64_t, 1}
180 * The initial executable memory allocator size (per EMT). The value is
181 * rounded up to the nearest chunk size, so 1 byte means one chunk. */
182 uint64_t cbInitialExec = 0;
183 rc = CFGMR3QueryU64Def(pIem, "InitialExecMemSize", &cbInitialExec, 0);
184 AssertLogRelRCReturn(rc, rc);
185 if (cbInitialExec > cbMaxExec)
186 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
187 "InitialExecMemSize value %'RU64 (%#RX64) is out of range (max %'RU64)",
188 cbInitialExec, cbInitialExec, cbMaxExec);
189
190 /** @cfgm{/IEM/NativeRecompileAtUsedCount, uint32_t, 16}
191 * The translation block use count value to do native recompilation at. */
192 uint32_t uTbNativeRecompileAtUsedCount = 16;
193 rc = CFGMR3QueryU32Def(pIem, "NativeRecompileAtUsedCount", &uTbNativeRecompileAtUsedCount, 16);
194 AssertLogRelRCReturn(rc, rc);
195
196#endif /* VBOX_WITH_IEM_RECOMPILER*/
197
198 /*
199 * Initialize per-CPU data and register statistics.
200 */
201#if 1
202 uint64_t const uInitialTlbRevision = UINT64_C(0) - (IEMTLB_REVISION_INCR * 200U);
203 uint64_t const uInitialTlbPhysRev = UINT64_C(0) - (IEMTLB_PHYS_REV_INCR * 100U);
204#else
205 uint64_t const uInitialTlbRevision = UINT64_C(0) + (IEMTLB_REVISION_INCR * 4U);
206 uint64_t const uInitialTlbPhysRev = UINT64_C(0) + (IEMTLB_PHYS_REV_INCR * 4U);
207#endif
208
209 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
210 {
211 PVMCPU const pVCpu = pVM->apCpusR3[idCpu];
212 AssertCompile(sizeof(pVCpu->iem.s) <= sizeof(pVCpu->iem.padding)); /* (tstVMStruct can't do it's job w/o instruction stats) */
213
214 pVCpu->iem.s.CodeTlb.uTlbRevision = pVCpu->iem.s.DataTlb.uTlbRevision = uInitialTlbRevision;
215#ifndef VBOX_VMM_TARGET_ARMV8
216 pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal = pVCpu->iem.s.DataTlb.uTlbRevisionGlobal = uInitialTlbRevision;
217#endif
218 pVCpu->iem.s.CodeTlb.uTlbPhysRev = pVCpu->iem.s.DataTlb.uTlbPhysRev = uInitialTlbPhysRev;
219#ifndef VBOX_VMM_TARGET_ARMV8
220 pVCpu->iem.s.CodeTlb.NonGlobalLargePageRange.uFirstTag = UINT64_MAX;
221 pVCpu->iem.s.CodeTlb.GlobalLargePageRange.uFirstTag = UINT64_MAX;
222 pVCpu->iem.s.DataTlb.NonGlobalLargePageRange.uFirstTag = UINT64_MAX;
223 pVCpu->iem.s.DataTlb.GlobalLargePageRange.uFirstTag = UINT64_MAX;
224#endif
225
226 /*
227 * Host and guest CPU information.
228 */
229 if (idCpu == 0)
230 {
231 pVCpu->iem.s.enmCpuVendor = CPUMGetGuestCpuVendor(pVM);
232 pVCpu->iem.s.enmHostCpuVendor = CPUMGetHostCpuVendor(pVM);
233#if !defined(VBOX_VMM_TARGET_ARMV8)
234 pVCpu->iem.s.aidxTargetCpuEflFlavour[0] = pVCpu->iem.s.enmCpuVendor == CPUMCPUVENDOR_INTEL
235 || pVCpu->iem.s.enmCpuVendor == CPUMCPUVENDOR_VIA /*??*/
236 ? IEMTARGETCPU_EFL_BEHAVIOR_INTEL : IEMTARGETCPU_EFL_BEHAVIOR_AMD;
237# if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
238 if (pVCpu->iem.s.enmCpuVendor == pVCpu->iem.s.enmHostCpuVendor)
239 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = IEMTARGETCPU_EFL_BEHAVIOR_NATIVE;
240 else
241# endif
242 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = pVCpu->iem.s.aidxTargetCpuEflFlavour[0];
243#else
244 pVCpu->iem.s.aidxTargetCpuEflFlavour[0] = IEMTARGETCPU_EFL_BEHAVIOR_NATIVE;
245 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = pVCpu->iem.s.aidxTargetCpuEflFlavour[0];
246#endif
247
248#if !defined(VBOX_VMM_TARGET_ARMV8) && (IEM_CFG_TARGET_CPU == IEMTARGETCPU_DYNAMIC)
249 switch (pVM->cpum.ro.GuestFeatures.enmMicroarch)
250 {
251 case kCpumMicroarch_Intel_8086: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_8086; break;
252 case kCpumMicroarch_Intel_80186: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_186; break;
253 case kCpumMicroarch_Intel_80286: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_286; break;
254 case kCpumMicroarch_Intel_80386: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_386; break;
255 case kCpumMicroarch_Intel_80486: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_486; break;
256 case kCpumMicroarch_Intel_P5: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_PENTIUM; break;
257 case kCpumMicroarch_Intel_P6: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_PPRO; break;
258 case kCpumMicroarch_NEC_V20: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_V20; break;
259 case kCpumMicroarch_NEC_V30: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_V20; break;
260 default: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_CURRENT; break;
261 }
262 LogRel(("IEM: TargetCpu=%s, Microarch=%s aidxTargetCpuEflFlavour={%d,%d}\n",
263 iemGetTargetCpuName(pVCpu->iem.s.uTargetCpu), CPUMMicroarchName(pVM->cpum.ro.GuestFeatures.enmMicroarch),
264 pVCpu->iem.s.aidxTargetCpuEflFlavour[0], pVCpu->iem.s.aidxTargetCpuEflFlavour[1]));
265#else
266 LogRel(("IEM: Microarch=%s aidxTargetCpuEflFlavour={%d,%d}\n",
267 CPUMMicroarchName(pVM->cpum.ro.GuestFeatures.enmMicroarch),
268 pVCpu->iem.s.aidxTargetCpuEflFlavour[0], pVCpu->iem.s.aidxTargetCpuEflFlavour[1]));
269#endif
270 }
271 else
272 {
273 pVCpu->iem.s.enmCpuVendor = pVM->apCpusR3[0]->iem.s.enmCpuVendor;
274 pVCpu->iem.s.enmHostCpuVendor = pVM->apCpusR3[0]->iem.s.enmHostCpuVendor;
275 pVCpu->iem.s.aidxTargetCpuEflFlavour[0] = pVM->apCpusR3[0]->iem.s.aidxTargetCpuEflFlavour[0];
276 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = pVM->apCpusR3[0]->iem.s.aidxTargetCpuEflFlavour[1];
277#if IEM_CFG_TARGET_CPU == IEMTARGETCPU_DYNAMIC
278 pVCpu->iem.s.uTargetCpu = pVM->apCpusR3[0]->iem.s.uTargetCpu;
279#endif
280 }
281
282 /*
283 * Mark all buffers free.
284 */
285 uint32_t iMemMap = RT_ELEMENTS(pVCpu->iem.s.aMemMappings);
286 while (iMemMap-- > 0)
287 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
288
289#ifdef VBOX_WITH_IEM_RECOMPILER
290 /*
291 * Distribute recompiler configuration.
292 */
293 pVCpu->iem.s.uTbNativeRecompileAtUsedCount = uTbNativeRecompileAtUsedCount;
294#endif
295
296#ifdef IEM_WITH_TLB_TRACE
297 /*
298 * Allocate trace buffer.
299 */
300 pVCpu->iem.s.idxTlbTraceEntry = 0;
301 pVCpu->iem.s.cTlbTraceEntriesShift = 19;//16;
302 pVCpu->iem.s.paTlbTraceEntries = (PIEMTLBTRACEENTRY)RTMemPageAlloc( RT_BIT_Z(pVCpu->iem.s.cTlbTraceEntriesShift)
303 * sizeof(*pVCpu->iem.s.paTlbTraceEntries));
304 AssertLogRelReturn(pVCpu->iem.s.paTlbTraceEntries, VERR_NO_PAGE_MEMORY);
305#endif
306 }
307
308
309#ifdef VBOX_WITH_IEM_RECOMPILER
310 /*
311 * Initialize the TB allocator and cache (/ hash table).
312 *
313 * This is done by each EMT to try get more optimal thread/numa locality of
314 * the allocations.
315 */
316 rc = VMR3ReqCallWait(pVM, VMCPUID_ALL, (PFNRT)iemTbInit, 6,
317 pVM, cInitialTbs, cMaxTbs, cbInitialExec, cbMaxExec, cbChunkExec);
318 AssertLogRelRCReturn(rc, rc);
319#endif
320
321 /*
322 * Register statistics.
323 */
324 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
325 {
326#if !defined(VBOX_VMM_TARGET_ARMV8) && defined(VBOX_WITH_NESTED_HWVIRT_VMX) /* quick fix for stupid structure duplication non-sense */
327 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
328 char szPat[128];
329 RT_NOREF_PV(szPat); /* lazy bird */
330 char szVal[128];
331 RT_NOREF_PV(szVal); /* lazy bird */
332
333 STAMR3RegisterF(pVM, &pVCpu->iem.s.cInstructions, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
334 "Instructions interpreted", "/IEM/CPU%u/cInstructions", idCpu);
335 STAMR3RegisterF(pVM, &pVCpu->iem.s.cLongJumps, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
336 "Number of longjmp calls", "/IEM/CPU%u/cLongJumps", idCpu);
337 STAMR3RegisterF(pVM, &pVCpu->iem.s.cPotentialExits, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
338 "Potential exits", "/IEM/CPU%u/cPotentialExits", idCpu);
339 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetAspectNotImplemented, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
340 "VERR_IEM_ASPECT_NOT_IMPLEMENTED", "/IEM/CPU%u/cRetAspectNotImplemented", idCpu);
341 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetInstrNotImplemented, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
342 "VERR_IEM_INSTR_NOT_IMPLEMENTED", "/IEM/CPU%u/cRetInstrNotImplemented", idCpu);
343 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetInfStatuses, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
344 "Informational statuses returned", "/IEM/CPU%u/cRetInfStatuses", idCpu);
345 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetErrStatuses, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
346 "Error statuses returned", "/IEM/CPU%u/cRetErrStatuses", idCpu);
347 STAMR3RegisterF(pVM, &pVCpu->iem.s.cbWritten, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
348 "Approx bytes written", "/IEM/CPU%u/cbWritten", idCpu);
349 STAMR3RegisterF(pVM, &pVCpu->iem.s.cPendingCommit, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
350 "Times RC/R0 had to postpone instruction committing to ring-3", "/IEM/CPU%u/cPendingCommit", idCpu);
351 STAMR3RegisterF(pVM, &pVCpu->iem.s.cMisalignedAtomics, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
352 "Number of misaligned (for the host) atomic instructions", "/IEM/CPU%u/cMisalignedAtomics", idCpu);
353
354 /* Code TLB: */
355 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.uTlbRevision, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
356 "Code TLB non-global revision", "/IEM/CPU%u/Tlb/Code/RevisionNonGlobal", idCpu);
357 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
358 "Code TLB global revision", "/IEM/CPU%u/Tlb/Code/RevisionGlobal", idCpu);
359 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlsFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
360 "Code TLB non-global flushes", "/IEM/CPU%u/Tlb/Code/RevisionNonGlobalFlushes", idCpu);
361 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlsGlobalFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
362 "Code TLB global flushes", "/IEM/CPU%u/Tlb/Code/RevisionGlobalFlushes", idCpu);
363 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbRevisionRollovers, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
364 "Code TLB revision rollovers", "/IEM/CPU%u/Tlb/Code/RevisionRollovers", idCpu);
365
366 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.CodeTlb.uTlbPhysRev, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
367 "Code TLB physical revision", "/IEM/CPU%u/Tlb/Code/PhysicalRevision", idCpu);
368 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
369 "Code TLB revision flushes", "/IEM/CPU%u/Tlb/Code/PhysicalRevisionFlushes", idCpu);
370 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbPhysRevRollovers, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
371 "Code TLB revision rollovers", "/IEM/CPU%u/Tlb/Code/PhysicalRevisionRollovers", idCpu);
372
373 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbGlobalLargePageCurLoads, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
374 "Code TLB global large page loads since flush", "/IEM/CPU%u/Tlb/Code/LargePageGlobalCurLoads", idCpu);
375 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.GlobalLargePageRange.uFirstTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
376 "Code TLB global large page range: lowest tag", "/IEM/CPU%u/Tlb/Code/LargePageGlobalFirstTag", idCpu);
377 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.GlobalLargePageRange.uLastTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
378 "Code TLB global large page range: last tag", "/IEM/CPU%u/Tlb/Code/LargePageGlobalLastTag", idCpu);
379
380 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNonGlobalLargePageCurLoads, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
381 "Code TLB non-global large page loads since flush", "/IEM/CPU%u/Tlb/Code/LargePageNonGlobalCurLoads", idCpu);
382 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.NonGlobalLargePageRange.uFirstTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
383 "Code TLB non-global large page range: lowest tag", "/IEM/CPU%u/Tlb/Code/LargePageNonGlobalFirstTag", idCpu);
384 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.NonGlobalLargePageRange.uLastTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
385 "Code TLB non-global large page range: last tag", "/IEM/CPU%u/Tlb/Code/LargePageNonGlobalLastTag", idCpu);
386
387 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbCoreMisses, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
388 "Code TLB misses", "/IEM/CPU%u/Tlb/Code/Misses", idCpu);
389 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbCoreGlobalLoads, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
390 "Code TLB global loads", "/IEM/CPU%u/Tlb/Code/Misses/GlobalLoads", idCpu);
391 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbSlowCodeReadPath, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
392 "Code TLB slow read path", "/IEM/CPU%u/Tlb/Code/SlowReads", idCpu);
393# ifdef IEM_WITH_TLB_STATISTICS
394 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbCoreHits, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
395 "Code TLB hits (non-native)", "/IEM/CPU%u/Tlb/Code/Hits/Other", idCpu);
396# if defined(VBOX_WITH_IEM_NATIVE_RECOMPILER)
397 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCodeTlbHitsForNewPage, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
398 "Code TLB native hits on new page", "/IEM/CPU%u/Tlb/Code/Hits/New-Page", idCpu);
399 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCodeTlbHitsForNewPageWithOffset, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
400 "Code TLB native hits on new page /w offset", "/IEM/CPU%u/Tlb/Code/Hits/New-Page-With-Offset", idCpu);
401# endif
402
403 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Code/Hits/*", idCpu);
404 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Code TLB hits",
405 "/IEM/CPU%u/Tlb/Code/Hits", idCpu);
406
407 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/Tlb/Code/Hits|/IEM/CPU%u/Tlb/Code/Misses", idCpu, idCpu);
408 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Code TLB lookups (sum of hits and misses)",
409 "/IEM/CPU%u/Tlb/Code/AllLookups", idCpu);
410
411 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/Tlb/Code/Misses", idCpu);
412 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Code/Hits", idCpu);
413 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PPM, szVal, true, szPat,
414 "Code TLB actual miss rate", "/IEM/CPU%u/Tlb/Code/RateMisses", idCpu);
415
416# if defined(VBOX_WITH_IEM_NATIVE_RECOMPILER)
417 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNativeMissTag, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
418 "Code TLB misses in native code: Tag mismatch [not directly included grand parent sum]",
419 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown/Tag", idCpu);
420 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNativeMissFlagsAndPhysRev, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
421 "Code TLB misses in native code: Flags or physical revision mistmatch [not directly included grand parent sum]",
422 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown/FlagsAndPhysRev", idCpu);
423 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNativeMissAlignment, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
424 "Code TLB misses in native code: Alignment [not directly included grand parent sum]",
425 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown/Alignment", idCpu);
426 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNativeMissCrossPage, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
427 "Code TLB misses in native code: Cross page [not directly included grand parent sum]",
428 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown/CrossPage", idCpu);
429 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNativeMissNonCanonical, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
430 "Code TLB misses in native code: Non-canonical [not directly included grand parent sum]",
431 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown/NonCanonical", idCpu);
432
433 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCodeTlbMissesNewPage, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
434 "Code TLB native misses on new page",
435 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown2/New-Page", idCpu);
436 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCodeTlbMissesNewPageWithOffset, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
437 "Code TLB native misses on new page w/ offset",
438 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown2/New-Page-With-Offset", idCpu);
439# endif
440# endif /* IEM_WITH_TLB_STATISTICS */
441
442 /* Data TLB organized as best we can... */
443 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.uTlbRevision, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
444 "Data TLB non-global revision", "/IEM/CPU%u/Tlb/Data/RevisionNonGlobal", idCpu);
445 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.uTlbRevisionGlobal, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
446 "Data TLB global revision", "/IEM/CPU%u/Tlb/Data/RevisionGlobal", idCpu);
447 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlsFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
448 "Data TLB non-global flushes", "/IEM/CPU%u/Tlb/Data/RevisionNonGlobalFlushes", idCpu);
449 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlsGlobalFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
450 "Data TLB global flushes", "/IEM/CPU%u/Tlb/Data/RevisionGlobalFlushes", idCpu);
451 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbRevisionRollovers, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
452 "Data TLB revision rollovers", "/IEM/CPU%u/Tlb/Data/RevisionRollovers", idCpu);
453
454 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.DataTlb.uTlbPhysRev, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
455 "Data TLB physical revision", "/IEM/CPU%u/Tlb/Data/PhysicalRevision", idCpu);
456 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
457 "Data TLB revision flushes", "/IEM/CPU%u/Tlb/Data/PhysicalRevisionFlushes", idCpu);
458 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbPhysRevRollovers, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
459 "Data TLB revision rollovers", "/IEM/CPU%u/Tlb/Data/PhysicalRevisionRollovers", idCpu);
460
461 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbGlobalLargePageCurLoads, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
462 "Data TLB global large page loads since flush", "/IEM/CPU%u/Tlb/Data/LargePageGlobalCurLoads", idCpu);
463 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.GlobalLargePageRange.uFirstTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
464 "Data TLB global large page range: lowest tag", "/IEM/CPU%u/Tlb/Data/LargePageGlobalFirstTag", idCpu);
465 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.GlobalLargePageRange.uLastTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
466 "Data TLB global large page range: last tag", "/IEM/CPU%u/Tlb/Data/LargePageGlobalLastTag", idCpu);
467
468 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNonGlobalLargePageCurLoads, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
469 "Data TLB non-global large page loads since flush", "/IEM/CPU%u/Tlb/Data/LargePageNonGlobalCurLoads", idCpu);
470 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.NonGlobalLargePageRange.uFirstTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
471 "Data TLB non-global large page range: lowest tag", "/IEM/CPU%u/Tlb/Data/LargePageNonGlobalFirstTag", idCpu);
472 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.NonGlobalLargePageRange.uLastTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
473 "Data TLB non-global large page range: last tag", "/IEM/CPU%u/Tlb/Data/LargePageNonGlobalLastTag", idCpu);
474
475 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbCoreMisses, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
476 "Data TLB core misses (iemMemMap, direct iemMemMapJmp (not safe path))",
477 "/IEM/CPU%u/Tlb/Data/Misses/Core", idCpu);
478 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbCoreGlobalLoads, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
479 "Data TLB global loads",
480 "/IEM/CPU%u/Tlb/Data/Misses/Core/GlobalLoads", idCpu);
481 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbSafeReadPath, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
482 "Data TLB safe read path (inline/native misses going to iemMemMapJmp)",
483 "/IEM/CPU%u/Tlb/Data/Misses/Safe/Reads", idCpu);
484 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbSafeWritePath, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
485 "Data TLB safe write path (inline/native misses going to iemMemMapJmp)",
486 "/IEM/CPU%u/Tlb/Data/Misses/Safe/Writes", idCpu);
487 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Data/Misses/*", idCpu);
488 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Data TLB misses",
489 "/IEM/CPU%u/Tlb/Data/Misses", idCpu);
490
491 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Data/Misses/Safe/*", idCpu);
492 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Data TLB actual safe path calls (read + write)",
493 "/IEM/CPU%u/Tlb/Data/Misses/Safe", idCpu);
494 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbSafeHits, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
495 "Data TLB hits in iemMemMapJmp - not part of safe-path total",
496 "/IEM/CPU%u/Tlb/Data/Misses/Safe/SubPartHits", idCpu);
497 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbSafeMisses, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
498 "Data TLB misses in iemMemMapJmp - not part of safe-path total",
499 "/IEM/CPU%u/Tlb/Data/Misses/Safe/SubPartMisses", idCpu);
500 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbSafeGlobalLoads, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
501 "Data TLB global loads",
502 "/IEM/CPU%u/Tlb/Data/Misses/Safe/SubPartMisses/GlobalLoads", idCpu);
503
504# ifdef IEM_WITH_TLB_STATISTICS
505# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
506 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNativeMissTag, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
507 "Data TLB misses in native code: Tag mismatch [not directly included grand parent sum]",
508 "/IEM/CPU%u/Tlb/Data/Misses/NativeBreakdown/Tag", idCpu);
509 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNativeMissFlagsAndPhysRev, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
510 "Data TLB misses in native code: Flags or physical revision mistmatch [not directly included grand parent sum]",
511 "/IEM/CPU%u/Tlb/Data/Misses/NativeBreakdown/FlagsAndPhysRev", idCpu);
512 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNativeMissAlignment, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
513 "Data TLB misses in native code: Alignment [not directly included grand parent sum]",
514 "/IEM/CPU%u/Tlb/Data/Misses/NativeBreakdown/Alignment", idCpu);
515 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNativeMissCrossPage, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
516 "Data TLB misses in native code: Cross page [not directly included grand parent sum]",
517 "/IEM/CPU%u/Tlb/Data/Misses/NativeBreakdown/CrossPage", idCpu);
518 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNativeMissNonCanonical, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
519 "Data TLB misses in native code: Non-canonical [not directly included grand parent sum]",
520 "/IEM/CPU%u/Tlb/Data/Misses/NativeBreakdown/NonCanonical", idCpu);
521# endif
522# endif
523
524# ifdef IEM_WITH_TLB_STATISTICS
525 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbCoreHits, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
526 "Data TLB core hits (iemMemMap, direct iemMemMapJmp (not safe path))",
527 "/IEM/CPU%u/Tlb/Data/Hits/Core", idCpu);
528 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbInlineCodeHits, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
529 "Data TLB hits in IEMAllMemRWTmplInline.cpp.h",
530 "/IEM/CPU%u/Tlb/Data/Hits/Inline", idCpu);
531# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
532 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeTlbHitsForStack, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
533 "Data TLB native stack access hits",
534 "/IEM/CPU%u/Tlb/Data/Hits/Native/Stack", idCpu);
535 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeTlbHitsForFetch, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
536 "Data TLB native data fetch hits",
537 "/IEM/CPU%u/Tlb/Data/Hits/Native/Fetch", idCpu);
538 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeTlbHitsForStore, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
539 "Data TLB native data store hits",
540 "/IEM/CPU%u/Tlb/Data/Hits/Native/Store", idCpu);
541 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeTlbHitsForMapped, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
542 "Data TLB native mapped data hits",
543 "/IEM/CPU%u/Tlb/Data/Hits/Native/Mapped", idCpu);
544# endif
545 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Data/Hits/*", idCpu);
546 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Data TLB hits",
547 "/IEM/CPU%u/Tlb/Data/Hits", idCpu);
548
549# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
550 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Data/Hits/Native/*", idCpu);
551 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Data TLB hits from native code",
552 "/IEM/CPU%u/Tlb/Data/Hits/Native", idCpu);
553# endif
554
555 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/Tlb/Data/Hits|/IEM/CPU%u/Tlb/Data/Misses", idCpu, idCpu);
556 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Data TLB lookups (sum of hits and misses)",
557 "/IEM/CPU%u/Tlb/Data/AllLookups", idCpu);
558
559 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/Tlb/Data/Misses", idCpu);
560 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Data/Hits", idCpu);
561 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PPM, szVal, true, szPat,
562 "Data TLB actual miss rate", "/IEM/CPU%u/Tlb/Data/RateMisses", idCpu);
563
564# endif /* IEM_WITH_TLB_STATISTICS */
565
566
567#ifdef VBOX_WITH_IEM_RECOMPILER
568 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.cTbExecNative, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
569 "Executed native translation block", "/IEM/CPU%u/re/cTbExecNative", idCpu);
570 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.cTbExecThreaded, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
571 "Executed threaded translation block", "/IEM/CPU%u/re/cTbExecThreaded", idCpu);
572 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbThreadedExecBreaks, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
573 "Times threaded TB execution was interrupted/broken off", "/IEM/CPU%u/re/cTbExecThreadedBreaks", idCpu);
574# ifdef VBOX_WITH_STATISTICS
575 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbThreadedExecBreaksWithLookup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
576 "Times threaded TB execution was interrupted/broken off on a call with lookup entries", "/IEM/CPU%u/re/cTbExecThreadedBreaksWithLookup", idCpu);
577 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbThreadedExecBreaksWithoutLookup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
578 "Times threaded TB execution was interrupted/broken off on a call without lookup entries", "/IEM/CPU%u/re/cTbExecThreadedBreaksWithoutLookup", idCpu);
579# endif
580
581 PIEMTBALLOCATOR const pTbAllocator = pVCpu->iem.s.pTbAllocatorR3;
582 STAMR3RegisterF(pVM, (void *)&pTbAllocator->StatAllocs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS,
583 "Translation block allocations", "/IEM/CPU%u/re/cTbAllocCalls", idCpu);
584 STAMR3RegisterF(pVM, (void *)&pTbAllocator->StatFrees, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS,
585 "Translation block frees", "/IEM/CPU%u/re/cTbFreeCalls", idCpu);
586# ifdef VBOX_WITH_STATISTICS
587 STAMR3RegisterF(pVM, (void *)&pTbAllocator->StatPrune, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
588 "Time spent freeing up TBs when full at alloc", "/IEM/CPU%u/re/TbPruningAlloc", idCpu);
589# endif
590 STAMR3RegisterF(pVM, (void *)&pTbAllocator->StatPruneNative, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
591 "Time spent freeing up native TBs when out of executable memory", "/IEM/CPU%u/re/ExecMem/TbPruningNative", idCpu);
592 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cAllocatedChunks, STAMTYPE_U16, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
593 "Populated TB chunks", "/IEM/CPU%u/re/cTbChunks", idCpu);
594 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cMaxChunks, STAMTYPE_U8, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
595 "Max number of TB chunks", "/IEM/CPU%u/re/cTbChunksMax", idCpu);
596 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cTotalTbs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
597 "Total number of TBs in the allocator", "/IEM/CPU%u/re/cTbTotal", idCpu);
598 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cMaxTbs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
599 "Max total number of TBs allowed", "/IEM/CPU%u/re/cTbTotalMax", idCpu);
600 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cInUseTbs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
601 "Number of currently allocated TBs", "/IEM/CPU%u/re/cTbAllocated", idCpu);
602 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cNativeTbs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
603 "Number of currently allocated native TBs", "/IEM/CPU%u/re/cTbAllocatedNative", idCpu);
604 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cThreadedTbs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
605 "Number of currently allocated threaded TBs", "/IEM/CPU%u/re/cTbAllocatedThreaded", idCpu);
606
607 PIEMTBCACHE const pTbCache = pVCpu->iem.s.pTbCacheR3;
608 STAMR3RegisterF(pVM, (void *)&pTbCache->cHash, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
609 "Translation block lookup table size", "/IEM/CPU%u/re/cTbHashTab", idCpu);
610
611 STAMR3RegisterF(pVM, (void *)&pTbCache->cLookupHits, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
612 "Translation block lookup hits", "/IEM/CPU%u/re/cTbLookupHits", idCpu);
613 STAMR3RegisterF(pVM, (void *)&pTbCache->cLookupHitsViaTbLookupTable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
614 "Translation block lookup hits via TB lookup table associated with the previous TB", "/IEM/CPU%u/re/cTbLookupHitsViaTbLookupTable", idCpu);
615 STAMR3RegisterF(pVM, (void *)&pTbCache->cLookupMisses, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
616 "Translation block lookup misses", "/IEM/CPU%u/re/cTbLookupMisses", idCpu);
617 STAMR3RegisterF(pVM, (void *)&pTbCache->cCollisions, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
618 "Translation block hash table collisions", "/IEM/CPU%u/re/cTbCollisions", idCpu);
619# ifdef VBOX_WITH_STATISTICS
620 STAMR3RegisterF(pVM, (void *)&pTbCache->StatPrune, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
621 "Time spent shortening collision lists", "/IEM/CPU%u/re/TbPruningCollisions", idCpu);
622# endif
623
624 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbThreadedCalls, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS_PER_TB,
625 "Calls per threaded translation block", "/IEM/CPU%u/re/ThrdCallsPerTb", idCpu);
626 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbInstr, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_INSTR_PER_TB,
627 "Instruction per threaded translation block", "/IEM/CPU%u/re/ThrdInstrPerTb", idCpu);
628 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbLookupEntries, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_INSTR_PER_TB,
629 "TB lookup table entries per threaded translation block", "/IEM/CPU%u/re/ThrdLookupEntriesPerTb", idCpu);
630
631 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatCheckIrqBreaks, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
632 "TB breaks by CheckIrq", "/IEM/CPU%u/re/CheckIrqBreaks", idCpu);
633 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatCheckModeBreaks, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
634 "TB breaks by CheckMode", "/IEM/CPU%u/re/CheckModeBreaks", idCpu);
635 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatCheckBranchMisses, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
636 "Branch target misses", "/IEM/CPU%u/re/CheckTbJmpMisses", idCpu);
637 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatCheckNeedCsLimChecking, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
638 "Needing CS.LIM checking TB after branch or on page crossing", "/IEM/CPU%u/re/CheckTbNeedCsLimChecking", idCpu);
639# ifdef VBOX_WITH_STATISTICS
640 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbLoopInTbDetected, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
641 "Detected loop within TB", "/IEM/CPU%u/re/LoopInTbDetected", idCpu);
642#endif
643
644 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeExecMemInstrBufAllocFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
645 "Number of times the exec memory allocator failed to allocate a large enough buffer",
646 "/IEM/CPU%u/re/NativeExecMemInstrBufAllocFailed", idCpu);
647
648 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCallsRecompiled, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS_PER_TB,
649 "Number of threaded calls per TB that have been properly recompiled to native code",
650 "/IEM/CPU%u/re/NativeCallsRecompiledPerTb", idCpu);
651 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCallsThreaded, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS_PER_TB,
652 "Number of threaded calls per TB that could not be recompiler to native code",
653 "/IEM/CPU%u/re/NativeCallsThreadedPerTb", idCpu);
654 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeFullyRecompiledTbs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
655 "Number of threaded calls that could not be recompiler to native code",
656 "/IEM/CPU%u/re/NativeFullyRecompiledTbs", idCpu);
657
658 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbNativeCode, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES_PER_TB,
659 "Size of native code per TB", "/IEM/CPU%u/re/NativeCodeSizePerTb", idCpu);
660 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeRecompilation, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
661 "Profiling iemNativeRecompile()", "/IEM/CPU%u/re/NativeRecompilation", idCpu);
662
663# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
664# ifdef VBOX_WITH_STATISTICS
665 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeRegFindFree, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
666 "Number of calls to iemNativeRegAllocFindFree.",
667 "/IEM/CPU%u/re/NativeRegFindFree", idCpu);
668# endif
669 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeRegFindFreeVar, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
670 "Number of times iemNativeRegAllocFindFree needed to free a variable.",
671 "/IEM/CPU%u/re/NativeRegFindFreeVar", idCpu);
672# ifdef VBOX_WITH_STATISTICS
673 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeRegFindFreeNoVar, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
674 "Number of times iemNativeRegAllocFindFree did not needed to free any variables.",
675 "/IEM/CPU%u/re/NativeRegFindFreeNoVar", idCpu);
676 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeRegFindFreeLivenessUnshadowed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
677 "Times liveness info freeed up shadowed guest registers in iemNativeRegAllocFindFree.",
678 "/IEM/CPU%u/re/NativeRegFindFreeLivenessUnshadowed", idCpu);
679 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeRegFindFreeLivenessHelped, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
680 "Times liveness info helped finding the return register in iemNativeRegAllocFindFree.",
681 "/IEM/CPU%u/re/NativeRegFindFreeLivenessHelped", idCpu);
682
683 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflSkippedArithmetic, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
684 "Skipped all status flag updating, arithmetic instructions",
685 "/IEM/CPU%u/re/NativeEFlagsSkippedArithmetic", idCpu);
686 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflSkippedLogical, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
687 "Skipped all status flag updating, logical instructions",
688 "/IEM/CPU%u/re/NativeEFlagsSkippedLogical", idCpu);
689
690 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflCfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.CF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsCfSkippable", idCpu);
691 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflPfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.PF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsPfSkippable", idCpu);
692 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflAfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.AF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsAfSkippable", idCpu);
693 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflZfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.ZF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsZfSkippable", idCpu);
694 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflSfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.SF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsSfSkippable", idCpu);
695 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflOfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.OF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsOfSkippable", idCpu);
696
697 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflCfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.CF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsCfRequired", idCpu);
698 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflPfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.PF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsPfRequired", idCpu);
699 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflAfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.AF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsAfRequired", idCpu);
700 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflZfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.ZF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsZfRequired", idCpu);
701 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflSfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.SF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsSfRequired", idCpu);
702 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflOfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.OF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsOfRequired", idCpu);
703
704# ifdef IEMLIVENESS_EXTENDED_LAYOUT
705 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflCfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.CF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsCfDelayable", idCpu);
706 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflPfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.PF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsPfDelayable", idCpu);
707 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflAfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.AF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsAfDelayable", idCpu);
708 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflZfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.ZF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsZfDelayable", idCpu);
709 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflSfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.SF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsSfDelayable", idCpu);
710 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflOfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.OF updating", "/IEM/CPU%u/re/NativeLivenessEFlagsOfDelayable", idCpu);
711# endif
712
713 /* Sum up all status bits ('_' is a sorting hack). */
714 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags?fSkippable*", idCpu);
715 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Total skippable EFLAGS status bit updating",
716 "/IEM/CPU%u/re/NativeLivenessEFlags_StatusSkippable", idCpu);
717
718 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags?fRequired*", idCpu);
719 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Total required STATUS status bit updating",
720 "/IEM/CPU%u/re/NativeLivenessEFlags_StatusRequired", idCpu);
721
722# ifdef IEMLIVENESS_EXTENDED_LAYOUT
723 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags?fDelayable*", idCpu);
724 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Total potentially delayable STATUS status bit updating",
725 "/IEM/CPU%u/re/NativeLivenessEFlags_StatusDelayable", idCpu);
726# endif
727
728 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags?f*", idCpu);
729 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Total STATUS status bit events of any kind",
730 "/IEM/CPU%u/re/NativeLivenessEFlags_StatusTotal", idCpu);
731
732 /* Ratio of the status bit skippables. */
733 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags_StatusTotal", idCpu);
734 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeLivenessEFlags_StatusSkippable", idCpu);
735 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
736 "Total skippable EFLAGS status bit updating percentage",
737 "/IEM/CPU%u/re/NativeLivenessEFlags_StatusSkippablePct", idCpu);
738
739# ifdef IEMLIVENESS_EXTENDED_LAYOUT
740 /* Ratio of the status bit skippables. */
741 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeLivenessEFlags_StatusDelayable", idCpu);
742 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
743 "Total potentially delayable EFLAGS status bit updating percentage",
744 "/IEM/CPU%u/re/NativeLivenessEFlags_StatusDelayablePct", idCpu);
745# endif
746
747 /* Ratios of individual bits. */
748 size_t const offFlagChar = RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlagsCf*", idCpu) - 3;
749 Assert(szPat[offFlagChar] == 'C');
750 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeLivenessEFlagsCfSkippable", idCpu);
751 Assert(szVal[offFlagChar] == 'C');
752 szPat[offFlagChar] = szVal[offFlagChar] = 'C'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.CF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlagsCfSkippablePct", idCpu);
753 szPat[offFlagChar] = szVal[offFlagChar] = 'P'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.PF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlagsPfSkippablePct", idCpu);
754 szPat[offFlagChar] = szVal[offFlagChar] = 'A'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.AF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlagsAfSkippablePct", idCpu);
755 szPat[offFlagChar] = szVal[offFlagChar] = 'Z'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.ZF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlagsZfSkippablePct", idCpu);
756 szPat[offFlagChar] = szVal[offFlagChar] = 'S'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.SF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlagsSfSkippablePct", idCpu);
757 szPat[offFlagChar] = szVal[offFlagChar] = 'O'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.OF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlagsOfSkippablePct", idCpu);
758
759 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativePcUpdateTotal, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Total RIP updates", "/IEM/CPU%u/re/NativePcUpdateTotal", idCpu);
760 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativePcUpdateDelayed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Delayed RIP updates", "/IEM/CPU%u/re/NativePcUpdateDelayed", idCpu);
761
762# ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
763 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeSimdRegFindFree, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
764 "Number of calls to iemNativeSimdRegAllocFindFree.",
765 "/IEM/CPU%u/re/NativeSimdRegFindFree", idCpu);
766 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeSimdRegFindFreeVar, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
767 "Number of times iemNativeSimdRegAllocFindFree needed to free a variable.",
768 "/IEM/CPU%u/re/NativeSimdRegFindFreeVar", idCpu);
769 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeSimdRegFindFreeNoVar, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
770 "Number of times iemNativeSimdRegAllocFindFree did not needed to free any variables.",
771 "/IEM/CPU%u/re/NativeSimdRegFindFreeNoVar", idCpu);
772 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeSimdRegFindFreeLivenessUnshadowed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
773 "Times liveness info freeed up shadowed guest registers in iemNativeSimdRegAllocFindFree.",
774 "/IEM/CPU%u/re/NativeSimdRegFindFreeLivenessUnshadowed", idCpu);
775 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeSimdRegFindFreeLivenessHelped, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
776 "Times liveness info helped finding the return register in iemNativeSimdRegAllocFindFree.",
777 "/IEM/CPU%u/re/NativeSimdRegFindFreeLivenessHelped", idCpu);
778
779 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeDeviceNotAvailXcptCheckPotential, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Potential IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE() checks",
780 "/IEM/CPU%u/re/NativeMaybeDeviceNotAvailXcptCheckPotential", idCpu);
781 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeWaitDeviceNotAvailXcptCheckPotential, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Potential IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE() checks",
782 "/IEM/CPU%u/re/NativeMaybeWaitDeviceNotAvailXcptCheckPotential", idCpu);
783 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeSseXcptCheckPotential, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Potential IEM_MC_MAYBE_RAISE_SSE_RELATED_XCPT() checks",
784 "/IEM/CPU%u/re/NativeMaybeSseXcptCheckPotential", idCpu);
785 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeAvxXcptCheckPotential, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Potential IEM_MC_MAYBE_RAISE_AVX_RELATED_XCPT() checks",
786 "/IEM/CPU%u/re/NativeMaybeAvxXcptCheckPotential", idCpu);
787
788 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeDeviceNotAvailXcptCheckOmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE() checks omitted",
789 "/IEM/CPU%u/re/NativeMaybeDeviceNotAvailXcptCheckOmitted", idCpu);
790 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeWaitDeviceNotAvailXcptCheckOmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE() checks omitted",
791 "/IEM/CPU%u/re/NativeMaybeWaitDeviceNotAvailXcptCheckOmitted", idCpu);
792 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeSseXcptCheckOmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "IEM_MC_MAYBE_RAISE_SSE_RELATED_XCPT() checks omitted",
793 "/IEM/CPU%u/re/NativeMaybeSseXcptCheckOmitted", idCpu);
794 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeAvxXcptCheckOmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "IEM_MC_MAYBE_RAISE_AVX_RELATED_XCPT() checks omitted",
795 "/IEM/CPU%u/re/NativeMaybeAvxXcptCheckOmitted", idCpu);
796# endif
797
798 /* Ratio of the status bit skippables. */
799 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativePcUpdateTotal", idCpu);
800 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativePcUpdateDelayed", idCpu);
801 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
802 "Delayed RIP updating percentage",
803 "/IEM/CPU%u/re/NativePcUpdateDelayed_StatusDelayedPct", idCpu);
804
805 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbFinished, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
806 "Number of times the TB finishes execution completely",
807 "/IEM/CPU%u/re/NativeTbFinished", idCpu);
808# endif /* VBOX_WITH_STATISTICS */
809 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitReturnBreak, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
810 "Number of times the TB finished through the ReturnBreak label",
811 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak", idCpu);
812 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitReturnBreakFF, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
813 "Number of times the TB finished through the ReturnBreak label",
814 "/IEM/CPU%u/re/NativeTbExit/ReturnBreakFF", idCpu);
815 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitReturnWithFlags, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
816 "Number of times the TB finished through the ReturnWithFlags label",
817 "/IEM/CPU%u/re/NativeTbExit/ReturnWithFlags", idCpu);
818 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitReturnOtherStatus, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
819 "Number of times the TB finished with some other status value",
820 "/IEM/CPU%u/re/NativeTbExit/ReturnOtherStatus", idCpu);
821 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitLongJump, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
822 "Number of times the TB finished via long jump / throw",
823 "/IEM/CPU%u/re/NativeTbExit/LongJumps", idCpu);
824 /* These end up returning VINF_IEM_REEXEC_BREAK and are thus already counted under NativeTbExit/ReturnBreak: */
825 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitObsoleteTb, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
826 "Number of times the TB finished through the ObsoleteTb label",
827 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/ObsoleteTb", idCpu);
828 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatCheckNeedCsLimChecking, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
829 "Number of times the TB finished through the NeedCsLimChecking label",
830 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/NeedCsLimChecking", idCpu);
831 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatCheckBranchMisses, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
832 "Number of times the TB finished through the CheckBranchMiss label",
833 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/CheckBranchMiss", idCpu);
834 /* Raising stuff will either increment NativeTbExit/LongJumps or NativeTbExit/ReturnOtherStatus
835 depending on whether VBOX_WITH_IEM_NATIVE_RECOMPILER_LONGJMP is defined: */
836# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER_LONGJMP
837# define RAISE_PREFIX "/IEM/CPU%u/re/NativeTbExit/ReturnOtherStatus/"
838# else
839# define RAISE_PREFIX "/IEM/CPU%u/re/NativeTbExit/LongJumps/"
840# endif
841 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseDe, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
842 "Number of times the TB finished raising a #DE exception",
843 RAISE_PREFIX "RaiseDe", idCpu);
844 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseUd, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
845 "Number of times the TB finished raising a #UD exception",
846 RAISE_PREFIX "RaiseUd", idCpu);
847 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseSseRelated, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
848 "Number of times the TB finished raising a SSE related exception",
849 RAISE_PREFIX "RaiseSseRelated", idCpu);
850 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseAvxRelated, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
851 "Number of times the TB finished raising a AVX related exception",
852 RAISE_PREFIX "RaiseAvxRelated", idCpu);
853 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseSseAvxFpRelated, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
854 "Number of times the TB finished raising a SSE/AVX floating point related exception",
855 RAISE_PREFIX "RaiseSseAvxFpRelated", idCpu);
856 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseNm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
857 "Number of times the TB finished raising a #NM exception",
858 RAISE_PREFIX "RaiseNm", idCpu);
859 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseGp0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
860 "Number of times the TB finished raising a #GP(0) exception",
861 RAISE_PREFIX "RaiseGp0", idCpu);
862 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseMf, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
863 "Number of times the TB finished raising a #MF exception",
864 RAISE_PREFIX "RaiseMf", idCpu);
865 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseXf, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
866 "Number of times the TB finished raising a #XF exception",
867 RAISE_PREFIX "RaiseXf", idCpu);
868
869 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1Irq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
870 "Direct linking #1 with IRQ check succeeded",
871 "/IEM/CPU%u/re/NativeTbExit/DirectLinking1Irq", idCpu);
872 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1NoIrq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
873 "Direct linking #1 w/o IRQ check succeeded",
874 "/IEM/CPU%u/re/NativeTbExit/DirectLinking1NoIrq", idCpu);
875# ifdef VBOX_WITH_STATISTICS
876 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1NoTb, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
877 "Direct linking #1 failed: No TB in lookup table",
878 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking1NoTb", idCpu);
879 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1MismatchGCPhysPc, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
880 "Direct linking #1 failed: GCPhysPc mismatch",
881 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking1MismatchGCPhysPc", idCpu);
882 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1MismatchFlags, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
883 "Direct linking #1 failed: TB flags mismatch",
884 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking1MismatchFlags", idCpu);
885 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1PendingIrq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
886 "Direct linking #1 failed: IRQ or FF pending",
887 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking1PendingIrq", idCpu);
888# endif
889
890 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2Irq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
891 "Direct linking #2 with IRQ check succeeded",
892 "/IEM/CPU%u/re/NativeTbExit/DirectLinking2Irq", idCpu);
893 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2NoIrq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
894 "Direct linking #2 w/o IRQ check succeeded",
895 "/IEM/CPU%u/re/NativeTbExit/DirectLinking2NoIrq", idCpu);
896# ifdef VBOX_WITH_STATISTICS
897 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2NoTb, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
898 "Direct linking #2 failed: No TB in lookup table",
899 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking2NoTb", idCpu);
900 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2MismatchGCPhysPc, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
901 "Direct linking #2 failed: GCPhysPc mismatch",
902 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking2MismatchGCPhysPc", idCpu);
903 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2MismatchFlags, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
904 "Direct linking #2 failed: TB flags mismatch",
905 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking2MismatchFlags", idCpu);
906 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2PendingIrq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
907 "Direct linking #2 failed: IRQ or FF pending",
908 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking2PendingIrq", idCpu);
909# endif
910
911 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeTbExit/*", idCpu); /* only immediate children, no sub folders */
912 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat,
913 "Number of times native TB execution finished before the end (not counting thrown memory++ exceptions)",
914 "/IEM/CPU%u/re/NativeTbExit", idCpu);
915
916
917# endif /* VBOX_WITH_IEM_NATIVE_RECOMPILER */
918
919
920# ifdef VBOX_WITH_STATISTICS
921 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatMemMapJmp, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
922 "iemMemMapJmp calls", "/IEM/CPU%u/iemMemMapJmp", idCpu);
923 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatMemMapNoJmp, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
924 "iemMemMap calls", "/IEM/CPU%u/iemMemMapNoJmp", idCpu);
925 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatMemBounceBufferCrossPage, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
926 "iemMemBounceBufferMapCrossPage calls", "/IEM/CPU%u/iemMemMapBounceBufferCrossPage", idCpu);
927 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatMemBounceBufferMapPhys, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
928 "iemMemBounceBufferMapPhys calls", "/IEM/CPU%u/iemMemMapBounceBufferMapPhys", idCpu);
929# endif
930
931
932#endif /* VBOX_WITH_IEM_RECOMPILER */
933
934 for (uint32_t i = 0; i < RT_ELEMENTS(pVCpu->iem.s.aStatXcpts); i++)
935 STAMR3RegisterF(pVM, &pVCpu->iem.s.aStatXcpts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
936 "", "/IEM/CPU%u/Exceptions/%02x", idCpu, i);
937 for (uint32_t i = 0; i < RT_ELEMENTS(pVCpu->iem.s.aStatInts); i++)
938 STAMR3RegisterF(pVM, &pVCpu->iem.s.aStatInts[i], STAMTYPE_U32_RESET, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
939 "", "/IEM/CPU%u/Interrupts/%02x", idCpu, i);
940
941# if !defined(VBOX_VMM_TARGET_ARMV8) && defined(VBOX_WITH_STATISTICS) && !defined(DOXYGEN_RUNNING)
942 /* Instruction statistics: */
943# define IEM_DO_INSTR_STAT(a_Name, a_szDesc) \
944 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatsRZ.a_Name, STAMTYPE_U32_RESET, STAMVISIBILITY_USED, \
945 STAMUNIT_COUNT, a_szDesc, "/IEM/CPU%u/instr-RZ/" #a_Name, idCpu); \
946 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatsR3.a_Name, STAMTYPE_U32_RESET, STAMVISIBILITY_USED, \
947 STAMUNIT_COUNT, a_szDesc, "/IEM/CPU%u/instr-R3/" #a_Name, idCpu);
948# include "IEMInstructionStatisticsTmpl.h"
949# undef IEM_DO_INSTR_STAT
950# endif
951
952# if defined(VBOX_WITH_STATISTICS) && defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
953 /* Threaded function statistics: */
954 for (unsigned i = 1; i < (unsigned)kIemThreadedFunc_End; i++)
955 STAMR3RegisterF(pVM, &pVCpu->iem.s.acThreadedFuncStats[i], STAMTYPE_U32_RESET, STAMVISIBILITY_USED,
956 STAMUNIT_COUNT, NULL, "/IEM/CPU%u/ThrdFuncs/%s", idCpu, g_apszIemThreadedFunctionStats[i]);
957# endif
958
959#endif /* !defined(VBOX_VMM_TARGET_ARMV8) && defined(VBOX_WITH_NESTED_HWVIRT_VMX) - quick fix for stupid structure duplication non-sense */
960 }
961
962#if !defined(VBOX_VMM_TARGET_ARMV8) && defined(VBOX_WITH_NESTED_HWVIRT_VMX)
963 /*
964 * Register the per-VM VMX APIC-access page handler type.
965 */
966 if (pVM->cpum.ro.GuestFeatures.fVmx)
967 {
968 rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_ALL, PGMPHYSHANDLER_F_NOT_IN_HM,
969 iemVmxApicAccessPageHandler,
970 "VMX APIC-access page", &pVM->iem.s.hVmxApicAccessPage);
971 AssertLogRelRCReturn(rc, rc);
972 }
973#endif
974
975 DBGFR3InfoRegisterInternalArgv(pVM, "itlb", "IEM instruction TLB", iemR3InfoITlb, DBGFINFO_FLAGS_RUN_ON_EMT);
976 DBGFR3InfoRegisterInternalArgv(pVM, "dtlb", "IEM instruction TLB", iemR3InfoDTlb, DBGFINFO_FLAGS_RUN_ON_EMT);
977#ifdef IEM_WITH_TLB_TRACE
978 DBGFR3InfoRegisterInternalArgv(pVM, "tlbtrace", "IEM TLB trace log", iemR3InfoTlbTrace, DBGFINFO_FLAGS_RUN_ON_EMT);
979#endif
980#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
981 DBGFR3InfoRegisterInternalArgv(pVM, "tb", "IEM translation block", iemR3InfoTb, DBGFINFO_FLAGS_RUN_ON_EMT);
982#endif
983#ifdef VBOX_WITH_DEBUGGER
984 iemR3RegisterDebuggerCommands();
985#endif
986
987 return VINF_SUCCESS;
988}
989
990
991VMMR3DECL(int) IEMR3Term(PVM pVM)
992{
993 NOREF(pVM);
994#ifdef IEM_WITH_TLB_TRACE
995 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
996 {
997 PVMCPU const pVCpu = pVM->apCpusR3[idCpu];
998 RTMemPageFree(pVCpu->iem.s.paTlbTraceEntries,
999 RT_BIT_Z(pVCpu->iem.s.cTlbTraceEntriesShift) * sizeof(*pVCpu->iem.s.paTlbTraceEntries));
1000 }
1001#endif
1002 return VINF_SUCCESS;
1003}
1004
1005
1006VMMR3DECL(void) IEMR3Relocate(PVM pVM)
1007{
1008 RT_NOREF(pVM);
1009}
1010
1011
1012/**
1013 * Gets the name of a generic IEM exit code.
1014 *
1015 * @returns Pointer to read only string if @a uExit is known, otherwise NULL.
1016 * @param uExit The IEM exit to name.
1017 */
1018VMMR3DECL(const char *) IEMR3GetExitName(uint32_t uExit)
1019{
1020 static const char * const s_apszNames[] =
1021 {
1022 /* external interrupts */
1023 "ExtInt 00h", "ExtInt 01h", "ExtInt 02h", "ExtInt 03h", "ExtInt 04h", "ExtInt 05h", "ExtInt 06h", "ExtInt 07h",
1024 "ExtInt 08h", "ExtInt 09h", "ExtInt 0ah", "ExtInt 0bh", "ExtInt 0ch", "ExtInt 0dh", "ExtInt 0eh", "ExtInt 0fh",
1025 "ExtInt 10h", "ExtInt 11h", "ExtInt 12h", "ExtInt 13h", "ExtInt 14h", "ExtInt 15h", "ExtInt 16h", "ExtInt 17h",
1026 "ExtInt 18h", "ExtInt 19h", "ExtInt 1ah", "ExtInt 1bh", "ExtInt 1ch", "ExtInt 1dh", "ExtInt 1eh", "ExtInt 1fh",
1027 "ExtInt 20h", "ExtInt 21h", "ExtInt 22h", "ExtInt 23h", "ExtInt 24h", "ExtInt 25h", "ExtInt 26h", "ExtInt 27h",
1028 "ExtInt 28h", "ExtInt 29h", "ExtInt 2ah", "ExtInt 2bh", "ExtInt 2ch", "ExtInt 2dh", "ExtInt 2eh", "ExtInt 2fh",
1029 "ExtInt 30h", "ExtInt 31h", "ExtInt 32h", "ExtInt 33h", "ExtInt 34h", "ExtInt 35h", "ExtInt 36h", "ExtInt 37h",
1030 "ExtInt 38h", "ExtInt 39h", "ExtInt 3ah", "ExtInt 3bh", "ExtInt 3ch", "ExtInt 3dh", "ExtInt 3eh", "ExtInt 3fh",
1031 "ExtInt 40h", "ExtInt 41h", "ExtInt 42h", "ExtInt 43h", "ExtInt 44h", "ExtInt 45h", "ExtInt 46h", "ExtInt 47h",
1032 "ExtInt 48h", "ExtInt 49h", "ExtInt 4ah", "ExtInt 4bh", "ExtInt 4ch", "ExtInt 4dh", "ExtInt 4eh", "ExtInt 4fh",
1033 "ExtInt 50h", "ExtInt 51h", "ExtInt 52h", "ExtInt 53h", "ExtInt 54h", "ExtInt 55h", "ExtInt 56h", "ExtInt 57h",
1034 "ExtInt 58h", "ExtInt 59h", "ExtInt 5ah", "ExtInt 5bh", "ExtInt 5ch", "ExtInt 5dh", "ExtInt 5eh", "ExtInt 5fh",
1035 "ExtInt 60h", "ExtInt 61h", "ExtInt 62h", "ExtInt 63h", "ExtInt 64h", "ExtInt 65h", "ExtInt 66h", "ExtInt 67h",
1036 "ExtInt 68h", "ExtInt 69h", "ExtInt 6ah", "ExtInt 6bh", "ExtInt 6ch", "ExtInt 6dh", "ExtInt 6eh", "ExtInt 6fh",
1037 "ExtInt 70h", "ExtInt 71h", "ExtInt 72h", "ExtInt 73h", "ExtInt 74h", "ExtInt 75h", "ExtInt 76h", "ExtInt 77h",
1038 "ExtInt 78h", "ExtInt 79h", "ExtInt 7ah", "ExtInt 7bh", "ExtInt 7ch", "ExtInt 7dh", "ExtInt 7eh", "ExtInt 7fh",
1039 "ExtInt 80h", "ExtInt 81h", "ExtInt 82h", "ExtInt 83h", "ExtInt 84h", "ExtInt 85h", "ExtInt 86h", "ExtInt 87h",
1040 "ExtInt 88h", "ExtInt 89h", "ExtInt 8ah", "ExtInt 8bh", "ExtInt 8ch", "ExtInt 8dh", "ExtInt 8eh", "ExtInt 8fh",
1041 "ExtInt 90h", "ExtInt 91h", "ExtInt 92h", "ExtInt 93h", "ExtInt 94h", "ExtInt 95h", "ExtInt 96h", "ExtInt 97h",
1042 "ExtInt 98h", "ExtInt 99h", "ExtInt 9ah", "ExtInt 9bh", "ExtInt 9ch", "ExtInt 9dh", "ExtInt 9eh", "ExtInt 9fh",
1043 "ExtInt a0h", "ExtInt a1h", "ExtInt a2h", "ExtInt a3h", "ExtInt a4h", "ExtInt a5h", "ExtInt a6h", "ExtInt a7h",
1044 "ExtInt a8h", "ExtInt a9h", "ExtInt aah", "ExtInt abh", "ExtInt ach", "ExtInt adh", "ExtInt aeh", "ExtInt afh",
1045 "ExtInt b0h", "ExtInt b1h", "ExtInt b2h", "ExtInt b3h", "ExtInt b4h", "ExtInt b5h", "ExtInt b6h", "ExtInt b7h",
1046 "ExtInt b8h", "ExtInt b9h", "ExtInt bah", "ExtInt bbh", "ExtInt bch", "ExtInt bdh", "ExtInt beh", "ExtInt bfh",
1047 "ExtInt c0h", "ExtInt c1h", "ExtInt c2h", "ExtInt c3h", "ExtInt c4h", "ExtInt c5h", "ExtInt c6h", "ExtInt c7h",
1048 "ExtInt c8h", "ExtInt c9h", "ExtInt cah", "ExtInt cbh", "ExtInt cch", "ExtInt cdh", "ExtInt ceh", "ExtInt cfh",
1049 "ExtInt d0h", "ExtInt d1h", "ExtInt d2h", "ExtInt d3h", "ExtInt d4h", "ExtInt d5h", "ExtInt d6h", "ExtInt d7h",
1050 "ExtInt d8h", "ExtInt d9h", "ExtInt dah", "ExtInt dbh", "ExtInt dch", "ExtInt ddh", "ExtInt deh", "ExtInt dfh",
1051 "ExtInt e0h", "ExtInt e1h", "ExtInt e2h", "ExtInt e3h", "ExtInt e4h", "ExtInt e5h", "ExtInt e6h", "ExtInt e7h",
1052 "ExtInt e8h", "ExtInt e9h", "ExtInt eah", "ExtInt ebh", "ExtInt ech", "ExtInt edh", "ExtInt eeh", "ExtInt efh",
1053 "ExtInt f0h", "ExtInt f1h", "ExtInt f2h", "ExtInt f3h", "ExtInt f4h", "ExtInt f5h", "ExtInt f6h", "ExtInt f7h",
1054 "ExtInt f8h", "ExtInt f9h", "ExtInt fah", "ExtInt fbh", "ExtInt fch", "ExtInt fdh", "ExtInt feh", "ExtInt ffh",
1055 /* software interrups */
1056 "SoftInt 00h", "SoftInt 01h", "SoftInt 02h", "SoftInt 03h", "SoftInt 04h", "SoftInt 05h", "SoftInt 06h", "SoftInt 07h",
1057 "SoftInt 08h", "SoftInt 09h", "SoftInt 0ah", "SoftInt 0bh", "SoftInt 0ch", "SoftInt 0dh", "SoftInt 0eh", "SoftInt 0fh",
1058 "SoftInt 10h", "SoftInt 11h", "SoftInt 12h", "SoftInt 13h", "SoftInt 14h", "SoftInt 15h", "SoftInt 16h", "SoftInt 17h",
1059 "SoftInt 18h", "SoftInt 19h", "SoftInt 1ah", "SoftInt 1bh", "SoftInt 1ch", "SoftInt 1dh", "SoftInt 1eh", "SoftInt 1fh",
1060 "SoftInt 20h", "SoftInt 21h", "SoftInt 22h", "SoftInt 23h", "SoftInt 24h", "SoftInt 25h", "SoftInt 26h", "SoftInt 27h",
1061 "SoftInt 28h", "SoftInt 29h", "SoftInt 2ah", "SoftInt 2bh", "SoftInt 2ch", "SoftInt 2dh", "SoftInt 2eh", "SoftInt 2fh",
1062 "SoftInt 30h", "SoftInt 31h", "SoftInt 32h", "SoftInt 33h", "SoftInt 34h", "SoftInt 35h", "SoftInt 36h", "SoftInt 37h",
1063 "SoftInt 38h", "SoftInt 39h", "SoftInt 3ah", "SoftInt 3bh", "SoftInt 3ch", "SoftInt 3dh", "SoftInt 3eh", "SoftInt 3fh",
1064 "SoftInt 40h", "SoftInt 41h", "SoftInt 42h", "SoftInt 43h", "SoftInt 44h", "SoftInt 45h", "SoftInt 46h", "SoftInt 47h",
1065 "SoftInt 48h", "SoftInt 49h", "SoftInt 4ah", "SoftInt 4bh", "SoftInt 4ch", "SoftInt 4dh", "SoftInt 4eh", "SoftInt 4fh",
1066 "SoftInt 50h", "SoftInt 51h", "SoftInt 52h", "SoftInt 53h", "SoftInt 54h", "SoftInt 55h", "SoftInt 56h", "SoftInt 57h",
1067 "SoftInt 58h", "SoftInt 59h", "SoftInt 5ah", "SoftInt 5bh", "SoftInt 5ch", "SoftInt 5dh", "SoftInt 5eh", "SoftInt 5fh",
1068 "SoftInt 60h", "SoftInt 61h", "SoftInt 62h", "SoftInt 63h", "SoftInt 64h", "SoftInt 65h", "SoftInt 66h", "SoftInt 67h",
1069 "SoftInt 68h", "SoftInt 69h", "SoftInt 6ah", "SoftInt 6bh", "SoftInt 6ch", "SoftInt 6dh", "SoftInt 6eh", "SoftInt 6fh",
1070 "SoftInt 70h", "SoftInt 71h", "SoftInt 72h", "SoftInt 73h", "SoftInt 74h", "SoftInt 75h", "SoftInt 76h", "SoftInt 77h",
1071 "SoftInt 78h", "SoftInt 79h", "SoftInt 7ah", "SoftInt 7bh", "SoftInt 7ch", "SoftInt 7dh", "SoftInt 7eh", "SoftInt 7fh",
1072 "SoftInt 80h", "SoftInt 81h", "SoftInt 82h", "SoftInt 83h", "SoftInt 84h", "SoftInt 85h", "SoftInt 86h", "SoftInt 87h",
1073 "SoftInt 88h", "SoftInt 89h", "SoftInt 8ah", "SoftInt 8bh", "SoftInt 8ch", "SoftInt 8dh", "SoftInt 8eh", "SoftInt 8fh",
1074 "SoftInt 90h", "SoftInt 91h", "SoftInt 92h", "SoftInt 93h", "SoftInt 94h", "SoftInt 95h", "SoftInt 96h", "SoftInt 97h",
1075 "SoftInt 98h", "SoftInt 99h", "SoftInt 9ah", "SoftInt 9bh", "SoftInt 9ch", "SoftInt 9dh", "SoftInt 9eh", "SoftInt 9fh",
1076 "SoftInt a0h", "SoftInt a1h", "SoftInt a2h", "SoftInt a3h", "SoftInt a4h", "SoftInt a5h", "SoftInt a6h", "SoftInt a7h",
1077 "SoftInt a8h", "SoftInt a9h", "SoftInt aah", "SoftInt abh", "SoftInt ach", "SoftInt adh", "SoftInt aeh", "SoftInt afh",
1078 "SoftInt b0h", "SoftInt b1h", "SoftInt b2h", "SoftInt b3h", "SoftInt b4h", "SoftInt b5h", "SoftInt b6h", "SoftInt b7h",
1079 "SoftInt b8h", "SoftInt b9h", "SoftInt bah", "SoftInt bbh", "SoftInt bch", "SoftInt bdh", "SoftInt beh", "SoftInt bfh",
1080 "SoftInt c0h", "SoftInt c1h", "SoftInt c2h", "SoftInt c3h", "SoftInt c4h", "SoftInt c5h", "SoftInt c6h", "SoftInt c7h",
1081 "SoftInt c8h", "SoftInt c9h", "SoftInt cah", "SoftInt cbh", "SoftInt cch", "SoftInt cdh", "SoftInt ceh", "SoftInt cfh",
1082 "SoftInt d0h", "SoftInt d1h", "SoftInt d2h", "SoftInt d3h", "SoftInt d4h", "SoftInt d5h", "SoftInt d6h", "SoftInt d7h",
1083 "SoftInt d8h", "SoftInt d9h", "SoftInt dah", "SoftInt dbh", "SoftInt dch", "SoftInt ddh", "SoftInt deh", "SoftInt dfh",
1084 "SoftInt e0h", "SoftInt e1h", "SoftInt e2h", "SoftInt e3h", "SoftInt e4h", "SoftInt e5h", "SoftInt e6h", "SoftInt e7h",
1085 "SoftInt e8h", "SoftInt e9h", "SoftInt eah", "SoftInt ebh", "SoftInt ech", "SoftInt edh", "SoftInt eeh", "SoftInt efh",
1086 "SoftInt f0h", "SoftInt f1h", "SoftInt f2h", "SoftInt f3h", "SoftInt f4h", "SoftInt f5h", "SoftInt f6h", "SoftInt f7h",
1087 "SoftInt f8h", "SoftInt f9h", "SoftInt fah", "SoftInt fbh", "SoftInt fch", "SoftInt fdh", "SoftInt feh", "SoftInt ffh",
1088 };
1089 if (uExit < RT_ELEMENTS(s_apszNames))
1090 return s_apszNames[uExit];
1091 return NULL;
1092}
1093
1094
1095/** Worker for iemR3InfoTlbPrintSlots and iemR3InfoTlbPrintAddress. */
1096static void iemR3InfoTlbPrintHeader(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb, bool *pfHeader)
1097{
1098 if (*pfHeader)
1099 return;
1100 pHlp->pfnPrintf(pHlp, "%cTLB for CPU %u:\n", &pVCpu->iem.s.CodeTlb == pTlb ? 'I' : 'D', pVCpu->idCpu);
1101 *pfHeader = true;
1102}
1103
1104
1105#define IEMR3INFOTLB_F_ONLY_VALID RT_BIT_32(0)
1106#define IEMR3INFOTLB_F_CHECK RT_BIT_32(1)
1107
1108/** Worker for iemR3InfoTlbPrintSlots and iemR3InfoTlbPrintAddress. */
1109static void iemR3InfoTlbPrintSlot(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb, IEMTLBENTRY const *pTlbe,
1110 uint32_t uSlot, uint32_t fFlags)
1111{
1112#ifndef VBOX_VMM_TARGET_ARMV8
1113 uint64_t const uTlbRevision = !(uSlot & 1) ? pTlb->uTlbRevision : pTlb->uTlbRevisionGlobal;
1114#else
1115 uint64_t const uTlbRevision = pTlb->uTlbRevision;
1116#endif
1117 if ((fFlags & IEMR3INFOTLB_F_ONLY_VALID) && (pTlbe->uTag & IEMTLB_REVISION_MASK) != uTlbRevision)
1118 return;
1119
1120 /* The address needs to be sign extended, thus the shifting fun here.*/
1121 RTGCPTR const GCPtr = (RTGCINTPTR)((pTlbe->uTag & ~IEMTLB_REVISION_MASK) << (64 - IEMTLB_TAG_ADDR_WIDTH))
1122 >> (64 - IEMTLB_TAG_ADDR_WIDTH - GUEST_PAGE_SHIFT);
1123 const char *pszValid = "";
1124#ifndef VBOX_VMM_TARGET_ARMV8
1125 char szTmp[128];
1126 if (fFlags & IEMR3INFOTLB_F_CHECK)
1127 {
1128 uint32_t const fInvSlotG = (uint32_t)!(uSlot & 1) << X86_PTE_BIT_G;
1129 PGMPTWALKFAST WalkFast;
1130 int rc = PGMGstQueryPageFast(pVCpu, GCPtr, 0 /*fFlags - don't check or modify anything */, &WalkFast);
1131 pszValid = szTmp;
1132 if (RT_FAILURE(rc))
1133 switch (rc)
1134 {
1135 case VERR_PAGE_TABLE_NOT_PRESENT:
1136 switch ((WalkFast.fFailed & PGM_WALKFAIL_LEVEL_MASK) >> PGM_WALKFAIL_LEVEL_SHIFT)
1137 {
1138 case 1: pszValid = " stale(page-not-present)"; break;
1139 case 2: pszValid = " stale(pd-entry-not-present)"; break;
1140 case 3: pszValid = " stale(pdptr-entry-not-present)"; break;
1141 case 4: pszValid = " stale(pml4-entry-not-present)"; break;
1142 case 5: pszValid = " stale(pml5-entry-not-present)"; break;
1143 default: pszValid = " stale(VERR_PAGE_TABLE_NOT_PRESENT)"; break;
1144 }
1145 break;
1146 default: RTStrPrintf(szTmp, sizeof(szTmp), " stale(rc=%d)", rc); break;
1147 }
1148 else if (WalkFast.GCPhys != pTlbe->GCPhys)
1149 RTStrPrintf(szTmp, sizeof(szTmp), " stale(GCPhys=%RGp)", WalkFast.GCPhys);
1150 else if ( (~WalkFast.fEffective & (X86_PTE_RW | X86_PTE_US | X86_PTE_G | X86_PTE_A | X86_PTE_D))
1151 == ( (pTlbe->fFlagsAndPhysRev & ( IEMTLBE_F_PT_NO_WRITE | IEMTLBE_F_PT_NO_USER
1152 | IEMTLBE_F_PT_NO_DIRTY | IEMTLBE_F_PT_NO_ACCESSED))
1153 | fInvSlotG ) )
1154 pszValid = " still-valid";
1155 else if ( (~WalkFast.fEffective & (X86_PTE_RW | X86_PTE_US | X86_PTE_G))
1156 == ((pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_WRITE | IEMTLBE_F_PT_NO_USER)) | fInvSlotG) )
1157 switch ( (~WalkFast.fEffective & (X86_PTE_A | X86_PTE_D))
1158 ^ (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_DIRTY | IEMTLBE_F_PT_NO_ACCESSED)) )
1159 {
1160 case X86_PTE_A:
1161 pszValid = WalkFast.fEffective & X86_PTE_A ? " still-valid(accessed-now)" : " still-valid(accessed-no-more)";
1162 break;
1163 case X86_PTE_D:
1164 pszValid = WalkFast.fEffective & X86_PTE_D ? " still-valid(dirty-now)" : " still-valid(dirty-no-more)";
1165 break;
1166 case X86_PTE_D | X86_PTE_A:
1167 RTStrPrintf(szTmp, sizeof(szTmp), " still-valid(%s%s)",
1168 (~WalkFast.fEffective & X86_PTE_D) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_DIRTY) ? ""
1169 : WalkFast.fEffective & X86_PTE_D ? "dirty-now" : "dirty-no-more",
1170 (~WalkFast.fEffective & X86_PTE_A) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED) ? ""
1171 : WalkFast.fEffective & X86_PTE_A ? " accessed-now" : " accessed-no-more");
1172 break;
1173 default: AssertFailed(); break;
1174 }
1175 else
1176 RTStrPrintf(szTmp, sizeof(szTmp), " stale(%s%s%s%s%s)",
1177 (~WalkFast.fEffective & X86_PTE_RW) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE) ? ""
1178 : WalkFast.fEffective & X86_PTE_RW ? "writeable-now" : "writable-no-more",
1179 (~WalkFast.fEffective & X86_PTE_US) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) ? ""
1180 : WalkFast.fEffective & X86_PTE_US ? " user-now" : " user-no-more",
1181 (~WalkFast.fEffective & X86_PTE_G) == fInvSlotG ? ""
1182 : WalkFast.fEffective & X86_PTE_G ? " global-now" : " global-no-more",
1183 (~WalkFast.fEffective & X86_PTE_D) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_DIRTY) ? ""
1184 : WalkFast.fEffective & X86_PTE_D ? " dirty-now" : " dirty-no-more",
1185 (~WalkFast.fEffective & X86_PTE_A) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED) ? ""
1186 : WalkFast.fEffective & X86_PTE_A ? " accessed-now" : " accessed-no-more");
1187 }
1188#else
1189 RT_NOREF(pVCpu);
1190#endif
1191
1192 pHlp->pfnPrintf(pHlp, IEMTLB_SLOT_FMT ": %s %#018RX64 -> %RGp / %p / %#05x %s%s%s%s%s%s%s/%s%s%s%s/%s %s%s\n",
1193 uSlot,
1194 (pTlbe->uTag & IEMTLB_REVISION_MASK) == uTlbRevision ? "valid "
1195 : (pTlbe->uTag & IEMTLB_REVISION_MASK) == 0 ? "empty "
1196 : "expired",
1197 GCPtr, /* -> */
1198 pTlbe->GCPhys, /* / */ pTlbe->pbMappingR3,
1199 /* / */
1200 (uint32_t)(pTlbe->fFlagsAndPhysRev & ~IEMTLBE_F_PHYS_REV),
1201 /* */
1202 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE ? "R-" : "RW",
1203 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC ? "-" : "X",
1204 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED ? "-" : "A",
1205 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_DIRTY ? "-" : "D",
1206 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER ? "U" : "S",
1207 !(uSlot & 1) ? "-" : "G",
1208 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE ? "4K" : "2M",
1209 /* / */
1210 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_WRITE ? "-" : "w",
1211 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_READ ? "-" : "r",
1212 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_UNASSIGNED ? "u" : "-",
1213 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_CODE_PAGE ? "c" : "-",
1214 /* / */
1215 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_NO_MAPPINGR3 ? "N" : "M",
1216 (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pTlb->uTlbPhysRev ? "phys-valid"
1217 : (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == 0 ? "phys-empty" : "phys-expired",
1218 pszValid);
1219}
1220
1221
1222/** Displays one or more TLB slots. */
1223static void iemR3InfoTlbPrintSlots(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb,
1224 uint32_t uSlot, uint32_t cSlots, uint32_t fFlags, bool *pfHeader)
1225{
1226 if (uSlot < RT_ELEMENTS(pTlb->aEntries))
1227 {
1228 if (cSlots > RT_ELEMENTS(pTlb->aEntries))
1229 {
1230 pHlp->pfnPrintf(pHlp, "error: Too many slots given: %u, adjusting it down to the max (%u)\n",
1231 cSlots, RT_ELEMENTS(pTlb->aEntries));
1232 cSlots = RT_ELEMENTS(pTlb->aEntries);
1233 }
1234
1235 iemR3InfoTlbPrintHeader(pVCpu, pHlp, pTlb, pfHeader);
1236 while (cSlots-- > 0)
1237 {
1238 IEMTLBENTRY const Tlbe = pTlb->aEntries[uSlot];
1239 iemR3InfoTlbPrintSlot(pVCpu, pHlp, pTlb, &Tlbe, uSlot, fFlags);
1240 uSlot = (uSlot + 1) % RT_ELEMENTS(pTlb->aEntries);
1241 }
1242 }
1243 else
1244 pHlp->pfnPrintf(pHlp, "error: TLB slot is out of range: %u (%#x), max %u (%#x)\n",
1245 uSlot, uSlot, RT_ELEMENTS(pTlb->aEntries) - 1, RT_ELEMENTS(pTlb->aEntries) - 1);
1246}
1247
1248
1249/** Displays the TLB slot for the given address. */
1250static void iemR3InfoTlbPrintAddress(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb,
1251 uint64_t uAddress, uint32_t fFlags, bool *pfHeader)
1252{
1253 iemR3InfoTlbPrintHeader(pVCpu, pHlp, pTlb, pfHeader);
1254
1255 uint64_t const uTag = (uAddress << 16) >> (X86_PAGE_SHIFT + 16);
1256 uint32_t const uSlot = (uint8_t)uTag;
1257 IEMTLBENTRY const Tlbe = pTlb->aEntries[uSlot];
1258 pHlp->pfnPrintf(pHlp, "Address %#RX64 -> slot %#x - %s\n", uAddress, uSlot,
1259 Tlbe.uTag == (uTag | pTlb->uTlbRevision) ? "match"
1260 : (Tlbe.uTag & ~IEMTLB_REVISION_MASK) == uTag ? "expired" : "mismatch");
1261 iemR3InfoTlbPrintSlot(pVCpu, pHlp, pTlb, &Tlbe, uSlot, fFlags);
1262}
1263
1264
1265/** Common worker for iemR3InfoDTlb and iemR3InfoITlb. */
1266static void iemR3InfoTlbCommon(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs, bool fITlb)
1267{
1268 /*
1269 * This is entirely argument driven.
1270 */
1271 static RTGETOPTDEF const s_aOptions[] =
1272 {
1273 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
1274 { "--vcpu", 'c', RTGETOPT_REQ_UINT32 },
1275 { "--check", 'C', RTGETOPT_REQ_NOTHING },
1276 { "all", 'A', RTGETOPT_REQ_NOTHING },
1277 { "--all", 'A', RTGETOPT_REQ_NOTHING },
1278 { "--address", 'a', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1279 { "--range", 'r', RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_HEX },
1280 { "--slot", 's', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX },
1281 { "--only-valid", 'v', RTGETOPT_REQ_NOTHING },
1282 };
1283
1284 RTGETOPTSTATE State;
1285 int rc = RTGetOptInit(&State, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /*iFirst*/, 0 /*fFlags*/);
1286 AssertRCReturnVoid(rc);
1287
1288 uint32_t cActionArgs = 0;
1289 bool fNeedHeader = true;
1290 bool fAddressMode = true;
1291 uint32_t fFlags = 0;
1292 PVMCPU const pVCpuCall = VMMGetCpu(pVM);
1293 PVMCPU pVCpu = pVCpuCall;
1294 if (!pVCpu)
1295 pVCpu = VMMGetCpuById(pVM, 0);
1296
1297 RTGETOPTUNION ValueUnion;
1298 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
1299 {
1300 switch (rc)
1301 {
1302 case 'c':
1303 if (ValueUnion.u32 >= pVM->cCpus)
1304 pHlp->pfnPrintf(pHlp, "error: Invalid CPU ID: %u\n", ValueUnion.u32);
1305 else if (!pVCpu || pVCpu->idCpu != ValueUnion.u32)
1306 {
1307 pVCpu = VMMGetCpuById(pVM, ValueUnion.u32);
1308 fNeedHeader = true;
1309 if (!pVCpuCall || pVCpuCall->idCpu != ValueUnion.u32)
1310 {
1311 pHlp->pfnPrintf(pHlp, "info: Can't check guest PTs when switching to a different VCpu! Targetting %u, on %u.\n",
1312 ValueUnion.u32, pVCpuCall->idCpu);
1313 fFlags &= ~IEMR3INFOTLB_F_CHECK;
1314 }
1315 }
1316 break;
1317
1318 case 'C':
1319 if (!pVCpuCall)
1320 pHlp->pfnPrintf(pHlp, "error: Can't check guest PT when not running on an EMT!\n");
1321 else if (pVCpu != pVCpuCall)
1322 pHlp->pfnPrintf(pHlp, "error: Can't check guest PTs when on a different EMT! Targetting %u, on %u.\n",
1323 pVCpu->idCpu, pVCpuCall->idCpu);
1324 else
1325 fFlags |= IEMR3INFOTLB_F_CHECK;
1326 break;
1327
1328 case 'a':
1329 iemR3InfoTlbPrintAddress(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1330 ValueUnion.u64, fFlags, &fNeedHeader);
1331 fAddressMode = true;
1332 cActionArgs++;
1333 break;
1334
1335 case 'A':
1336 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1337 0, RT_ELEMENTS(pVCpu->iem.s.CodeTlb.aEntries), fFlags, &fNeedHeader);
1338 cActionArgs++;
1339 break;
1340
1341 case 'r':
1342 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1343 ValueUnion.PairU32.uFirst, ValueUnion.PairU32.uSecond, fFlags, &fNeedHeader);
1344 fAddressMode = false;
1345 cActionArgs++;
1346 break;
1347
1348 case 's':
1349 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1350 ValueUnion.u32, 1, fFlags, &fNeedHeader);
1351 fAddressMode = false;
1352 cActionArgs++;
1353 break;
1354
1355 case 'v':
1356 fFlags |= IEMR3INFOTLB_F_ONLY_VALID;
1357 break;
1358
1359 case VINF_GETOPT_NOT_OPTION:
1360 if (fAddressMode)
1361 {
1362 uint64_t uAddr;
1363 rc = RTStrToUInt64Full(ValueUnion.psz, 16, &uAddr);
1364 if (RT_SUCCESS(rc) && rc != VWRN_NUMBER_TOO_BIG)
1365 iemR3InfoTlbPrintAddress(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1366 uAddr, fFlags, &fNeedHeader);
1367 else
1368 pHlp->pfnPrintf(pHlp, "error: Invalid or malformed guest address '%s': %Rrc\n", ValueUnion.psz, rc);
1369 }
1370 else
1371 {
1372 uint32_t uSlot;
1373 rc = RTStrToUInt32Full(ValueUnion.psz, 16, &uSlot);
1374 if (RT_SUCCESS(rc) && rc != VWRN_NUMBER_TOO_BIG)
1375 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1376 uSlot, 1, fFlags, &fNeedHeader);
1377 else
1378 pHlp->pfnPrintf(pHlp, "error: Invalid or malformed TLB slot number '%s': %Rrc\n", ValueUnion.psz, rc);
1379 }
1380 cActionArgs++;
1381 break;
1382
1383 case 'h':
1384 pHlp->pfnPrintf(pHlp,
1385 "Usage: info %ctlb [options]\n"
1386 "\n"
1387 "Options:\n"
1388 " -c<n>, --cpu=<n>, --vcpu=<n>\n"
1389 " Selects the CPU which TLBs we're looking at. Default: Caller / 0\n"
1390 " -C,--check\n"
1391 " Check valid entries against guest PTs.\n"
1392 " -A, --all, all\n"
1393 " Display all the TLB entries (default if no other args).\n"
1394 " -a<virt>, --address=<virt>\n"
1395 " Shows the TLB entry for the specified guest virtual address.\n"
1396 " -r<slot:count>, --range=<slot:count>\n"
1397 " Shows the TLB entries for the specified slot range.\n"
1398 " -s<slot>,--slot=<slot>\n"
1399 " Shows the given TLB slot.\n"
1400 " -v,--only-valid\n"
1401 " Only show valid TLB entries (TAG, not phys)\n"
1402 "\n"
1403 "Non-options are interpreted according to the last -a, -r or -s option,\n"
1404 "defaulting to addresses if not preceeded by any of those options.\n"
1405 , fITlb ? 'i' : 'd');
1406 return;
1407
1408 default:
1409 pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
1410 return;
1411 }
1412 }
1413
1414 /*
1415 * If no action taken, we display all (-A) by default.
1416 */
1417 if (!cActionArgs)
1418 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1419 0, RT_ELEMENTS(pVCpu->iem.s.CodeTlb.aEntries), fFlags, &fNeedHeader);
1420}
1421
1422
1423/**
1424 * @callback_method_impl{FNDBGFINFOARGVINT, itlb}
1425 */
1426static DECLCALLBACK(void) iemR3InfoITlb(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
1427{
1428 return iemR3InfoTlbCommon(pVM, pHlp, cArgs, papszArgs, true /*fITlb*/);
1429}
1430
1431
1432/**
1433 * @callback_method_impl{FNDBGFINFOARGVINT, dtlb}
1434 */
1435static DECLCALLBACK(void) iemR3InfoDTlb(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
1436{
1437 return iemR3InfoTlbCommon(pVM, pHlp, cArgs, papszArgs, false /*fITlb*/);
1438}
1439
1440
1441#ifdef IEM_WITH_TLB_TRACE
1442/**
1443 * @callback_method_impl{FNDBGFINFOARGVINT, tlbtrace}
1444 */
1445static DECLCALLBACK(void) iemR3InfoTlbTrace(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
1446{
1447 /*
1448 * Parse arguments.
1449 */
1450 static RTGETOPTDEF const s_aOptions[] =
1451 {
1452 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
1453 { "--vcpu", 'c', RTGETOPT_REQ_UINT32 },
1454 { "--last", 'l', RTGETOPT_REQ_UINT32 },
1455 { "--limit", 'l', RTGETOPT_REQ_UINT32 },
1456 { "--stop-at-global-flush", 'g', RTGETOPT_REQ_NOTHING },
1457 };
1458
1459 RTGETOPTSTATE State;
1460 int rc = RTGetOptInit(&State, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /*iFirst*/, 0 /*fFlags*/);
1461 AssertRCReturnVoid(rc);
1462
1463 uint32_t cLimit = UINT32_MAX;
1464 bool fStopAtGlobalFlush = false;
1465 PVMCPU const pVCpuCall = VMMGetCpu(pVM);
1466 PVMCPU pVCpu = pVCpuCall;
1467 if (!pVCpu)
1468 pVCpu = VMMGetCpuById(pVM, 0);
1469
1470 RTGETOPTUNION ValueUnion;
1471 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
1472 {
1473 switch (rc)
1474 {
1475 case 'c':
1476 if (ValueUnion.u32 >= pVM->cCpus)
1477 pHlp->pfnPrintf(pHlp, "error: Invalid CPU ID: %u\n", ValueUnion.u32);
1478 else if (!pVCpu || pVCpu->idCpu != ValueUnion.u32)
1479 pVCpu = VMMGetCpuById(pVM, ValueUnion.u32);
1480 break;
1481
1482 case 'l':
1483 cLimit = ValueUnion.u32;
1484 break;
1485
1486 case 'g':
1487 fStopAtGlobalFlush = true;
1488 break;
1489
1490 case 'h':
1491 pHlp->pfnPrintf(pHlp,
1492 "Usage: info tlbtrace [options]\n"
1493 "\n"
1494 "Options:\n"
1495 " -c<n>, --cpu=<n>, --vcpu=<n>\n"
1496 " Selects the CPU which TLB trace we're looking at. Default: Caller / 0\n"
1497 " -l<n>, --last=<n>\n"
1498 " Limit display to the last N entries. Default: all\n"
1499 " -g,--stop-at-global-flush\n"
1500 " Stop after the first global flush entry.\n"
1501 );
1502 return;
1503
1504 default:
1505 pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
1506 return;
1507 }
1508 }
1509
1510 /*
1511 * Get the details.
1512 */
1513 AssertReturnVoid(pVCpu);
1514 Assert(pVCpu->iem.s.cTlbTraceEntriesShift <= 28);
1515 uint32_t idx = pVCpu->iem.s.idxTlbTraceEntry;
1516 uint32_t const cShift = RT_MIN(pVCpu->iem.s.cTlbTraceEntriesShift, 28);
1517 uint32_t const fMask = RT_BIT_32(cShift) - 1;
1518 uint32_t cLeft = RT_MIN(RT_MIN(idx, RT_BIT_32(cShift)), cLimit);
1519 PCIEMTLBTRACEENTRY paEntries = pVCpu->iem.s.paTlbTraceEntries;
1520 if (cLeft && paEntries)
1521 {
1522 /*
1523 * Display the entries.
1524 */
1525 pHlp->pfnPrintf(pHlp, "TLB Trace for CPU %u:\n", pVCpu->idCpu);
1526 while (cLeft-- > 0)
1527 {
1528 PCIEMTLBTRACEENTRY const pCur = &paEntries[--idx & fMask];
1529 switch (pCur->enmType)
1530 {
1531 case kIemTlbTraceType_InvlPg:
1532 pHlp->pfnPrintf(pHlp, "%u: %016RX64 invlpg %RGv slot=" IEMTLB_SLOT_FMT "\n",
1533 idx, pCur->rip, pCur->u64Param, (uint32_t)IEMTLB_ADDR_TO_EVEN_INDEX(pCur->u64Param));
1534 break;
1535 case kIemTlbTraceType_Flush:
1536 pHlp->pfnPrintf(pHlp, "%u: %016RX64 flush %s rev=%#RX64\n", idx, pCur->rip,
1537 pCur->bParam ? "data" : "code", pCur->u64Param);
1538 break;
1539 case kIemTlbTraceType_FlushGlobal:
1540 pHlp->pfnPrintf(pHlp, "%u: %016RX64 flush %s rev=%#RX64 grev=%#RX64\n", idx, pCur->rip,
1541 pCur->bParam ? "data" : "code", pCur->u64Param, pCur->u64Param2);
1542 if (fStopAtGlobalFlush)
1543 return;
1544 break;
1545 case kIemTlbTraceType_Load:
1546 pHlp->pfnPrintf(pHlp, "%u: %016RX64 load %s %RGv slot=" IEMTLB_SLOT_FMT "\n",
1547 idx, pCur->rip, pCur->bParam ? "data" : "code",
1548 pCur->u64Param, (uint32_t)IEMTLB_ADDR_TO_EVEN_INDEX(pCur->u64Param));
1549 break;
1550 case kIemTlbTraceType_LoadGlobal:
1551 pHlp->pfnPrintf(pHlp, "%u: %016RX64 load %s %RGv slot=" IEMTLB_SLOT_FMT " (global)\n",
1552 idx, pCur->rip, pCur->bParam ? "data" : "code",
1553 pCur->u64Param, (uint32_t)IEMTLB_ADDR_TO_EVEN_INDEX(pCur->u64Param));
1554 break;
1555 case kIemTlbTraceType_Load_Cr0:
1556 pHlp->pfnPrintf(pHlp, "%u: %016RX64 load cr0 %08RX64 (was %08RX64)\n",
1557 idx, pCur->rip, pCur->u64Param, pCur->u64Param2);
1558 break;
1559 case kIemTlbTraceType_Load_Cr3:
1560 pHlp->pfnPrintf(pHlp, "%u: %016RX64 load cr3 %016RX64 (was %016RX64)\n",
1561 idx, pCur->rip, pCur->u64Param, pCur->u64Param2);
1562 break;
1563 case kIemTlbTraceType_Load_Cr4:
1564 pHlp->pfnPrintf(pHlp, "%u: %016RX64 load cr4 %08RX64 (was %08RX64)\n",
1565 idx, pCur->rip, pCur->u64Param, pCur->u64Param2);
1566 break;
1567 case kIemTlbTraceType_Load_Efer:
1568 pHlp->pfnPrintf(pHlp, "%u: %016RX64 load efer %016RX64 (was %016RX64)\n",
1569 idx, pCur->rip, pCur->u64Param, pCur->u64Param2);
1570 break;
1571 case kIemTlbTraceType_Invalid:
1572 pHlp->pfnPrintf(pHlp, "%u: Invalid!\n");
1573 break;
1574 }
1575 }
1576 }
1577 else
1578 pHlp->pfnPrintf(pHlp, "No trace entries to display\n");
1579}
1580#endif /* IEM_WITH_TLB_TRACE */
1581
1582#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
1583/**
1584 * @callback_method_impl{FNDBGFINFOARGVINT, tb}
1585 */
1586static DECLCALLBACK(void) iemR3InfoTb(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
1587{
1588 /*
1589 * Parse arguments.
1590 */
1591 static RTGETOPTDEF const s_aOptions[] =
1592 {
1593 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
1594 { "--vcpu", 'c', RTGETOPT_REQ_UINT32 },
1595 { "--addr", 'a', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1596 { "--address", 'a', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1597 { "--phys", 'p', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1598 { "--physical", 'p', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1599 { "--phys-addr", 'p', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1600 { "--phys-address", 'p', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1601 { "--physical-address", 'p', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1602 { "--flags", 'f', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX },
1603 };
1604
1605 RTGETOPTSTATE State;
1606 int rc = RTGetOptInit(&State, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /*iFirst*/, 0 /*fFlags*/);
1607 AssertRCReturnVoid(rc);
1608
1609 PVMCPU const pVCpuThis = VMMGetCpu(pVM);
1610 PVMCPU pVCpu = pVCpuThis ? pVCpuThis : VMMGetCpuById(pVM, 0);
1611 RTGCPHYS GCPhysPc = NIL_RTGCPHYS;
1612 RTGCPHYS GCVirt = NIL_RTGCPTR;
1613 uint32_t fFlags = UINT32_MAX;
1614
1615 RTGETOPTUNION ValueUnion;
1616 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
1617 {
1618 switch (rc)
1619 {
1620 case 'c':
1621 if (ValueUnion.u32 >= pVM->cCpus)
1622 pHlp->pfnPrintf(pHlp, "error: Invalid CPU ID: %u\n", ValueUnion.u32);
1623 else if (!pVCpu || pVCpu->idCpu != ValueUnion.u32)
1624 pVCpu = VMMGetCpuById(pVM, ValueUnion.u32);
1625 break;
1626
1627 case 'a':
1628 GCVirt = ValueUnion.u64;
1629 GCPhysPc = NIL_RTGCPHYS;
1630 break;
1631
1632 case 'p':
1633 GCVirt = NIL_RTGCPHYS;
1634 GCPhysPc = ValueUnion.u64;
1635 break;
1636
1637 case 'f':
1638 fFlags = ValueUnion.u32;
1639 break;
1640
1641 case 'h':
1642 pHlp->pfnPrintf(pHlp,
1643 "Usage: info tb [options]\n"
1644 "\n"
1645 "Options:\n"
1646 " -c<n>, --cpu=<n>, --vcpu=<n>\n"
1647 " Selects the CPU which TBs we're looking at. Default: Caller / 0\n"
1648 " -a<virt>, --address=<virt>\n"
1649 " Shows the TB for the specified guest virtual address.\n"
1650 " -p<phys>, --phys=<phys>, --phys-addr=<phys>\n"
1651 " Shows the TB for the specified guest physical address.\n"
1652 " -f<flags>,--flags=<flags>\n"
1653 " The TB flags value (hex) to use when looking up the TB.\n"
1654 "\n"
1655 "The default is to use CS:RIP and derive flags from the CPU mode.\n");
1656 return;
1657
1658 default:
1659 pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
1660 return;
1661 }
1662 }
1663
1664 /* Currently, only do work on the same EMT. */
1665 if (pVCpu != pVCpuThis)
1666 {
1667 pHlp->pfnPrintf(pHlp, "TODO: Cross EMT calling not supported yet: targeting %u, caller on %d\n",
1668 pVCpu->idCpu, pVCpuThis ? (int)pVCpuThis->idCpu : -1);
1669 return;
1670 }
1671
1672 /*
1673 * Defaults.
1674 */
1675 if (GCPhysPc == NIL_RTGCPHYS)
1676 {
1677 if (GCVirt == NIL_RTGCPTR)
1678 GCVirt = CPUMGetGuestFlatPC(pVCpu);
1679 rc = PGMPhysGCPtr2GCPhys(pVCpu, GCVirt, &GCPhysPc);
1680 if (RT_FAILURE(rc))
1681 {
1682 pHlp->pfnPrintf(pHlp, "Failed to convert %%%RGv to an guest physical address: %Rrc\n", GCVirt, rc);
1683 return;
1684 }
1685 }
1686 if (fFlags == UINT32_MAX)
1687 {
1688 /* Note! This is duplicating code in IEMAllThrdRecompiler. */
1689 fFlags = iemCalcExecFlags(pVCpu);
1690 if (pVM->cCpus == 1)
1691 fFlags |= IEM_F_X86_DISREGARD_LOCK;
1692 if (CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx))
1693 fFlags |= IEMTB_F_INHIBIT_SHADOW;
1694 if (CPUMAreInterruptsInhibitedByNmiEx(&pVCpu->cpum.GstCtx))
1695 fFlags |= IEMTB_F_INHIBIT_NMI;
1696 if ((IEM_F_MODE_CPUMODE_MASK & fFlags) != IEMMODE_64BIT)
1697 {
1698 int64_t const offFromLim = (int64_t)pVCpu->cpum.GstCtx.cs.u32Limit - (int64_t)pVCpu->cpum.GstCtx.eip;
1699 if (offFromLim < X86_PAGE_SIZE + 16 - (int32_t)(pVCpu->cpum.GstCtx.cs.u64Base & GUEST_PAGE_OFFSET_MASK))
1700 fFlags |= IEMTB_F_CS_LIM_CHECKS;
1701 }
1702 }
1703
1704 /*
1705 * Do the lookup...
1706 *
1707 * Note! This is also duplicating code in IEMAllThrdRecompiler. We don't
1708 * have much choice since we don't want to increase use counters and
1709 * trigger native recompilation.
1710 */
1711 fFlags &= IEMTB_F_KEY_MASK;
1712 IEMTBCACHE const * const pTbCache = pVCpu->iem.s.pTbCacheR3;
1713 uint32_t const idxHash = IEMTBCACHE_HASH(pTbCache, fFlags, GCPhysPc);
1714 PCIEMTB pTb = IEMTBCACHE_PTR_GET_TB(pTbCache->apHash[idxHash]);
1715 while (pTb)
1716 {
1717 if (pTb->GCPhysPc == GCPhysPc)
1718 {
1719 if ((pTb->fFlags & IEMTB_F_KEY_MASK) == fFlags)
1720 {
1721 /// @todo if (pTb->x86.fAttr == (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u)
1722 break;
1723 }
1724 }
1725 pTb = pTb->pNext;
1726 }
1727 if (!pTb)
1728 pHlp->pfnPrintf(pHlp, "PC=%RGp fFlags=%#x - no TB found on #%u\n", GCPhysPc, fFlags, pVCpu->idCpu);
1729 else
1730 {
1731 /*
1732 * Disassemble according to type.
1733 */
1734 switch (pTb->fFlags & IEMTB_F_TYPE_MASK)
1735 {
1736# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
1737 case IEMTB_F_TYPE_NATIVE:
1738 pHlp->pfnPrintf(pHlp, "PC=%RGp fFlags=%#x on #%u: %p - native\n", GCPhysPc, fFlags, pVCpu->idCpu, pTb);
1739 iemNativeDisassembleTb(pVCpu, pTb, pHlp);
1740 break;
1741# endif
1742
1743 case IEMTB_F_TYPE_THREADED:
1744 pHlp->pfnPrintf(pHlp, "PC=%RGp fFlags=%#x on #%u: %p - threaded\n", GCPhysPc, fFlags, pVCpu->idCpu, pTb);
1745 iemThreadedDisassembleTb(pTb, pHlp);
1746 break;
1747
1748 default:
1749 pHlp->pfnPrintf(pHlp, "PC=%RGp fFlags=%#x on #%u: %p - ??? %#x\n",
1750 GCPhysPc, fFlags, pVCpu->idCpu, pTb, pTb->fFlags);
1751 break;
1752 }
1753 }
1754}
1755#endif /* VBOX_WITH_IEM_RECOMPILER && !VBOX_VMM_TARGET_ARMV8 */
1756
1757
1758#ifdef VBOX_WITH_DEBUGGER
1759
1760/** @callback_method_impl{FNDBGCCMD,
1761 * Implements the '.alliem' command. }
1762 */
1763static DECLCALLBACK(int) iemR3DbgFlushTlbs(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1764{
1765 VMCPUID idCpu = DBGCCmdHlpGetCurrentCpu(pCmdHlp);
1766 PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, idCpu);
1767 if (pVCpu)
1768 {
1769 VMR3ReqPriorityCallVoidWaitU(pUVM, idCpu, (PFNRT)IEMTlbInvalidateAllGlobal, 1, pVCpu);
1770 return VINF_SUCCESS;
1771 }
1772 RT_NOREF(paArgs, cArgs);
1773 return DBGCCmdHlpFail(pCmdHlp, pCmd, "failed to get the PVMCPU for the current CPU");
1774}
1775
1776
1777/**
1778 * Called by IEMR3Init to register debugger commands.
1779 */
1780static void iemR3RegisterDebuggerCommands(void)
1781{
1782 /*
1783 * Register debugger commands.
1784 */
1785 static DBGCCMD const s_aCmds[] =
1786 {
1787 {
1788 /* .pszCmd = */ "iemflushtlb",
1789 /* .cArgsMin = */ 0,
1790 /* .cArgsMax = */ 0,
1791 /* .paArgDescs = */ NULL,
1792 /* .cArgDescs = */ 0,
1793 /* .fFlags = */ 0,
1794 /* .pfnHandler = */ iemR3DbgFlushTlbs,
1795 /* .pszSyntax = */ "",
1796 /* .pszDescription = */ "Flushed the code and data TLBs"
1797 },
1798 };
1799
1800 int rc = DBGCRegisterCommands(&s_aCmds[0], RT_ELEMENTS(s_aCmds));
1801 AssertLogRelRC(rc);
1802}
1803
1804#endif /* VBOX_WITH_DEBUGGER */
1805
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette