VirtualBox

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

Last change on this file since 106171 was 106101, checked in by vboxsync, 4 months ago

VMM/IEM: More native eflag stats. Added IEMNATIVE_WITH_EFLAGS_POSTPONING config option (no code). bugref:10720

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 145.9 KB
Line 
1/* $Id: IEMR3.cpp 106101 2024-09-19 21:16:19Z vboxsync $ */
2/** @file
3 * IEM - Interpreted Execution Manager.
4 */
5
6/*
7 * Copyright (C) 2011-2024 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#include <VBox/vmm/ssm.h>
39#if defined(VBOX_VMM_TARGET_ARMV8)
40# include "IEMInternal-armv8.h"
41#else
42# include "IEMInternal.h"
43#endif
44#include <VBox/vmm/vm.h>
45#include <VBox/vmm/vmapi.h>
46#include <VBox/err.h>
47#ifdef VBOX_WITH_DEBUGGER
48# include <VBox/dbg.h>
49#endif
50
51#include <iprt/assert.h>
52#include <iprt/getopt.h>
53#ifdef IEM_WITH_TLB_TRACE
54# include <iprt/mem.h>
55#endif
56#include <iprt/string.h>
57
58#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
59# include "IEMN8veRecompiler.h"
60# include "IEMThreadedFunctions.h"
61# include "IEMInline.h"
62#endif
63
64
65/*********************************************************************************************************************************
66* Internal Functions *
67*********************************************************************************************************************************/
68static FNDBGFINFOARGVINT iemR3InfoITlb;
69static FNDBGFINFOARGVINT iemR3InfoDTlb;
70#ifdef IEM_WITH_TLB_TRACE
71static FNDBGFINFOARGVINT iemR3InfoTlbTrace;
72#endif
73#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
74static FNDBGFINFOARGVINT iemR3InfoTb;
75static FNDBGFINFOARGVINT iemR3InfoTbTop;
76#endif
77#ifdef VBOX_WITH_DEBUGGER
78static void iemR3RegisterDebuggerCommands(void);
79#endif
80
81
82#if !defined(VBOX_VMM_TARGET_ARMV8)
83static const char *iemGetTargetCpuName(uint32_t enmTargetCpu)
84{
85 switch (enmTargetCpu)
86 {
87#define CASE_RET_STR(enmValue) case enmValue: return #enmValue + (sizeof("IEMTARGETCPU_") - 1)
88 CASE_RET_STR(IEMTARGETCPU_8086);
89 CASE_RET_STR(IEMTARGETCPU_V20);
90 CASE_RET_STR(IEMTARGETCPU_186);
91 CASE_RET_STR(IEMTARGETCPU_286);
92 CASE_RET_STR(IEMTARGETCPU_386);
93 CASE_RET_STR(IEMTARGETCPU_486);
94 CASE_RET_STR(IEMTARGETCPU_PENTIUM);
95 CASE_RET_STR(IEMTARGETCPU_PPRO);
96 CASE_RET_STR(IEMTARGETCPU_CURRENT);
97#undef CASE_RET_STR
98 default: return "Unknown";
99 }
100}
101#endif
102
103
104/**
105 * Initializes the interpreted execution manager.
106 *
107 * This must be called after CPUM as we're quering information from CPUM about
108 * the guest and host CPUs.
109 *
110 * @returns VBox status code.
111 * @param pVM The cross context VM structure.
112 */
113VMMR3DECL(int) IEMR3Init(PVM pVM)
114{
115 /*
116 * Read configuration.
117 */
118#if (!defined(VBOX_VMM_TARGET_ARMV8) && !defined(VBOX_WITHOUT_CPUID_HOST_CALL)) || defined(VBOX_WITH_IEM_RECOMPILER)
119 PCFGMNODE const pIem = CFGMR3GetChild(CFGMR3GetRoot(pVM), "IEM");
120 int rc;
121#endif
122
123#if !defined(VBOX_VMM_TARGET_ARMV8) && !defined(VBOX_WITHOUT_CPUID_HOST_CALL)
124 /** @cfgm{/IEM/CpuIdHostCall, boolean, false}
125 * Controls whether the custom VBox specific CPUID host call interface is
126 * enabled or not. */
127# ifdef DEBUG_bird
128 rc = CFGMR3QueryBoolDef(pIem, "CpuIdHostCall", &pVM->iem.s.fCpuIdHostCall, true);
129# else
130 rc = CFGMR3QueryBoolDef(pIem, "CpuIdHostCall", &pVM->iem.s.fCpuIdHostCall, false);
131# endif
132 AssertLogRelRCReturn(rc, rc);
133#endif
134
135#ifdef VBOX_WITH_IEM_RECOMPILER
136 /** @cfgm{/IEM/MaxTbCount, uint32_t, 524288}
137 * Max number of TBs per EMT. */
138 uint32_t cMaxTbs = 0;
139 rc = CFGMR3QueryU32Def(pIem, "MaxTbCount", &cMaxTbs, _512K);
140 AssertLogRelRCReturn(rc, rc);
141 if (cMaxTbs < _16K || cMaxTbs > _8M)
142 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
143 "MaxTbCount value %u (%#x) is out of range (min %u, max %u)", cMaxTbs, cMaxTbs, _16K, _8M);
144
145 /** @cfgm{/IEM/InitialTbCount, uint32_t, 32678}
146 * Initial (minimum) number of TBs per EMT in ring-3. */
147 uint32_t cInitialTbs = 0;
148 rc = CFGMR3QueryU32Def(pIem, "InitialTbCount", &cInitialTbs, RT_MIN(cMaxTbs, _32K));
149 AssertLogRelRCReturn(rc, rc);
150 if (cInitialTbs < _16K || cInitialTbs > _8M)
151 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
152 "InitialTbCount value %u (%#x) is out of range (min %u, max %u)", cInitialTbs, cInitialTbs, _16K, _8M);
153
154 /* Check that the two values makes sense together. Expect user/api to do
155 the right thing or get lost. */
156 if (cInitialTbs > cMaxTbs)
157 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
158 "InitialTbCount value %u (%#x) is higher than the MaxTbCount value %u (%#x)",
159 cInitialTbs, cInitialTbs, cMaxTbs, cMaxTbs);
160
161 /** @cfgm{/IEM/MaxExecMem, uint64_t, 512 MiB}
162 * Max executable memory for recompiled code per EMT. */
163 uint64_t cbMaxExec = 0;
164 rc = CFGMR3QueryU64Def(pIem, "MaxExecMem", &cbMaxExec, _512M);
165 AssertLogRelRCReturn(rc, rc);
166 if (cbMaxExec < _1M || cbMaxExec > 16*_1G64)
167 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
168 "MaxExecMem value %'RU64 (%#RX64) is out of range (min %'RU64, max %'RU64)",
169 cbMaxExec, cbMaxExec, (uint64_t)_1M, 16*_1G64);
170
171 /** @cfgm{/IEM/ExecChunkSize, uint32_t, 0 (auto)}
172 * The executable memory allocator chunk size. */
173 uint32_t cbChunkExec = 0;
174 rc = CFGMR3QueryU32Def(pIem, "ExecChunkSize", &cbChunkExec, 0);
175 AssertLogRelRCReturn(rc, rc);
176 if (cbChunkExec != 0 && cbChunkExec != UINT32_MAX && (cbChunkExec < _1M || cbChunkExec > _256M))
177 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
178 "ExecChunkSize value %'RU32 (%#RX32) is out of range (min %'RU32, max %'RU32)",
179 cbChunkExec, cbChunkExec, _1M, _256M);
180
181 /** @cfgm{/IEM/InitialExecMemSize, uint64_t, 1}
182 * The initial executable memory allocator size (per EMT). The value is
183 * rounded up to the nearest chunk size, so 1 byte means one chunk. */
184 uint64_t cbInitialExec = 0;
185 rc = CFGMR3QueryU64Def(pIem, "InitialExecMemSize", &cbInitialExec, 0);
186 AssertLogRelRCReturn(rc, rc);
187 if (cbInitialExec > cbMaxExec)
188 return VMSetError(pVM, VERR_OUT_OF_RANGE, RT_SRC_POS,
189 "InitialExecMemSize value %'RU64 (%#RX64) is out of range (max %'RU64)",
190 cbInitialExec, cbInitialExec, cbMaxExec);
191
192 /** @cfgm{/IEM/NativeRecompileAtUsedCount, uint32_t, 16}
193 * The translation block use count value to do native recompilation at.
194 * Set to zero to disable native recompilation. */
195 uint32_t uTbNativeRecompileAtUsedCount = 16;
196 rc = CFGMR3QueryU32Def(pIem, "NativeRecompileAtUsedCount", &uTbNativeRecompileAtUsedCount, 16);
197 AssertLogRelRCReturn(rc, rc);
198
199#endif /* VBOX_WITH_IEM_RECOMPILER*/
200
201 /*
202 * Initialize per-CPU data and register statistics.
203 */
204#if 1
205 uint64_t const uInitialTlbRevision = UINT64_C(0) - (IEMTLB_REVISION_INCR * 200U);
206 uint64_t const uInitialTlbPhysRev = UINT64_C(0) - (IEMTLB_PHYS_REV_INCR * 100U);
207#else
208 uint64_t const uInitialTlbRevision = UINT64_C(0) + (IEMTLB_REVISION_INCR * 4U);
209 uint64_t const uInitialTlbPhysRev = UINT64_C(0) + (IEMTLB_PHYS_REV_INCR * 4U);
210#endif
211
212 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
213 {
214 PVMCPU const pVCpu = pVM->apCpusR3[idCpu];
215 AssertCompile(sizeof(pVCpu->iem.s) <= sizeof(pVCpu->iem.padding)); /* (tstVMStruct can't do it's job w/o instruction stats) */
216
217 pVCpu->iem.s.CodeTlb.uTlbRevision = pVCpu->iem.s.DataTlb.uTlbRevision = uInitialTlbRevision;
218#ifndef VBOX_VMM_TARGET_ARMV8
219 pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal = pVCpu->iem.s.DataTlb.uTlbRevisionGlobal = uInitialTlbRevision;
220#endif
221 pVCpu->iem.s.CodeTlb.uTlbPhysRev = pVCpu->iem.s.DataTlb.uTlbPhysRev = uInitialTlbPhysRev;
222#ifndef VBOX_VMM_TARGET_ARMV8
223 pVCpu->iem.s.CodeTlb.NonGlobalLargePageRange.uFirstTag = UINT64_MAX;
224 pVCpu->iem.s.CodeTlb.GlobalLargePageRange.uFirstTag = UINT64_MAX;
225 pVCpu->iem.s.DataTlb.NonGlobalLargePageRange.uFirstTag = UINT64_MAX;
226 pVCpu->iem.s.DataTlb.GlobalLargePageRange.uFirstTag = UINT64_MAX;
227#endif
228
229#ifndef VBOX_VMM_TARGET_ARMV8
230 pVCpu->iem.s.cTbsTillNextTimerPoll = 128;
231 pVCpu->iem.s.cTbsTillNextTimerPollPrev = 128;
232#endif
233
234 /*
235 * Host and guest CPU information.
236 */
237 if (idCpu == 0)
238 {
239 pVCpu->iem.s.enmCpuVendor = CPUMGetGuestCpuVendor(pVM);
240 pVCpu->iem.s.enmHostCpuVendor = CPUMGetHostCpuVendor(pVM);
241#if !defined(VBOX_VMM_TARGET_ARMV8)
242 pVCpu->iem.s.aidxTargetCpuEflFlavour[0] = pVCpu->iem.s.enmCpuVendor == CPUMCPUVENDOR_INTEL
243 || pVCpu->iem.s.enmCpuVendor == CPUMCPUVENDOR_VIA /*??*/
244 ? IEMTARGETCPU_EFL_BEHAVIOR_INTEL : IEMTARGETCPU_EFL_BEHAVIOR_AMD;
245# if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
246 if (pVCpu->iem.s.enmCpuVendor == pVCpu->iem.s.enmHostCpuVendor)
247 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = IEMTARGETCPU_EFL_BEHAVIOR_NATIVE;
248 else
249# endif
250 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = pVCpu->iem.s.aidxTargetCpuEflFlavour[0];
251#else
252 pVCpu->iem.s.aidxTargetCpuEflFlavour[0] = IEMTARGETCPU_EFL_BEHAVIOR_NATIVE;
253 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = pVCpu->iem.s.aidxTargetCpuEflFlavour[0];
254#endif
255
256#if !defined(VBOX_VMM_TARGET_ARMV8) && (IEM_CFG_TARGET_CPU == IEMTARGETCPU_DYNAMIC)
257 switch (pVM->cpum.ro.GuestFeatures.enmMicroarch)
258 {
259 case kCpumMicroarch_Intel_8086: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_8086; break;
260 case kCpumMicroarch_Intel_80186: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_186; break;
261 case kCpumMicroarch_Intel_80286: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_286; break;
262 case kCpumMicroarch_Intel_80386: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_386; break;
263 case kCpumMicroarch_Intel_80486: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_486; break;
264 case kCpumMicroarch_Intel_P5: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_PENTIUM; break;
265 case kCpumMicroarch_Intel_P6: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_PPRO; break;
266 case kCpumMicroarch_NEC_V20: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_V20; break;
267 case kCpumMicroarch_NEC_V30: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_V20; break;
268 default: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_CURRENT; break;
269 }
270 LogRel(("IEM: TargetCpu=%s, Microarch=%s aidxTargetCpuEflFlavour={%d,%d}\n",
271 iemGetTargetCpuName(pVCpu->iem.s.uTargetCpu), CPUMMicroarchName(pVM->cpum.ro.GuestFeatures.enmMicroarch),
272 pVCpu->iem.s.aidxTargetCpuEflFlavour[0], pVCpu->iem.s.aidxTargetCpuEflFlavour[1]));
273#else
274 LogRel(("IEM: Microarch=%s aidxTargetCpuEflFlavour={%d,%d}\n",
275 CPUMMicroarchName(pVM->cpum.ro.GuestFeatures.enmMicroarch),
276 pVCpu->iem.s.aidxTargetCpuEflFlavour[0], pVCpu->iem.s.aidxTargetCpuEflFlavour[1]));
277#endif
278 }
279 else
280 {
281 pVCpu->iem.s.enmCpuVendor = pVM->apCpusR3[0]->iem.s.enmCpuVendor;
282 pVCpu->iem.s.enmHostCpuVendor = pVM->apCpusR3[0]->iem.s.enmHostCpuVendor;
283 pVCpu->iem.s.aidxTargetCpuEflFlavour[0] = pVM->apCpusR3[0]->iem.s.aidxTargetCpuEflFlavour[0];
284 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = pVM->apCpusR3[0]->iem.s.aidxTargetCpuEflFlavour[1];
285#if IEM_CFG_TARGET_CPU == IEMTARGETCPU_DYNAMIC
286 pVCpu->iem.s.uTargetCpu = pVM->apCpusR3[0]->iem.s.uTargetCpu;
287#endif
288 }
289
290 /*
291 * Mark all buffers free.
292 */
293 uint32_t iMemMap = RT_ELEMENTS(pVCpu->iem.s.aMemMappings);
294 while (iMemMap-- > 0)
295 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
296
297#ifdef VBOX_WITH_IEM_RECOMPILER
298 /*
299 * Recompiler state and configuration distribution.
300 */
301 pVCpu->iem.s.uRegFpCtrl = IEMNATIVE_SIMD_FP_CTRL_REG_NOT_MODIFIED;
302 pVCpu->iem.s.uTbNativeRecompileAtUsedCount = uTbNativeRecompileAtUsedCount;
303#endif
304
305#ifdef IEM_WITH_TLB_TRACE
306 /*
307 * Allocate trace buffer.
308 */
309 pVCpu->iem.s.idxTlbTraceEntry = 0;
310 pVCpu->iem.s.cTlbTraceEntriesShift = 16;
311 pVCpu->iem.s.paTlbTraceEntries = (PIEMTLBTRACEENTRY)RTMemPageAlloc( RT_BIT_Z(pVCpu->iem.s.cTlbTraceEntriesShift)
312 * sizeof(*pVCpu->iem.s.paTlbTraceEntries));
313 AssertLogRelReturn(pVCpu->iem.s.paTlbTraceEntries, VERR_NO_PAGE_MEMORY);
314#endif
315 }
316
317
318#ifdef VBOX_WITH_IEM_RECOMPILER
319 /*
320 * Initialize the TB allocator and cache (/ hash table).
321 *
322 * This is done by each EMT to try get more optimal thread/numa locality of
323 * the allocations.
324 */
325 rc = VMR3ReqCallWait(pVM, VMCPUID_ALL, (PFNRT)iemTbInit, 6,
326 pVM, cInitialTbs, cMaxTbs, cbInitialExec, cbMaxExec, cbChunkExec);
327 AssertLogRelRCReturn(rc, rc);
328#endif
329
330 /*
331 * Register statistics.
332 */
333 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
334 {
335#if !defined(VBOX_VMM_TARGET_ARMV8) && defined(VBOX_WITH_NESTED_HWVIRT_VMX) /* quick fix for stupid structure duplication non-sense */
336 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
337 char szPat[128];
338 RT_NOREF_PV(szPat); /* lazy bird */
339 char szVal[128];
340 RT_NOREF_PV(szVal); /* lazy bird */
341
342 STAMR3RegisterF(pVM, &pVCpu->iem.s.cInstructions, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
343 "Instructions interpreted", "/IEM/CPU%u/cInstructions", idCpu);
344 STAMR3RegisterF(pVM, &pVCpu->iem.s.cLongJumps, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
345 "Number of longjmp calls", "/IEM/CPU%u/cLongJumps", idCpu);
346 STAMR3RegisterF(pVM, &pVCpu->iem.s.cPotentialExits, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
347 "Potential exits", "/IEM/CPU%u/cPotentialExits", idCpu);
348 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetAspectNotImplemented, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
349 "VERR_IEM_ASPECT_NOT_IMPLEMENTED", "/IEM/CPU%u/cRetAspectNotImplemented", idCpu);
350 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetInstrNotImplemented, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
351 "VERR_IEM_INSTR_NOT_IMPLEMENTED", "/IEM/CPU%u/cRetInstrNotImplemented", idCpu);
352 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetInfStatuses, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
353 "Informational statuses returned", "/IEM/CPU%u/cRetInfStatuses", idCpu);
354 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetErrStatuses, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
355 "Error statuses returned", "/IEM/CPU%u/cRetErrStatuses", idCpu);
356 STAMR3RegisterF(pVM, &pVCpu->iem.s.cbWritten, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
357 "Approx bytes written", "/IEM/CPU%u/cbWritten", idCpu);
358 STAMR3RegisterF(pVM, &pVCpu->iem.s.cPendingCommit, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
359 "Times RC/R0 had to postpone instruction committing to ring-3", "/IEM/CPU%u/cPendingCommit", idCpu);
360 STAMR3RegisterF(pVM, &pVCpu->iem.s.cMisalignedAtomics, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
361 "Number of misaligned (for the host) atomic instructions", "/IEM/CPU%u/cMisalignedAtomics", idCpu);
362
363 /* Code TLB: */
364 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.uTlbRevision, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
365 "Code TLB non-global revision", "/IEM/CPU%u/Tlb/Code/RevisionNonGlobal", idCpu);
366 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.uTlbRevisionGlobal, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
367 "Code TLB global revision", "/IEM/CPU%u/Tlb/Code/RevisionGlobal", idCpu);
368 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlsFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
369 "Code TLB non-global flushes", "/IEM/CPU%u/Tlb/Code/RevisionNonGlobalFlushes", idCpu);
370 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlsGlobalFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
371 "Code TLB global flushes", "/IEM/CPU%u/Tlb/Code/RevisionGlobalFlushes", idCpu);
372 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbRevisionRollovers, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
373 "Code TLB revision rollovers", "/IEM/CPU%u/Tlb/Code/RevisionRollovers", idCpu);
374
375 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.CodeTlb.uTlbPhysRev, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
376 "Code TLB physical revision", "/IEM/CPU%u/Tlb/Code/PhysicalRevision", idCpu);
377 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbPhysRevFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
378 "Code TLB revision flushes", "/IEM/CPU%u/Tlb/Code/PhysicalRevisionFlushes", idCpu);
379 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbPhysRevRollovers, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
380 "Code TLB revision rollovers", "/IEM/CPU%u/Tlb/Code/PhysicalRevisionRollovers", idCpu);
381
382 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbGlobalLargePageCurLoads, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
383 "Code TLB global large page loads since flush", "/IEM/CPU%u/Tlb/Code/LargePageGlobalCurLoads", idCpu);
384 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.GlobalLargePageRange.uFirstTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
385 "Code TLB global large page range: lowest tag", "/IEM/CPU%u/Tlb/Code/LargePageGlobalFirstTag", idCpu);
386 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.GlobalLargePageRange.uLastTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
387 "Code TLB global large page range: last tag", "/IEM/CPU%u/Tlb/Code/LargePageGlobalLastTag", idCpu);
388
389 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNonGlobalLargePageCurLoads, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
390 "Code TLB non-global large page loads since flush", "/IEM/CPU%u/Tlb/Code/LargePageNonGlobalCurLoads", idCpu);
391 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.NonGlobalLargePageRange.uFirstTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
392 "Code TLB non-global large page range: lowest tag", "/IEM/CPU%u/Tlb/Code/LargePageNonGlobalFirstTag", idCpu);
393 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.NonGlobalLargePageRange.uLastTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
394 "Code TLB non-global large page range: last tag", "/IEM/CPU%u/Tlb/Code/LargePageNonGlobalLastTag", idCpu);
395
396 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbInvlPg, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
397 "Code TLB page invalidation requests", "/IEM/CPU%u/Tlb/Code/InvlPg", idCpu);
398 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbInvlPgLargeGlobal, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
399 "Code TLB page invlpg scanning for global large pages", "/IEM/CPU%u/Tlb/Code/InvlPg/LargeGlobal", idCpu);
400 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbInvlPgLargeNonGlobal, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
401 "Code TLB page invlpg scanning for non-global large pages", "/IEM/CPU%u/Tlb/Code/InvlPg/LargeNonGlobal", idCpu);
402
403 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbCoreMisses, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
404 "Code TLB misses", "/IEM/CPU%u/Tlb/Code/Misses", idCpu);
405 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbCoreGlobalLoads, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
406 "Code TLB global loads", "/IEM/CPU%u/Tlb/Code/Misses/GlobalLoads", idCpu);
407 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbSlowCodeReadPath, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
408 "Code TLB slow read path", "/IEM/CPU%u/Tlb/Code/SlowReads", idCpu);
409# ifdef IEM_WITH_TLB_STATISTICS
410 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbCoreHits, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
411 "Code TLB hits (non-native)", "/IEM/CPU%u/Tlb/Code/Hits/Other", idCpu);
412# if defined(VBOX_WITH_IEM_NATIVE_RECOMPILER)
413 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCodeTlbHitsForNewPage, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
414 "Code TLB native hits on new page", "/IEM/CPU%u/Tlb/Code/Hits/New-Page", idCpu);
415 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCodeTlbHitsForNewPageWithOffset, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
416 "Code TLB native hits on new page /w offset", "/IEM/CPU%u/Tlb/Code/Hits/New-Page-With-Offset", idCpu);
417# endif
418
419 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Code/Hits/*", idCpu);
420 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Code TLB hits",
421 "/IEM/CPU%u/Tlb/Code/Hits", idCpu);
422
423 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/Tlb/Code/Hits|/IEM/CPU%u/Tlb/Code/Misses", idCpu, idCpu);
424 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Code TLB lookups (sum of hits and misses)",
425 "/IEM/CPU%u/Tlb/Code/AllLookups", idCpu);
426
427 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/Tlb/Code/Misses", idCpu);
428 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Code/Hits", idCpu);
429 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PPM, szVal, true, szPat,
430 "Code TLB actual miss rate", "/IEM/CPU%u/Tlb/Code/RateMisses", idCpu);
431
432# if defined(VBOX_WITH_IEM_NATIVE_RECOMPILER)
433 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNativeMissTag, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
434 "Code TLB misses in native code: Tag mismatch [not directly included grand parent sum]",
435 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown/Tag", idCpu);
436 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNativeMissFlagsAndPhysRev, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
437 "Code TLB misses in native code: Flags or physical revision mistmatch [not directly included grand parent sum]",
438 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown/FlagsAndPhysRev", idCpu);
439 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNativeMissAlignment, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
440 "Code TLB misses in native code: Alignment [not directly included grand parent sum]",
441 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown/Alignment", idCpu);
442 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNativeMissCrossPage, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
443 "Code TLB misses in native code: Cross page [not directly included grand parent sum]",
444 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown/CrossPage", idCpu);
445 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbNativeMissNonCanonical, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
446 "Code TLB misses in native code: Non-canonical [not directly included grand parent sum]",
447 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown/NonCanonical", idCpu);
448
449 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCodeTlbMissesNewPage, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
450 "Code TLB native misses on new page",
451 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown2/New-Page", idCpu);
452 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCodeTlbMissesNewPageWithOffset, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
453 "Code TLB native misses on new page w/ offset",
454 "/IEM/CPU%u/Tlb/Code/Misses/NativeBreakdown2/New-Page-With-Offset", idCpu);
455# endif
456# endif /* IEM_WITH_TLB_STATISTICS */
457
458 /* Data TLB organized as best we can... */
459 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.uTlbRevision, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
460 "Data TLB non-global revision", "/IEM/CPU%u/Tlb/Data/RevisionNonGlobal", idCpu);
461 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.uTlbRevisionGlobal, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
462 "Data TLB global revision", "/IEM/CPU%u/Tlb/Data/RevisionGlobal", idCpu);
463 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlsFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
464 "Data TLB non-global flushes", "/IEM/CPU%u/Tlb/Data/RevisionNonGlobalFlushes", idCpu);
465 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlsGlobalFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
466 "Data TLB global flushes", "/IEM/CPU%u/Tlb/Data/RevisionGlobalFlushes", idCpu);
467 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbRevisionRollovers, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
468 "Data TLB revision rollovers", "/IEM/CPU%u/Tlb/Data/RevisionRollovers", idCpu);
469
470 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.DataTlb.uTlbPhysRev, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
471 "Data TLB physical revision", "/IEM/CPU%u/Tlb/Data/PhysicalRevision", idCpu);
472 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbPhysRevFlushes, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
473 "Data TLB revision flushes", "/IEM/CPU%u/Tlb/Data/PhysicalRevisionFlushes", idCpu);
474 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbPhysRevRollovers, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
475 "Data TLB revision rollovers", "/IEM/CPU%u/Tlb/Data/PhysicalRevisionRollovers", idCpu);
476
477 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbGlobalLargePageCurLoads, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
478 "Data TLB global large page loads since flush", "/IEM/CPU%u/Tlb/Data/LargePageGlobalCurLoads", idCpu);
479 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.GlobalLargePageRange.uFirstTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
480 "Data TLB global large page range: lowest tag", "/IEM/CPU%u/Tlb/Data/LargePageGlobalFirstTag", idCpu);
481 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.GlobalLargePageRange.uLastTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
482 "Data TLB global large page range: last tag", "/IEM/CPU%u/Tlb/Data/LargePageGlobalLastTag", idCpu);
483
484 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNonGlobalLargePageCurLoads, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
485 "Data TLB non-global large page loads since flush", "/IEM/CPU%u/Tlb/Data/LargePageNonGlobalCurLoads", idCpu);
486 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.NonGlobalLargePageRange.uFirstTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
487 "Data TLB non-global large page range: lowest tag", "/IEM/CPU%u/Tlb/Data/LargePageNonGlobalFirstTag", idCpu);
488 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.NonGlobalLargePageRange.uLastTag, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
489 "Data TLB non-global large page range: last tag", "/IEM/CPU%u/Tlb/Data/LargePageNonGlobalLastTag", idCpu);
490
491 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbInvlPg, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
492 "Data TLB page invalidation requests", "/IEM/CPU%u/Tlb/Data/InvlPg", idCpu);
493 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbInvlPgLargeGlobal, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
494 "Data TLB page invlpg scanning for global large pages", "/IEM/CPU%u/Tlb/Data/InvlPg/LargeGlobal", idCpu);
495 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbInvlPgLargeNonGlobal, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
496 "Data TLB page invlpg scanning for non-global large pages", "/IEM/CPU%u/Tlb/Data/InvlPg/LargeNonGlobal", idCpu);
497
498 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbCoreMisses, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
499 "Data TLB core misses (iemMemMap, direct iemMemMapJmp (not safe path))",
500 "/IEM/CPU%u/Tlb/Data/Misses/Core", idCpu);
501 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbCoreGlobalLoads, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
502 "Data TLB global loads",
503 "/IEM/CPU%u/Tlb/Data/Misses/Core/GlobalLoads", idCpu);
504 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbSafeReadPath, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
505 "Data TLB safe read path (inline/native misses going to iemMemMapJmp)",
506 "/IEM/CPU%u/Tlb/Data/Misses/Safe/Reads", idCpu);
507 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbSafeWritePath, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
508 "Data TLB safe write path (inline/native misses going to iemMemMapJmp)",
509 "/IEM/CPU%u/Tlb/Data/Misses/Safe/Writes", idCpu);
510 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Data/Misses/*", idCpu);
511 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Data TLB misses",
512 "/IEM/CPU%u/Tlb/Data/Misses", idCpu);
513
514 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Data/Misses/Safe/*", idCpu);
515 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Data TLB actual safe path calls (read + write)",
516 "/IEM/CPU%u/Tlb/Data/Misses/Safe", idCpu);
517 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbSafeHits, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
518 "Data TLB hits in iemMemMapJmp - not part of safe-path total",
519 "/IEM/CPU%u/Tlb/Data/Misses/Safe/SubPartHits", idCpu);
520 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbSafeMisses, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
521 "Data TLB misses in iemMemMapJmp - not part of safe-path total",
522 "/IEM/CPU%u/Tlb/Data/Misses/Safe/SubPartMisses", idCpu);
523 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbSafeGlobalLoads, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
524 "Data TLB global loads",
525 "/IEM/CPU%u/Tlb/Data/Misses/Safe/SubPartMisses/GlobalLoads", idCpu);
526
527# ifdef IEM_WITH_TLB_STATISTICS
528# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
529 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNativeMissTag, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
530 "Data TLB misses in native code: Tag mismatch [not directly included grand parent sum]",
531 "/IEM/CPU%u/Tlb/Data/Misses/NativeBreakdown/Tag", idCpu);
532 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNativeMissFlagsAndPhysRev, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
533 "Data TLB misses in native code: Flags or physical revision mistmatch [not directly included grand parent sum]",
534 "/IEM/CPU%u/Tlb/Data/Misses/NativeBreakdown/FlagsAndPhysRev", idCpu);
535 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNativeMissAlignment, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
536 "Data TLB misses in native code: Alignment [not directly included grand parent sum]",
537 "/IEM/CPU%u/Tlb/Data/Misses/NativeBreakdown/Alignment", idCpu);
538 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNativeMissCrossPage, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
539 "Data TLB misses in native code: Cross page [not directly included grand parent sum]",
540 "/IEM/CPU%u/Tlb/Data/Misses/NativeBreakdown/CrossPage", idCpu);
541 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbNativeMissNonCanonical, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
542 "Data TLB misses in native code: Non-canonical [not directly included grand parent sum]",
543 "/IEM/CPU%u/Tlb/Data/Misses/NativeBreakdown/NonCanonical", idCpu);
544# endif
545# endif
546
547# ifdef IEM_WITH_TLB_STATISTICS
548 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbCoreHits, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
549 "Data TLB core hits (iemMemMap, direct iemMemMapJmp (not safe path))",
550 "/IEM/CPU%u/Tlb/Data/Hits/Core", idCpu);
551 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbInlineCodeHits, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
552 "Data TLB hits in IEMAllMemRWTmplInline.cpp.h",
553 "/IEM/CPU%u/Tlb/Data/Hits/Inline", idCpu);
554# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
555 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeTlbHitsForStack, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
556 "Data TLB native stack access hits",
557 "/IEM/CPU%u/Tlb/Data/Hits/Native/Stack", idCpu);
558 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeTlbHitsForFetch, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
559 "Data TLB native data fetch hits",
560 "/IEM/CPU%u/Tlb/Data/Hits/Native/Fetch", idCpu);
561 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeTlbHitsForStore, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
562 "Data TLB native data store hits",
563 "/IEM/CPU%u/Tlb/Data/Hits/Native/Store", idCpu);
564 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeTlbHitsForMapped, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
565 "Data TLB native mapped data hits",
566 "/IEM/CPU%u/Tlb/Data/Hits/Native/Mapped", idCpu);
567# endif
568 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Data/Hits/*", idCpu);
569 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Data TLB hits",
570 "/IEM/CPU%u/Tlb/Data/Hits", idCpu);
571
572# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
573 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Data/Hits/Native/*", idCpu);
574 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Data TLB hits from native code",
575 "/IEM/CPU%u/Tlb/Data/Hits/Native", idCpu);
576# endif
577
578 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/Tlb/Data/Hits|/IEM/CPU%u/Tlb/Data/Misses", idCpu, idCpu);
579 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Data TLB lookups (sum of hits and misses)",
580 "/IEM/CPU%u/Tlb/Data/AllLookups", idCpu);
581
582 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/Tlb/Data/Misses", idCpu);
583 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/Tlb/Data/Hits", idCpu);
584 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PPM, szVal, true, szPat,
585 "Data TLB actual miss rate", "/IEM/CPU%u/Tlb/Data/RateMisses", idCpu);
586
587# endif /* IEM_WITH_TLB_STATISTICS */
588
589
590#ifdef VBOX_WITH_IEM_RECOMPILER
591 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.cTbExecNative, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
592 "Executed native translation block", "/IEM/CPU%u/re/cTbExecNative", idCpu);
593 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.cTbExecThreaded, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
594 "Executed threaded translation block", "/IEM/CPU%u/re/cTbExecThreaded", idCpu);
595 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbThreadedExecBreaks, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
596 "Times threaded TB execution was interrupted/broken off", "/IEM/CPU%u/re/cTbExecThreadedBreaks", idCpu);
597# ifdef VBOX_WITH_STATISTICS
598 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbThreadedExecBreaksWithLookup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
599 "Times threaded TB execution was interrupted/broken off on a call with lookup entries", "/IEM/CPU%u/re/cTbExecThreadedBreaksWithLookup", idCpu);
600 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbThreadedExecBreaksWithoutLookup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
601 "Times threaded TB execution was interrupted/broken off on a call without lookup entries", "/IEM/CPU%u/re/cTbExecThreadedBreaksWithoutLookup", idCpu);
602# endif
603
604# ifdef VBOX_WITH_STATISTICS
605 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTimerPoll, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
606 "Timer polling profiling", "/IEM/CPU%u/re/TimerPoll", idCpu);
607 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTimerPollRun, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
608 "Timer polling profiling", "/IEM/CPU%u/re/TimerPoll/Running", idCpu);
609 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTimerPollUnchanged, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
610 "Timer polling interval unchanged", "/IEM/CPU%u/re/TimerPoll/Unchanged", idCpu);
611 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTimerPollTiny, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
612 "Timer polling interval tiny", "/IEM/CPU%u/re/TimerPoll/Tiny", idCpu);
613 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTimerPollDefaultCalc, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
614 "Timer polling interval calculated using defaults", "/IEM/CPU%u/re/TimerPoll/DefaultCalc", idCpu);
615 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTimerPollMax, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
616 "Timer polling interval maxed out", "/IEM/CPU%u/re/TimerPoll/Max", idCpu);
617 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTimerPollFactorDivision, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_OCCURENCE,
618 "Timer polling factor", "/IEM/CPU%u/re/TimerPoll/FactorDivision", idCpu);
619 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTimerPollFactorMultiplication, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
620 "Timer polling factor", "/IEM/CPU%u/re/TimerPoll/FactorMultiplication", idCpu);
621# endif
622 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.cTbsTillNextTimerPollPrev, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
623 "Timer polling interval (in TBs)", "/IEM/CPU%u/re/TimerPollInterval", idCpu);
624
625 PIEMTBALLOCATOR const pTbAllocator = pVCpu->iem.s.pTbAllocatorR3;
626 STAMR3RegisterF(pVM, (void *)&pTbAllocator->StatAllocs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS,
627 "Translation block allocations", "/IEM/CPU%u/re/cTbAllocCalls", idCpu);
628 STAMR3RegisterF(pVM, (void *)&pTbAllocator->StatFrees, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS,
629 "Translation block frees", "/IEM/CPU%u/re/cTbFreeCalls", idCpu);
630# ifdef VBOX_WITH_STATISTICS
631 STAMR3RegisterF(pVM, (void *)&pTbAllocator->StatPrune, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
632 "Time spent freeing up TBs when full at alloc", "/IEM/CPU%u/re/TbPruningAlloc", idCpu);
633# endif
634 STAMR3RegisterF(pVM, (void *)&pTbAllocator->StatPruneNative, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
635 "Time spent freeing up native TBs when out of executable memory", "/IEM/CPU%u/re/ExecMem/TbPruningNative", idCpu);
636 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cAllocatedChunks, STAMTYPE_U16, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
637 "Populated TB chunks", "/IEM/CPU%u/re/cTbChunks", idCpu);
638 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cMaxChunks, STAMTYPE_U8, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
639 "Max number of TB chunks", "/IEM/CPU%u/re/cTbChunksMax", idCpu);
640 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cTotalTbs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
641 "Total number of TBs in the allocator", "/IEM/CPU%u/re/cTbTotal", idCpu);
642 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cMaxTbs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
643 "Max total number of TBs allowed", "/IEM/CPU%u/re/cTbTotalMax", idCpu);
644 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cInUseTbs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
645 "Number of currently allocated TBs", "/IEM/CPU%u/re/cTbAllocated", idCpu);
646 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cNativeTbs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
647 "Number of currently allocated native TBs", "/IEM/CPU%u/re/cTbAllocatedNative", idCpu);
648 STAMR3RegisterF(pVM, (void *)&pTbAllocator->cThreadedTbs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
649 "Number of currently allocated threaded TBs", "/IEM/CPU%u/re/cTbAllocatedThreaded", idCpu);
650
651 PIEMTBCACHE const pTbCache = pVCpu->iem.s.pTbCacheR3;
652 STAMR3RegisterF(pVM, (void *)&pTbCache->cHash, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
653 "Translation block lookup table size", "/IEM/CPU%u/re/cTbHashTab", idCpu);
654
655 STAMR3RegisterF(pVM, (void *)&pTbCache->cLookupHits, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
656 "Translation block lookup hits", "/IEM/CPU%u/re/cTbLookupHits", idCpu);
657 STAMR3RegisterF(pVM, (void *)&pTbCache->cLookupHitsViaTbLookupTable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
658 "Translation block lookup hits via TB lookup table associated with the previous TB", "/IEM/CPU%u/re/cTbLookupHitsViaTbLookupTable", idCpu);
659 STAMR3RegisterF(pVM, (void *)&pTbCache->cLookupMisses, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
660 "Translation block lookup misses", "/IEM/CPU%u/re/cTbLookupMisses", idCpu);
661 STAMR3RegisterF(pVM, (void *)&pTbCache->cCollisions, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
662 "Translation block hash table collisions", "/IEM/CPU%u/re/cTbCollisions", idCpu);
663# ifdef VBOX_WITH_STATISTICS
664 STAMR3RegisterF(pVM, (void *)&pTbCache->StatPrune, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
665 "Time spent shortening collision lists", "/IEM/CPU%u/re/TbPruningCollisions", idCpu);
666# endif
667
668 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbThreadedCalls, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS_PER_TB,
669 "Calls per threaded translation block", "/IEM/CPU%u/re/ThrdCallsPerTb", idCpu);
670 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbInstr, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_INSTR_PER_TB,
671 "Instruction per threaded translation block", "/IEM/CPU%u/re/ThrdInstrPerTb", idCpu);
672 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbLookupEntries, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_INSTR_PER_TB,
673 "TB lookup table entries per threaded translation block", "/IEM/CPU%u/re/ThrdLookupEntriesPerTb", idCpu);
674
675 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatCheckIrqBreaks, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
676 "TB breaks by CheckIrq", "/IEM/CPU%u/re/CheckIrqBreaks", idCpu);
677 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatCheckTimersBreaks, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
678 "TB breaks by CheckIrq", "/IEM/CPU%u/re/CheckTimersBreaks", idCpu);
679 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatCheckModeBreaks, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
680 "TB breaks by CheckMode", "/IEM/CPU%u/re/CheckModeBreaks", idCpu);
681 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatCheckBranchMisses, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
682 "Branch target misses", "/IEM/CPU%u/re/CheckTbJmpMisses", idCpu);
683 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatCheckNeedCsLimChecking, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
684 "Needing CS.LIM checking TB after branch or on page crossing", "/IEM/CPU%u/re/CheckTbNeedCsLimChecking", idCpu);
685
686 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbLoopFullTbDetected, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
687 "Detected loop full TB", "/IEM/CPU%u/re/LoopFullTbDetected", idCpu);
688 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbLoopFullTbDetected2, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
689 "Detected loop full TB but looping back to before the first TB instruction",
690 "/IEM/CPU%u/re/LoopFullTbDetected2", idCpu);
691 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbLoopInTbDetected, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
692 "Detected loop within TB", "/IEM/CPU%u/re/LoopInTbDetected", idCpu);
693
694 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeExecMemInstrBufAllocFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
695 "Number of times the exec memory allocator failed to allocate a large enough buffer",
696 "/IEM/CPU%u/re/NativeExecMemInstrBufAllocFailed", idCpu);
697
698 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCallsRecompiled, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS_PER_TB,
699 "Number of threaded calls per TB that have been properly recompiled to native code",
700 "/IEM/CPU%u/re/NativeCallsRecompiledPerTb", idCpu);
701 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeCallsThreaded, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS_PER_TB,
702 "Number of threaded calls per TB that could not be recompiler to native code",
703 "/IEM/CPU%u/re/NativeCallsThreadedPerTb", idCpu);
704 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeFullyRecompiledTbs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
705 "Number of threaded calls that could not be recompiler to native code",
706 "/IEM/CPU%u/re/NativeFullyRecompiledTbs", idCpu);
707
708 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatTbNativeCode, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES_PER_TB,
709 "Size of native code per TB", "/IEM/CPU%u/re/NativeCodeSizePerTb", idCpu);
710 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.StatNativeRecompilation, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
711 "Profiling iemNativeRecompile()", "/IEM/CPU%u/re/NativeRecompilation", idCpu);
712
713# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
714# ifdef VBOX_WITH_STATISTICS
715 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeRegFindFree, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
716 "Number of calls to iemNativeRegAllocFindFree.",
717 "/IEM/CPU%u/re/NativeRegFindFree", idCpu);
718# endif
719 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeRegFindFreeVar, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
720 "Number of times iemNativeRegAllocFindFree needed to free a variable.",
721 "/IEM/CPU%u/re/NativeRegFindFreeVar", idCpu);
722# ifdef VBOX_WITH_STATISTICS
723 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeRegFindFreeNoVar, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
724 "Number of times iemNativeRegAllocFindFree did not needed to free any variables.",
725 "/IEM/CPU%u/re/NativeRegFindFreeNoVar", idCpu);
726 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeRegFindFreeLivenessUnshadowed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
727 "Times liveness info freeed up shadowed guest registers in iemNativeRegAllocFindFree.",
728 "/IEM/CPU%u/re/NativeRegFindFreeLivenessUnshadowed", idCpu);
729 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeRegFindFreeLivenessHelped, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
730 "Times liveness info helped finding the return register in iemNativeRegAllocFindFree.",
731 "/IEM/CPU%u/re/NativeRegFindFreeLivenessHelped", idCpu);
732
733 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflSkippedArithmetic, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
734 "Skipped all status flag updating, arithmetic instructions",
735 "/IEM/CPU%u/re/NativeEFlags/ArithmeticSkipped", idCpu);
736 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflTotalArithmetic, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
737 "Total number of arithmetic intructions with status flag updating",
738 "/IEM/CPU%u/re/NativeEFlags/ArithmeticTotal", idCpu);
739 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeEFlags/ArithmeticTotal", idCpu);
740 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeEFlags/ArithmeticSkipped", idCpu);
741 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
742 "Skipped all status flag updating, arithmetic instructions, percentage",
743 "/IEM/CPU%u/re/NativeEFlags/ArithmeticSkippedPct", idCpu);
744
745 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflSkippedLogical, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
746 "Skipped all status flag updating, logical instructions",
747 "/IEM/CPU%u/re/NativeEFlags/LogicalSkipped", idCpu);
748 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflTotalLogical, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
749 "Total number of logical intructions with status flag updating",
750 "/IEM/CPU%u/re/NativeEFlags/LogicalTotal", idCpu);
751 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeEFlags/LogicalTotal", idCpu);
752 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeEFlags/LogicalSkipped", idCpu);
753 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
754 "Skipped all status flag updating, logical instructions, percentage",
755 "/IEM/CPU%u/re/NativeEFlags/LogicalSkippedPct", idCpu);
756
757 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflSkippedShift, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
758 "Skipped all status flag updating, shift instructions",
759 "/IEM/CPU%u/re/NativeEFlags/ShiftSkipped", idCpu);
760 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEflTotalShift, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
761 "Total number of shift intructions with status flag updating",
762 "/IEM/CPU%u/re/NativeEFlags/ShiftTotal", idCpu);
763 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeEFlags/ShiftTotal", idCpu);
764 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeEFlags/ShiftSkipped", idCpu);
765 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
766 "Skipped all status flag updating, shift instructions, percentage",
767 "/IEM/CPU%u/re/NativeEFlags/ShiftSkippedPct", idCpu);
768
769 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflCfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.CF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/CfSkippable", idCpu);
770 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflPfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.PF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/PfSkippable", idCpu);
771 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflAfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.AF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/AfSkippable", idCpu);
772 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflZfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.ZF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/ZfSkippable", idCpu);
773 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflSfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.SF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/SfSkippable", idCpu);
774 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflOfSkippable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Skippable EFLAGS.OF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/OfSkippable", idCpu);
775
776 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflCfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.CF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/CfRequired", idCpu);
777 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflPfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.PF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/PfRequired", idCpu);
778 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflAfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.AF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/AfRequired", idCpu);
779 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflZfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.ZF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/ZfRequired", idCpu);
780 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflSfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.SF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/SfRequired", idCpu);
781 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflOfRequired, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Required EFLAGS.OF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/OfRequired", idCpu);
782
783# ifdef IEMLIVENESS_EXTENDED_LAYOUT
784 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflCfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.CF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/CfDelayable", idCpu);
785 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflPfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.PF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/PfDelayable", idCpu);
786 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflAfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.AF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/AfDelayable", idCpu);
787 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflZfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.ZF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/ZfDelayable", idCpu);
788 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflSfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.SF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/SfDelayable", idCpu);
789 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeLivenessEflOfDelayable, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Maybe delayable EFLAGS.OF updating", "/IEM/CPU%u/re/NativeLivenessEFlags/OfDelayable", idCpu);
790# endif
791
792 /* Sum up all status bits ('_' is a sorting hack). */
793 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags/?fSkippable*", idCpu);
794 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Total skippable EFLAGS status bit updating",
795 "/IEM/CPU%u/re/NativeLivenessEFlags/totalSkippable", idCpu);
796
797 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags/?fRequired*", idCpu);
798 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Total required STATUS status bit updating",
799 "/IEM/CPU%u/re/NativeLivenessEFlags/totalRequired", idCpu);
800
801# ifdef IEMLIVENESS_EXTENDED_LAYOUT
802 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags/?fDelayable*", idCpu);
803 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Total potentially delayable STATUS status bit updating",
804 "/IEM/CPU%u/re/NativeLivenessEFlags/totalDelayable", idCpu);
805# endif
806
807 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags/?f*", idCpu);
808 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat, "Total STATUS status bit events of any kind",
809 "/IEM/CPU%u/re/NativeLivenessEFlags/totalTotal", idCpu);
810
811 /* Corresponding ratios / percentages of the totals. */
812 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags/totalTotal", idCpu);
813 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeLivenessEFlags/totalSkippable", idCpu);
814 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
815 "Total skippable EFLAGS status bit updating percentage",
816 "/IEM/CPU%u/re/NativeLivenessEFlags/totalSkippablePct", idCpu);
817
818 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags/totalTotal", idCpu);
819 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeLivenessEFlags/totalRequired", idCpu);
820 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
821 "Total required EFLAGS status bit updating percentage",
822 "/IEM/CPU%u/re/NativeLivenessEFlags/totalRequiredPct", idCpu);
823
824# ifdef IEMLIVENESS_EXTENDED_LAYOUT
825 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeLivenessEFlags/totalDelayable", idCpu);
826 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
827 "Total potentially delayable EFLAGS status bit updating percentage",
828 "/IEM/CPU%u/re/NativeLivenessEFlags/totalDelayablePct", idCpu);
829# endif
830
831 /* Ratios of individual bits. */
832 size_t const offFlagChar = RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeLivenessEFlags/Cf*", idCpu) - 3;
833 Assert(szPat[offFlagChar] == 'C');
834 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativeLivenessEFlags/CfSkippable", idCpu);
835 Assert(szVal[offFlagChar] == 'C');
836 szPat[offFlagChar] = szVal[offFlagChar] = 'C'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.CF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlags/CfSkippablePct", idCpu);
837 szPat[offFlagChar] = szVal[offFlagChar] = 'P'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.PF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlags/PfSkippablePct", idCpu);
838 szPat[offFlagChar] = szVal[offFlagChar] = 'A'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.AF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlags/AfSkippablePct", idCpu);
839 szPat[offFlagChar] = szVal[offFlagChar] = 'Z'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.ZF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlags/ZfSkippablePct", idCpu);
840 szPat[offFlagChar] = szVal[offFlagChar] = 'S'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.SF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlags/SfSkippablePct", idCpu);
841 szPat[offFlagChar] = szVal[offFlagChar] = 'O'; STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, true, szPat, "Skippable EFLAGS.OF updating percentage", "/IEM/CPU%u/re/NativeLivenessEFlags/OfSkippablePct", idCpu);
842
843 /* PC updates total and skipped, with PCT ratio. */
844 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativePcUpdateTotal, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Total RIP updates", "/IEM/CPU%u/re/NativePcUpdateTotal", idCpu);
845 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativePcUpdateDelayed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Delayed RIP updates", "/IEM/CPU%u/re/NativePcUpdateDelayed", idCpu);
846 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativePcUpdateTotal", idCpu);
847 RTStrPrintf(szVal, sizeof(szVal), "/IEM/CPU%u/re/NativePcUpdateDelayed", idCpu);
848 STAMR3RegisterPctOfSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, STAMUNIT_PCT, szVal, false, szPat,
849 "Delayed RIP updating percentage",
850 "/IEM/CPU%u/re/NativePcUpdateDelayed_StatusDelayedPct", idCpu);
851
852# endif /* VBOX_WITH_STATISTICS */
853# ifdef IEMNATIVE_WITH_DELAYED_REGISTER_WRITEBACK
854 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeEndIfOtherBranchDirty, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
855 "IEM_MC_ENDIF flushing dirty shadow registers for other branch (not good).",
856 "/IEM/CPU%u/re/NativeEndIfOtherBranchDirty", idCpu);
857# endif
858# ifdef VBOX_WITH_STATISTICS
859# ifdef IEMNATIVE_WITH_SIMD_REG_ALLOCATOR
860 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeSimdRegFindFree, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
861 "Number of calls to iemNativeSimdRegAllocFindFree.",
862 "/IEM/CPU%u/re/NativeSimdRegFindFree", idCpu);
863 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeSimdRegFindFreeVar, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
864 "Number of times iemNativeSimdRegAllocFindFree needed to free a variable.",
865 "/IEM/CPU%u/re/NativeSimdRegFindFreeVar", idCpu);
866 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeSimdRegFindFreeNoVar, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
867 "Number of times iemNativeSimdRegAllocFindFree did not needed to free any variables.",
868 "/IEM/CPU%u/re/NativeSimdRegFindFreeNoVar", idCpu);
869 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeSimdRegFindFreeLivenessUnshadowed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
870 "Times liveness info freeed up shadowed guest registers in iemNativeSimdRegAllocFindFree.",
871 "/IEM/CPU%u/re/NativeSimdRegFindFreeLivenessUnshadowed", idCpu);
872 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeSimdRegFindFreeLivenessHelped, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
873 "Times liveness info helped finding the return register in iemNativeSimdRegAllocFindFree.",
874 "/IEM/CPU%u/re/NativeSimdRegFindFreeLivenessHelped", idCpu);
875
876 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeDeviceNotAvailXcptCheckPotential, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Potential IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE() checks",
877 "/IEM/CPU%u/re/NativeMaybeDeviceNotAvailXcptCheckPotential", idCpu);
878 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeWaitDeviceNotAvailXcptCheckPotential, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Potential IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE() checks",
879 "/IEM/CPU%u/re/NativeMaybeWaitDeviceNotAvailXcptCheckPotential", idCpu);
880 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeSseXcptCheckPotential, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Potential IEM_MC_MAYBE_RAISE_SSE_RELATED_XCPT() checks",
881 "/IEM/CPU%u/re/NativeMaybeSseXcptCheckPotential", idCpu);
882 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeAvxXcptCheckPotential, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Potential IEM_MC_MAYBE_RAISE_AVX_RELATED_XCPT() checks",
883 "/IEM/CPU%u/re/NativeMaybeAvxXcptCheckPotential", idCpu);
884
885 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeDeviceNotAvailXcptCheckOmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE() checks omitted",
886 "/IEM/CPU%u/re/NativeMaybeDeviceNotAvailXcptCheckOmitted", idCpu);
887 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeWaitDeviceNotAvailXcptCheckOmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE() checks omitted",
888 "/IEM/CPU%u/re/NativeMaybeWaitDeviceNotAvailXcptCheckOmitted", idCpu);
889 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeSseXcptCheckOmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "IEM_MC_MAYBE_RAISE_SSE_RELATED_XCPT() checks omitted",
890 "/IEM/CPU%u/re/NativeMaybeSseXcptCheckOmitted", idCpu);
891 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeMaybeAvxXcptCheckOmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "IEM_MC_MAYBE_RAISE_AVX_RELATED_XCPT() checks omitted",
892 "/IEM/CPU%u/re/NativeMaybeAvxXcptCheckOmitted", idCpu);
893# endif
894
895 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbFinished, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
896 "Number of times the TB finishes execution completely",
897 "/IEM/CPU%u/re/NativeTbFinished", idCpu);
898# endif /* VBOX_WITH_STATISTICS */
899 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitReturnBreak, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
900 "Number of times the TB finished through the ReturnBreak label",
901 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak", idCpu);
902 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitReturnBreakFF, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
903 "Number of times the TB finished through the ReturnBreak label",
904 "/IEM/CPU%u/re/NativeTbExit/ReturnBreakFF", idCpu);
905 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitReturnWithFlags, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
906 "Number of times the TB finished through the ReturnWithFlags label",
907 "/IEM/CPU%u/re/NativeTbExit/ReturnWithFlags", idCpu);
908 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitReturnOtherStatus, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
909 "Number of times the TB finished with some other status value",
910 "/IEM/CPU%u/re/NativeTbExit/ReturnOtherStatus", idCpu);
911 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitLongJump, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
912 "Number of times the TB finished via long jump / throw",
913 "/IEM/CPU%u/re/NativeTbExit/LongJumps", idCpu);
914 /* These end up returning VINF_IEM_REEXEC_BREAK and are thus already counted under NativeTbExit/ReturnBreak: */
915 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitObsoleteTb, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
916 "Number of times the TB finished through the ObsoleteTb label",
917 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/ObsoleteTb", idCpu);
918 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatCheckNeedCsLimChecking, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
919 "Number of times the TB finished through the NeedCsLimChecking label",
920 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/NeedCsLimChecking", idCpu);
921 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatCheckBranchMisses, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
922 "Number of times the TB finished through the CheckBranchMiss label",
923 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/CheckBranchMiss", idCpu);
924 /* Raising stuff will either increment NativeTbExit/LongJumps or NativeTbExit/ReturnOtherStatus
925 depending on whether VBOX_WITH_IEM_NATIVE_RECOMPILER_LONGJMP is defined: */
926# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER_LONGJMP
927# define RAISE_PREFIX "/IEM/CPU%u/re/NativeTbExit/ReturnOtherStatus/"
928# else
929# define RAISE_PREFIX "/IEM/CPU%u/re/NativeTbExit/LongJumps/"
930# endif
931 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseDe, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
932 "Number of times the TB finished raising a #DE exception",
933 RAISE_PREFIX "RaiseDe", idCpu);
934 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseUd, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
935 "Number of times the TB finished raising a #UD exception",
936 RAISE_PREFIX "RaiseUd", idCpu);
937 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseSseRelated, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
938 "Number of times the TB finished raising a SSE related exception",
939 RAISE_PREFIX "RaiseSseRelated", idCpu);
940 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseAvxRelated, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
941 "Number of times the TB finished raising a AVX related exception",
942 RAISE_PREFIX "RaiseAvxRelated", idCpu);
943 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseSseAvxFpRelated, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
944 "Number of times the TB finished raising a SSE/AVX floating point related exception",
945 RAISE_PREFIX "RaiseSseAvxFpRelated", idCpu);
946 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseNm, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
947 "Number of times the TB finished raising a #NM exception",
948 RAISE_PREFIX "RaiseNm", idCpu);
949 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseGp0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
950 "Number of times the TB finished raising a #GP(0) exception",
951 RAISE_PREFIX "RaiseGp0", idCpu);
952 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseMf, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
953 "Number of times the TB finished raising a #MF exception",
954 RAISE_PREFIX "RaiseMf", idCpu);
955 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitRaiseXf, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
956 "Number of times the TB finished raising a #XF exception",
957 RAISE_PREFIX "RaiseXf", idCpu);
958
959# ifdef VBOX_WITH_STATISTICS
960 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitLoopFullTb, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
961 "Number of full TB loops.",
962 "/IEM/CPU%u/re/NativeTbExit/LoopFullTb", idCpu);
963# endif
964
965 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1Irq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
966 "Direct linking #1 with IRQ check succeeded",
967 "/IEM/CPU%u/re/NativeTbExit/DirectLinking1Irq", idCpu);
968 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1NoIrq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
969 "Direct linking #1 w/o IRQ check succeeded",
970 "/IEM/CPU%u/re/NativeTbExit/DirectLinking1NoIrq", idCpu);
971# ifdef VBOX_WITH_STATISTICS
972 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1NoTb, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
973 "Direct linking #1 failed: No TB in lookup table",
974 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking1NoTb", idCpu);
975 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1MismatchGCPhysPc, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
976 "Direct linking #1 failed: GCPhysPc mismatch",
977 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking1MismatchGCPhysPc", idCpu);
978 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1MismatchFlags, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
979 "Direct linking #1 failed: TB flags mismatch",
980 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking1MismatchFlags", idCpu);
981 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking1PendingIrq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
982 "Direct linking #1 failed: IRQ or FF pending",
983 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking1PendingIrq", idCpu);
984# endif
985
986 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2Irq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
987 "Direct linking #2 with IRQ check succeeded",
988 "/IEM/CPU%u/re/NativeTbExit/DirectLinking2Irq", idCpu);
989 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2NoIrq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
990 "Direct linking #2 w/o IRQ check succeeded",
991 "/IEM/CPU%u/re/NativeTbExit/DirectLinking2NoIrq", idCpu);
992# ifdef VBOX_WITH_STATISTICS
993 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2NoTb, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
994 "Direct linking #2 failed: No TB in lookup table",
995 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking2NoTb", idCpu);
996 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2MismatchGCPhysPc, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
997 "Direct linking #2 failed: GCPhysPc mismatch",
998 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking2MismatchGCPhysPc", idCpu);
999 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2MismatchFlags, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
1000 "Direct linking #2 failed: TB flags mismatch",
1001 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking2MismatchFlags", idCpu);
1002 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatNativeTbExitDirectLinking2PendingIrq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
1003 "Direct linking #2 failed: IRQ or FF pending",
1004 "/IEM/CPU%u/re/NativeTbExit/ReturnBreak/DirectLinking2PendingIrq", idCpu);
1005# endif
1006
1007 RTStrPrintf(szPat, sizeof(szPat), "/IEM/CPU%u/re/NativeTbExit/*", idCpu); /* only immediate children, no sub folders */
1008 STAMR3RegisterSum(pVM->pUVM, STAMVISIBILITY_ALWAYS, szPat,
1009 "Number of times native TB execution finished before the end (not counting thrown memory++ exceptions)",
1010 "/IEM/CPU%u/re/NativeTbExit", idCpu);
1011
1012
1013# endif /* VBOX_WITH_IEM_NATIVE_RECOMPILER */
1014
1015
1016# ifdef VBOX_WITH_STATISTICS
1017 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatMemMapJmp, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
1018 "iemMemMapJmp calls", "/IEM/CPU%u/iemMemMapJmp", idCpu);
1019 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatMemMapNoJmp, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
1020 "iemMemMap calls", "/IEM/CPU%u/iemMemMapNoJmp", idCpu);
1021 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatMemBounceBufferCrossPage, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
1022 "iemMemBounceBufferMapCrossPage calls", "/IEM/CPU%u/iemMemMapBounceBufferCrossPage", idCpu);
1023 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatMemBounceBufferMapPhys, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
1024 "iemMemBounceBufferMapPhys calls", "/IEM/CPU%u/iemMemMapBounceBufferMapPhys", idCpu);
1025# endif
1026
1027
1028#endif /* VBOX_WITH_IEM_RECOMPILER */
1029
1030 for (uint32_t i = 0; i < RT_ELEMENTS(pVCpu->iem.s.aStatXcpts); i++)
1031 STAMR3RegisterF(pVM, &pVCpu->iem.s.aStatXcpts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1032 "", "/IEM/CPU%u/Exceptions/%02x", idCpu, i);
1033 for (uint32_t i = 0; i < RT_ELEMENTS(pVCpu->iem.s.aStatInts); i++)
1034 STAMR3RegisterF(pVM, &pVCpu->iem.s.aStatInts[i], STAMTYPE_U32_RESET, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
1035 "", "/IEM/CPU%u/Interrupts/%02x", idCpu, i);
1036
1037# if !defined(VBOX_VMM_TARGET_ARMV8) && defined(VBOX_WITH_STATISTICS) && !defined(DOXYGEN_RUNNING)
1038 /* Instruction statistics: */
1039# define IEM_DO_INSTR_STAT(a_Name, a_szDesc) \
1040 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatsRZ.a_Name, STAMTYPE_U32_RESET, STAMVISIBILITY_USED, \
1041 STAMUNIT_COUNT, a_szDesc, "/IEM/CPU%u/instr-RZ/" #a_Name, idCpu); \
1042 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatsR3.a_Name, STAMTYPE_U32_RESET, STAMVISIBILITY_USED, \
1043 STAMUNIT_COUNT, a_szDesc, "/IEM/CPU%u/instr-R3/" #a_Name, idCpu);
1044# include "IEMInstructionStatisticsTmpl.h"
1045# undef IEM_DO_INSTR_STAT
1046# endif
1047
1048# if defined(VBOX_WITH_STATISTICS) && defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
1049 /* Threaded function statistics: */
1050 for (unsigned i = 1; i < (unsigned)kIemThreadedFunc_End; i++)
1051 STAMR3RegisterF(pVM, &pVCpu->iem.s.acThreadedFuncStats[i], STAMTYPE_U32_RESET, STAMVISIBILITY_USED,
1052 STAMUNIT_COUNT, NULL, "/IEM/CPU%u/ThrdFuncs/%s", idCpu, g_apszIemThreadedFunctionStats[i]);
1053# endif
1054
1055#endif /* !defined(VBOX_VMM_TARGET_ARMV8) && defined(VBOX_WITH_NESTED_HWVIRT_VMX) - quick fix for stupid structure duplication non-sense */
1056 }
1057
1058#if !defined(VBOX_VMM_TARGET_ARMV8) && defined(VBOX_WITH_NESTED_HWVIRT_VMX)
1059 /*
1060 * Register the per-VM VMX APIC-access page handler type.
1061 */
1062 if (pVM->cpum.ro.GuestFeatures.fVmx)
1063 {
1064 rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_ALL, PGMPHYSHANDLER_F_NOT_IN_HM,
1065 iemVmxApicAccessPageHandler,
1066 "VMX APIC-access page", &pVM->iem.s.hVmxApicAccessPage);
1067 AssertLogRelRCReturn(rc, rc);
1068 }
1069#endif
1070
1071 DBGFR3InfoRegisterInternalArgv(pVM, "itlb", "IEM instruction TLB", iemR3InfoITlb, DBGFINFO_FLAGS_RUN_ON_EMT);
1072 DBGFR3InfoRegisterInternalArgv(pVM, "dtlb", "IEM instruction TLB", iemR3InfoDTlb, DBGFINFO_FLAGS_RUN_ON_EMT);
1073#ifdef IEM_WITH_TLB_TRACE
1074 DBGFR3InfoRegisterInternalArgv(pVM, "tlbtrace", "IEM TLB trace log", iemR3InfoTlbTrace, DBGFINFO_FLAGS_RUN_ON_EMT);
1075#endif
1076#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
1077 DBGFR3InfoRegisterInternalArgv(pVM, "tb", "IEM translation block", iemR3InfoTb, DBGFINFO_FLAGS_RUN_ON_EMT);
1078 DBGFR3InfoRegisterInternalArgv(pVM, "tbtop", "IEM translation blocks most used or most recently used",
1079 iemR3InfoTbTop, DBGFINFO_FLAGS_RUN_ON_EMT);
1080#endif
1081#ifdef VBOX_WITH_DEBUGGER
1082 iemR3RegisterDebuggerCommands();
1083#endif
1084
1085 return VINF_SUCCESS;
1086}
1087
1088
1089VMMR3DECL(int) IEMR3Term(PVM pVM)
1090{
1091 NOREF(pVM);
1092#ifdef IEM_WITH_TLB_TRACE
1093 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1094 {
1095 PVMCPU const pVCpu = pVM->apCpusR3[idCpu];
1096 RTMemPageFree(pVCpu->iem.s.paTlbTraceEntries,
1097 RT_BIT_Z(pVCpu->iem.s.cTlbTraceEntriesShift) * sizeof(*pVCpu->iem.s.paTlbTraceEntries));
1098 }
1099#endif
1100 return VINF_SUCCESS;
1101}
1102
1103
1104VMMR3DECL(void) IEMR3Relocate(PVM pVM)
1105{
1106 RT_NOREF(pVM);
1107}
1108
1109
1110/**
1111 * Gets the name of a generic IEM exit code.
1112 *
1113 * @returns Pointer to read only string if @a uExit is known, otherwise NULL.
1114 * @param uExit The IEM exit to name.
1115 */
1116VMMR3DECL(const char *) IEMR3GetExitName(uint32_t uExit)
1117{
1118 static const char * const s_apszNames[] =
1119 {
1120 /* external interrupts */
1121 "ExtInt 00h", "ExtInt 01h", "ExtInt 02h", "ExtInt 03h", "ExtInt 04h", "ExtInt 05h", "ExtInt 06h", "ExtInt 07h",
1122 "ExtInt 08h", "ExtInt 09h", "ExtInt 0ah", "ExtInt 0bh", "ExtInt 0ch", "ExtInt 0dh", "ExtInt 0eh", "ExtInt 0fh",
1123 "ExtInt 10h", "ExtInt 11h", "ExtInt 12h", "ExtInt 13h", "ExtInt 14h", "ExtInt 15h", "ExtInt 16h", "ExtInt 17h",
1124 "ExtInt 18h", "ExtInt 19h", "ExtInt 1ah", "ExtInt 1bh", "ExtInt 1ch", "ExtInt 1dh", "ExtInt 1eh", "ExtInt 1fh",
1125 "ExtInt 20h", "ExtInt 21h", "ExtInt 22h", "ExtInt 23h", "ExtInt 24h", "ExtInt 25h", "ExtInt 26h", "ExtInt 27h",
1126 "ExtInt 28h", "ExtInt 29h", "ExtInt 2ah", "ExtInt 2bh", "ExtInt 2ch", "ExtInt 2dh", "ExtInt 2eh", "ExtInt 2fh",
1127 "ExtInt 30h", "ExtInt 31h", "ExtInt 32h", "ExtInt 33h", "ExtInt 34h", "ExtInt 35h", "ExtInt 36h", "ExtInt 37h",
1128 "ExtInt 38h", "ExtInt 39h", "ExtInt 3ah", "ExtInt 3bh", "ExtInt 3ch", "ExtInt 3dh", "ExtInt 3eh", "ExtInt 3fh",
1129 "ExtInt 40h", "ExtInt 41h", "ExtInt 42h", "ExtInt 43h", "ExtInt 44h", "ExtInt 45h", "ExtInt 46h", "ExtInt 47h",
1130 "ExtInt 48h", "ExtInt 49h", "ExtInt 4ah", "ExtInt 4bh", "ExtInt 4ch", "ExtInt 4dh", "ExtInt 4eh", "ExtInt 4fh",
1131 "ExtInt 50h", "ExtInt 51h", "ExtInt 52h", "ExtInt 53h", "ExtInt 54h", "ExtInt 55h", "ExtInt 56h", "ExtInt 57h",
1132 "ExtInt 58h", "ExtInt 59h", "ExtInt 5ah", "ExtInt 5bh", "ExtInt 5ch", "ExtInt 5dh", "ExtInt 5eh", "ExtInt 5fh",
1133 "ExtInt 60h", "ExtInt 61h", "ExtInt 62h", "ExtInt 63h", "ExtInt 64h", "ExtInt 65h", "ExtInt 66h", "ExtInt 67h",
1134 "ExtInt 68h", "ExtInt 69h", "ExtInt 6ah", "ExtInt 6bh", "ExtInt 6ch", "ExtInt 6dh", "ExtInt 6eh", "ExtInt 6fh",
1135 "ExtInt 70h", "ExtInt 71h", "ExtInt 72h", "ExtInt 73h", "ExtInt 74h", "ExtInt 75h", "ExtInt 76h", "ExtInt 77h",
1136 "ExtInt 78h", "ExtInt 79h", "ExtInt 7ah", "ExtInt 7bh", "ExtInt 7ch", "ExtInt 7dh", "ExtInt 7eh", "ExtInt 7fh",
1137 "ExtInt 80h", "ExtInt 81h", "ExtInt 82h", "ExtInt 83h", "ExtInt 84h", "ExtInt 85h", "ExtInt 86h", "ExtInt 87h",
1138 "ExtInt 88h", "ExtInt 89h", "ExtInt 8ah", "ExtInt 8bh", "ExtInt 8ch", "ExtInt 8dh", "ExtInt 8eh", "ExtInt 8fh",
1139 "ExtInt 90h", "ExtInt 91h", "ExtInt 92h", "ExtInt 93h", "ExtInt 94h", "ExtInt 95h", "ExtInt 96h", "ExtInt 97h",
1140 "ExtInt 98h", "ExtInt 99h", "ExtInt 9ah", "ExtInt 9bh", "ExtInt 9ch", "ExtInt 9dh", "ExtInt 9eh", "ExtInt 9fh",
1141 "ExtInt a0h", "ExtInt a1h", "ExtInt a2h", "ExtInt a3h", "ExtInt a4h", "ExtInt a5h", "ExtInt a6h", "ExtInt a7h",
1142 "ExtInt a8h", "ExtInt a9h", "ExtInt aah", "ExtInt abh", "ExtInt ach", "ExtInt adh", "ExtInt aeh", "ExtInt afh",
1143 "ExtInt b0h", "ExtInt b1h", "ExtInt b2h", "ExtInt b3h", "ExtInt b4h", "ExtInt b5h", "ExtInt b6h", "ExtInt b7h",
1144 "ExtInt b8h", "ExtInt b9h", "ExtInt bah", "ExtInt bbh", "ExtInt bch", "ExtInt bdh", "ExtInt beh", "ExtInt bfh",
1145 "ExtInt c0h", "ExtInt c1h", "ExtInt c2h", "ExtInt c3h", "ExtInt c4h", "ExtInt c5h", "ExtInt c6h", "ExtInt c7h",
1146 "ExtInt c8h", "ExtInt c9h", "ExtInt cah", "ExtInt cbh", "ExtInt cch", "ExtInt cdh", "ExtInt ceh", "ExtInt cfh",
1147 "ExtInt d0h", "ExtInt d1h", "ExtInt d2h", "ExtInt d3h", "ExtInt d4h", "ExtInt d5h", "ExtInt d6h", "ExtInt d7h",
1148 "ExtInt d8h", "ExtInt d9h", "ExtInt dah", "ExtInt dbh", "ExtInt dch", "ExtInt ddh", "ExtInt deh", "ExtInt dfh",
1149 "ExtInt e0h", "ExtInt e1h", "ExtInt e2h", "ExtInt e3h", "ExtInt e4h", "ExtInt e5h", "ExtInt e6h", "ExtInt e7h",
1150 "ExtInt e8h", "ExtInt e9h", "ExtInt eah", "ExtInt ebh", "ExtInt ech", "ExtInt edh", "ExtInt eeh", "ExtInt efh",
1151 "ExtInt f0h", "ExtInt f1h", "ExtInt f2h", "ExtInt f3h", "ExtInt f4h", "ExtInt f5h", "ExtInt f6h", "ExtInt f7h",
1152 "ExtInt f8h", "ExtInt f9h", "ExtInt fah", "ExtInt fbh", "ExtInt fch", "ExtInt fdh", "ExtInt feh", "ExtInt ffh",
1153 /* software interrups */
1154 "SoftInt 00h", "SoftInt 01h", "SoftInt 02h", "SoftInt 03h", "SoftInt 04h", "SoftInt 05h", "SoftInt 06h", "SoftInt 07h",
1155 "SoftInt 08h", "SoftInt 09h", "SoftInt 0ah", "SoftInt 0bh", "SoftInt 0ch", "SoftInt 0dh", "SoftInt 0eh", "SoftInt 0fh",
1156 "SoftInt 10h", "SoftInt 11h", "SoftInt 12h", "SoftInt 13h", "SoftInt 14h", "SoftInt 15h", "SoftInt 16h", "SoftInt 17h",
1157 "SoftInt 18h", "SoftInt 19h", "SoftInt 1ah", "SoftInt 1bh", "SoftInt 1ch", "SoftInt 1dh", "SoftInt 1eh", "SoftInt 1fh",
1158 "SoftInt 20h", "SoftInt 21h", "SoftInt 22h", "SoftInt 23h", "SoftInt 24h", "SoftInt 25h", "SoftInt 26h", "SoftInt 27h",
1159 "SoftInt 28h", "SoftInt 29h", "SoftInt 2ah", "SoftInt 2bh", "SoftInt 2ch", "SoftInt 2dh", "SoftInt 2eh", "SoftInt 2fh",
1160 "SoftInt 30h", "SoftInt 31h", "SoftInt 32h", "SoftInt 33h", "SoftInt 34h", "SoftInt 35h", "SoftInt 36h", "SoftInt 37h",
1161 "SoftInt 38h", "SoftInt 39h", "SoftInt 3ah", "SoftInt 3bh", "SoftInt 3ch", "SoftInt 3dh", "SoftInt 3eh", "SoftInt 3fh",
1162 "SoftInt 40h", "SoftInt 41h", "SoftInt 42h", "SoftInt 43h", "SoftInt 44h", "SoftInt 45h", "SoftInt 46h", "SoftInt 47h",
1163 "SoftInt 48h", "SoftInt 49h", "SoftInt 4ah", "SoftInt 4bh", "SoftInt 4ch", "SoftInt 4dh", "SoftInt 4eh", "SoftInt 4fh",
1164 "SoftInt 50h", "SoftInt 51h", "SoftInt 52h", "SoftInt 53h", "SoftInt 54h", "SoftInt 55h", "SoftInt 56h", "SoftInt 57h",
1165 "SoftInt 58h", "SoftInt 59h", "SoftInt 5ah", "SoftInt 5bh", "SoftInt 5ch", "SoftInt 5dh", "SoftInt 5eh", "SoftInt 5fh",
1166 "SoftInt 60h", "SoftInt 61h", "SoftInt 62h", "SoftInt 63h", "SoftInt 64h", "SoftInt 65h", "SoftInt 66h", "SoftInt 67h",
1167 "SoftInt 68h", "SoftInt 69h", "SoftInt 6ah", "SoftInt 6bh", "SoftInt 6ch", "SoftInt 6dh", "SoftInt 6eh", "SoftInt 6fh",
1168 "SoftInt 70h", "SoftInt 71h", "SoftInt 72h", "SoftInt 73h", "SoftInt 74h", "SoftInt 75h", "SoftInt 76h", "SoftInt 77h",
1169 "SoftInt 78h", "SoftInt 79h", "SoftInt 7ah", "SoftInt 7bh", "SoftInt 7ch", "SoftInt 7dh", "SoftInt 7eh", "SoftInt 7fh",
1170 "SoftInt 80h", "SoftInt 81h", "SoftInt 82h", "SoftInt 83h", "SoftInt 84h", "SoftInt 85h", "SoftInt 86h", "SoftInt 87h",
1171 "SoftInt 88h", "SoftInt 89h", "SoftInt 8ah", "SoftInt 8bh", "SoftInt 8ch", "SoftInt 8dh", "SoftInt 8eh", "SoftInt 8fh",
1172 "SoftInt 90h", "SoftInt 91h", "SoftInt 92h", "SoftInt 93h", "SoftInt 94h", "SoftInt 95h", "SoftInt 96h", "SoftInt 97h",
1173 "SoftInt 98h", "SoftInt 99h", "SoftInt 9ah", "SoftInt 9bh", "SoftInt 9ch", "SoftInt 9dh", "SoftInt 9eh", "SoftInt 9fh",
1174 "SoftInt a0h", "SoftInt a1h", "SoftInt a2h", "SoftInt a3h", "SoftInt a4h", "SoftInt a5h", "SoftInt a6h", "SoftInt a7h",
1175 "SoftInt a8h", "SoftInt a9h", "SoftInt aah", "SoftInt abh", "SoftInt ach", "SoftInt adh", "SoftInt aeh", "SoftInt afh",
1176 "SoftInt b0h", "SoftInt b1h", "SoftInt b2h", "SoftInt b3h", "SoftInt b4h", "SoftInt b5h", "SoftInt b6h", "SoftInt b7h",
1177 "SoftInt b8h", "SoftInt b9h", "SoftInt bah", "SoftInt bbh", "SoftInt bch", "SoftInt bdh", "SoftInt beh", "SoftInt bfh",
1178 "SoftInt c0h", "SoftInt c1h", "SoftInt c2h", "SoftInt c3h", "SoftInt c4h", "SoftInt c5h", "SoftInt c6h", "SoftInt c7h",
1179 "SoftInt c8h", "SoftInt c9h", "SoftInt cah", "SoftInt cbh", "SoftInt cch", "SoftInt cdh", "SoftInt ceh", "SoftInt cfh",
1180 "SoftInt d0h", "SoftInt d1h", "SoftInt d2h", "SoftInt d3h", "SoftInt d4h", "SoftInt d5h", "SoftInt d6h", "SoftInt d7h",
1181 "SoftInt d8h", "SoftInt d9h", "SoftInt dah", "SoftInt dbh", "SoftInt dch", "SoftInt ddh", "SoftInt deh", "SoftInt dfh",
1182 "SoftInt e0h", "SoftInt e1h", "SoftInt e2h", "SoftInt e3h", "SoftInt e4h", "SoftInt e5h", "SoftInt e6h", "SoftInt e7h",
1183 "SoftInt e8h", "SoftInt e9h", "SoftInt eah", "SoftInt ebh", "SoftInt ech", "SoftInt edh", "SoftInt eeh", "SoftInt efh",
1184 "SoftInt f0h", "SoftInt f1h", "SoftInt f2h", "SoftInt f3h", "SoftInt f4h", "SoftInt f5h", "SoftInt f6h", "SoftInt f7h",
1185 "SoftInt f8h", "SoftInt f9h", "SoftInt fah", "SoftInt fbh", "SoftInt fch", "SoftInt fdh", "SoftInt feh", "SoftInt ffh",
1186 };
1187 if (uExit < RT_ELEMENTS(s_apszNames))
1188 return s_apszNames[uExit];
1189 return NULL;
1190}
1191
1192
1193/** Worker for iemR3InfoTlbPrintSlots and iemR3InfoTlbPrintAddress. */
1194static void iemR3InfoTlbPrintHeader(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb, bool *pfHeader)
1195{
1196 if (*pfHeader)
1197 return;
1198 pHlp->pfnPrintf(pHlp, "%cTLB for CPU %u:\n", &pVCpu->iem.s.CodeTlb == pTlb ? 'I' : 'D', pVCpu->idCpu);
1199 *pfHeader = true;
1200}
1201
1202
1203#define IEMR3INFOTLB_F_ONLY_VALID RT_BIT_32(0)
1204#define IEMR3INFOTLB_F_CHECK RT_BIT_32(1)
1205
1206/** Worker for iemR3InfoTlbPrintSlots and iemR3InfoTlbPrintAddress. */
1207static void iemR3InfoTlbPrintSlot(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb, IEMTLBENTRY const *pTlbe,
1208 uint32_t uSlot, uint32_t fFlags)
1209{
1210#ifndef VBOX_VMM_TARGET_ARMV8
1211 uint64_t const uTlbRevision = !(uSlot & 1) ? pTlb->uTlbRevision : pTlb->uTlbRevisionGlobal;
1212#else
1213 uint64_t const uTlbRevision = pTlb->uTlbRevision;
1214#endif
1215 if ((fFlags & IEMR3INFOTLB_F_ONLY_VALID) && (pTlbe->uTag & IEMTLB_REVISION_MASK) != uTlbRevision)
1216 return;
1217
1218 /* The address needs to be sign extended, thus the shifting fun here.*/
1219 RTGCPTR const GCPtr = (RTGCINTPTR)((pTlbe->uTag & ~IEMTLB_REVISION_MASK) << (64 - IEMTLB_TAG_ADDR_WIDTH))
1220 >> (64 - IEMTLB_TAG_ADDR_WIDTH - GUEST_PAGE_SHIFT);
1221 const char *pszValid = "";
1222#ifndef VBOX_VMM_TARGET_ARMV8
1223 char szTmp[128];
1224 if (fFlags & IEMR3INFOTLB_F_CHECK)
1225 {
1226 uint32_t const fInvSlotG = (uint32_t)!(uSlot & 1) << X86_PTE_BIT_G;
1227 PGMPTWALKFAST WalkFast;
1228 int rc = PGMGstQueryPageFast(pVCpu, GCPtr, 0 /*fFlags - don't check or modify anything */, &WalkFast);
1229 pszValid = szTmp;
1230 if (RT_FAILURE(rc))
1231 switch (rc)
1232 {
1233 case VERR_PAGE_TABLE_NOT_PRESENT:
1234 switch ((WalkFast.fFailed & PGM_WALKFAIL_LEVEL_MASK) >> PGM_WALKFAIL_LEVEL_SHIFT)
1235 {
1236 case 1: pszValid = " stale(page-not-present)"; break;
1237 case 2: pszValid = " stale(pd-entry-not-present)"; break;
1238 case 3: pszValid = " stale(pdptr-entry-not-present)"; break;
1239 case 4: pszValid = " stale(pml4-entry-not-present)"; break;
1240 case 5: pszValid = " stale(pml5-entry-not-present)"; break;
1241 default: pszValid = " stale(VERR_PAGE_TABLE_NOT_PRESENT)"; break;
1242 }
1243 break;
1244 default: RTStrPrintf(szTmp, sizeof(szTmp), " stale(rc=%d)", rc); break;
1245 }
1246 else if (WalkFast.GCPhys != pTlbe->GCPhys)
1247 RTStrPrintf(szTmp, sizeof(szTmp), " stale(GCPhys=%RGp)", WalkFast.GCPhys);
1248 else if ( (~WalkFast.fEffective & (X86_PTE_RW | X86_PTE_US | X86_PTE_G | X86_PTE_A | X86_PTE_D))
1249 == ( (pTlbe->fFlagsAndPhysRev & ( IEMTLBE_F_PT_NO_WRITE | IEMTLBE_F_PT_NO_USER
1250 | IEMTLBE_F_PT_NO_DIRTY | IEMTLBE_F_PT_NO_ACCESSED))
1251 | fInvSlotG ) )
1252 pszValid = " still-valid";
1253 else if ( (~WalkFast.fEffective & (X86_PTE_RW | X86_PTE_US | X86_PTE_G))
1254 == ((pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_WRITE | IEMTLBE_F_PT_NO_USER)) | fInvSlotG) )
1255 switch ( (~WalkFast.fEffective & (X86_PTE_A | X86_PTE_D))
1256 ^ (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_DIRTY | IEMTLBE_F_PT_NO_ACCESSED)) )
1257 {
1258 case X86_PTE_A:
1259 pszValid = WalkFast.fEffective & X86_PTE_A ? " still-valid(accessed-now)" : " still-valid(accessed-no-more)";
1260 break;
1261 case X86_PTE_D:
1262 pszValid = WalkFast.fEffective & X86_PTE_D ? " still-valid(dirty-now)" : " still-valid(dirty-no-more)";
1263 break;
1264 case X86_PTE_D | X86_PTE_A:
1265 RTStrPrintf(szTmp, sizeof(szTmp), " still-valid(%s%s)",
1266 (~WalkFast.fEffective & X86_PTE_D) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_DIRTY) ? ""
1267 : WalkFast.fEffective & X86_PTE_D ? "dirty-now" : "dirty-no-more",
1268 (~WalkFast.fEffective & X86_PTE_A) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED) ? ""
1269 : WalkFast.fEffective & X86_PTE_A ? " accessed-now" : " accessed-no-more");
1270 break;
1271 default: AssertFailed(); break;
1272 }
1273 else
1274 RTStrPrintf(szTmp, sizeof(szTmp), " stale(%s%s%s%s%s)",
1275 (~WalkFast.fEffective & X86_PTE_RW) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE) ? ""
1276 : WalkFast.fEffective & X86_PTE_RW ? "writeable-now" : "writable-no-more",
1277 (~WalkFast.fEffective & X86_PTE_US) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) ? ""
1278 : WalkFast.fEffective & X86_PTE_US ? " user-now" : " user-no-more",
1279 (~WalkFast.fEffective & X86_PTE_G) == fInvSlotG ? ""
1280 : WalkFast.fEffective & X86_PTE_G ? " global-now" : " global-no-more",
1281 (~WalkFast.fEffective & X86_PTE_D) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_DIRTY) ? ""
1282 : WalkFast.fEffective & X86_PTE_D ? " dirty-now" : " dirty-no-more",
1283 (~WalkFast.fEffective & X86_PTE_A) == (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED) ? ""
1284 : WalkFast.fEffective & X86_PTE_A ? " accessed-now" : " accessed-no-more");
1285 }
1286#else
1287 RT_NOREF(pVCpu);
1288#endif
1289
1290 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",
1291 uSlot,
1292 (pTlbe->uTag & IEMTLB_REVISION_MASK) == uTlbRevision ? "valid "
1293 : (pTlbe->uTag & IEMTLB_REVISION_MASK) == 0 ? "empty "
1294 : "expired",
1295 GCPtr, /* -> */
1296 pTlbe->GCPhys, /* / */ pTlbe->pbMappingR3,
1297 /* / */
1298 (uint32_t)(pTlbe->fFlagsAndPhysRev & ~IEMTLBE_F_PHYS_REV),
1299 /* */
1300 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE ? "R-" : "RW",
1301 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC ? "-" : "X",
1302 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED ? "-" : "A",
1303 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_DIRTY ? "-" : "D",
1304 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER ? "U" : "S",
1305 !(uSlot & 1) ? "-" : "G",
1306 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_LARGE_PAGE ? "4K" : "2M",
1307 /* / */
1308 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_WRITE ? "-" : "w",
1309 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_READ ? "-" : "r",
1310 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_UNASSIGNED ? "u" : "-",
1311 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_CODE_PAGE ? "c" : "-",
1312 /* / */
1313 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_NO_MAPPINGR3 ? "N" : "M",
1314 (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pTlb->uTlbPhysRev ? "phys-valid"
1315 : (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == 0 ? "phys-empty" : "phys-expired",
1316 pszValid);
1317}
1318
1319
1320/** Displays one or more TLB slots. */
1321static void iemR3InfoTlbPrintSlots(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb,
1322 uint32_t uSlot, uint32_t cSlots, uint32_t fFlags, bool *pfHeader)
1323{
1324 if (uSlot < RT_ELEMENTS(pTlb->aEntries))
1325 {
1326 if (cSlots > RT_ELEMENTS(pTlb->aEntries))
1327 {
1328 pHlp->pfnPrintf(pHlp, "error: Too many slots given: %u, adjusting it down to the max (%u)\n",
1329 cSlots, RT_ELEMENTS(pTlb->aEntries));
1330 cSlots = RT_ELEMENTS(pTlb->aEntries);
1331 }
1332
1333 iemR3InfoTlbPrintHeader(pVCpu, pHlp, pTlb, pfHeader);
1334 while (cSlots-- > 0)
1335 {
1336 IEMTLBENTRY const Tlbe = pTlb->aEntries[uSlot];
1337 iemR3InfoTlbPrintSlot(pVCpu, pHlp, pTlb, &Tlbe, uSlot, fFlags);
1338 uSlot = (uSlot + 1) % RT_ELEMENTS(pTlb->aEntries);
1339 }
1340 }
1341 else
1342 pHlp->pfnPrintf(pHlp, "error: TLB slot is out of range: %u (%#x), max %u (%#x)\n",
1343 uSlot, uSlot, RT_ELEMENTS(pTlb->aEntries) - 1, RT_ELEMENTS(pTlb->aEntries) - 1);
1344}
1345
1346
1347/** Displays the TLB slot for the given address. */
1348static void iemR3InfoTlbPrintAddress(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb,
1349 uint64_t uAddress, uint32_t fFlags, bool *pfHeader)
1350{
1351 iemR3InfoTlbPrintHeader(pVCpu, pHlp, pTlb, pfHeader);
1352
1353 uint64_t const uTag = IEMTLB_CALC_TAG_NO_REV(uAddress);
1354#ifdef IEMTLB_TAG_TO_EVEN_INDEX
1355 uint32_t const uSlot = IEMTLB_TAG_TO_EVEN_INDEX(uTag);
1356#else
1357 uint32_t const uSlot = IEMTLB_TAG_TO_INDEX(uTag);
1358#endif
1359 IEMTLBENTRY const TlbeL = pTlb->aEntries[uSlot];
1360#ifndef VBOX_VMM_TARGET_ARMV8
1361 IEMTLBENTRY const TlbeG = pTlb->aEntries[uSlot + 1];
1362#endif
1363 pHlp->pfnPrintf(pHlp, "Address %#RX64 -> slot %#x - %s\n", uAddress, uSlot,
1364 TlbeL.uTag == (uTag | pTlb->uTlbRevision) ? "match"
1365 : (TlbeL.uTag & ~IEMTLB_REVISION_MASK) == uTag ? "expired" : "mismatch");
1366 iemR3InfoTlbPrintSlot(pVCpu, pHlp, pTlb, &TlbeL, uSlot, fFlags);
1367
1368#ifndef VBOX_VMM_TARGET_ARMV8
1369 pHlp->pfnPrintf(pHlp, "Address %#RX64 -> slot %#x - %s\n", uAddress, uSlot + 1,
1370 TlbeG.uTag == (uTag | pTlb->uTlbRevisionGlobal) ? "match"
1371 : (TlbeG.uTag & ~IEMTLB_REVISION_MASK) == uTag ? "expired" : "mismatch");
1372 iemR3InfoTlbPrintSlot(pVCpu, pHlp, pTlb, &TlbeG, uSlot + 1, fFlags);
1373#endif
1374}
1375
1376
1377/** Common worker for iemR3InfoDTlb and iemR3InfoITlb. */
1378static void iemR3InfoTlbCommon(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs, bool fITlb)
1379{
1380 /*
1381 * This is entirely argument driven.
1382 */
1383 static RTGETOPTDEF const s_aOptions[] =
1384 {
1385 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
1386 { "--vcpu", 'c', RTGETOPT_REQ_UINT32 },
1387 { "--check", 'C', RTGETOPT_REQ_NOTHING },
1388 { "all", 'A', RTGETOPT_REQ_NOTHING },
1389 { "--all", 'A', RTGETOPT_REQ_NOTHING },
1390 { "--address", 'a', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1391 { "--range", 'r', RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_HEX },
1392 { "--slot", 's', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX },
1393 { "--only-valid", 'v', RTGETOPT_REQ_NOTHING },
1394 };
1395
1396 RTGETOPTSTATE State;
1397 int rc = RTGetOptInit(&State, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /*iFirst*/, 0 /*fFlags*/);
1398 AssertRCReturnVoid(rc);
1399
1400 uint32_t cActionArgs = 0;
1401 bool fNeedHeader = true;
1402 bool fAddressMode = true;
1403 uint32_t fFlags = 0;
1404 PVMCPU const pVCpuCall = VMMGetCpu(pVM);
1405 PVMCPU pVCpu = pVCpuCall;
1406 if (!pVCpu)
1407 pVCpu = VMMGetCpuById(pVM, 0);
1408
1409 RTGETOPTUNION ValueUnion;
1410 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
1411 {
1412 switch (rc)
1413 {
1414 case 'c':
1415 if (ValueUnion.u32 >= pVM->cCpus)
1416 pHlp->pfnPrintf(pHlp, "error: Invalid CPU ID: %u\n", ValueUnion.u32);
1417 else if (!pVCpu || pVCpu->idCpu != ValueUnion.u32)
1418 {
1419 pVCpu = VMMGetCpuById(pVM, ValueUnion.u32);
1420 fNeedHeader = true;
1421 if (!pVCpuCall || pVCpuCall->idCpu != ValueUnion.u32)
1422 {
1423 pHlp->pfnPrintf(pHlp, "info: Can't check guest PTs when switching to a different VCpu! Targetting %u, on %u.\n",
1424 ValueUnion.u32, pVCpuCall->idCpu);
1425 fFlags &= ~IEMR3INFOTLB_F_CHECK;
1426 }
1427 }
1428 break;
1429
1430 case 'C':
1431 if (!pVCpuCall)
1432 pHlp->pfnPrintf(pHlp, "error: Can't check guest PT when not running on an EMT!\n");
1433 else if (pVCpu != pVCpuCall)
1434 pHlp->pfnPrintf(pHlp, "error: Can't check guest PTs when on a different EMT! Targetting %u, on %u.\n",
1435 pVCpu->idCpu, pVCpuCall->idCpu);
1436 else
1437 fFlags |= IEMR3INFOTLB_F_CHECK;
1438 break;
1439
1440 case 'a':
1441 iemR3InfoTlbPrintAddress(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1442 ValueUnion.u64, fFlags, &fNeedHeader);
1443 fAddressMode = true;
1444 cActionArgs++;
1445 break;
1446
1447 case 'A':
1448 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1449 0, RT_ELEMENTS(pVCpu->iem.s.CodeTlb.aEntries), fFlags, &fNeedHeader);
1450 cActionArgs++;
1451 break;
1452
1453 case 'r':
1454 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1455 ValueUnion.PairU32.uFirst, ValueUnion.PairU32.uSecond, fFlags, &fNeedHeader);
1456 fAddressMode = false;
1457 cActionArgs++;
1458 break;
1459
1460 case 's':
1461 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1462 ValueUnion.u32, 1, fFlags, &fNeedHeader);
1463 fAddressMode = false;
1464 cActionArgs++;
1465 break;
1466
1467 case 'v':
1468 fFlags |= IEMR3INFOTLB_F_ONLY_VALID;
1469 break;
1470
1471 case VINF_GETOPT_NOT_OPTION:
1472 if (fAddressMode)
1473 {
1474 uint64_t uAddr;
1475 rc = RTStrToUInt64Full(ValueUnion.psz, 16, &uAddr);
1476 if (RT_SUCCESS(rc) && rc != VWRN_NUMBER_TOO_BIG)
1477 iemR3InfoTlbPrintAddress(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1478 uAddr, fFlags, &fNeedHeader);
1479 else
1480 pHlp->pfnPrintf(pHlp, "error: Invalid or malformed guest address '%s': %Rrc\n", ValueUnion.psz, rc);
1481 }
1482 else
1483 {
1484 uint32_t uSlot;
1485 rc = RTStrToUInt32Full(ValueUnion.psz, 16, &uSlot);
1486 if (RT_SUCCESS(rc) && rc != VWRN_NUMBER_TOO_BIG)
1487 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1488 uSlot, 1, fFlags, &fNeedHeader);
1489 else
1490 pHlp->pfnPrintf(pHlp, "error: Invalid or malformed TLB slot number '%s': %Rrc\n", ValueUnion.psz, rc);
1491 }
1492 cActionArgs++;
1493 break;
1494
1495 case 'h':
1496 pHlp->pfnPrintf(pHlp,
1497 "Usage: info %ctlb [options]\n"
1498 "\n"
1499 "Options:\n"
1500 " -c<n>, --cpu=<n>, --vcpu=<n>\n"
1501 " Selects the CPU which TLBs we're looking at. Default: Caller / 0\n"
1502 " -C,--check\n"
1503 " Check valid entries against guest PTs.\n"
1504 " -A, --all, all\n"
1505 " Display all the TLB entries (default if no other args).\n"
1506 " -a<virt>, --address=<virt>\n"
1507 " Shows the TLB entry for the specified guest virtual address.\n"
1508 " -r<slot:count>, --range=<slot:count>\n"
1509 " Shows the TLB entries for the specified slot range.\n"
1510 " -s<slot>,--slot=<slot>\n"
1511 " Shows the given TLB slot.\n"
1512 " -v,--only-valid\n"
1513 " Only show valid TLB entries (TAG, not phys)\n"
1514 "\n"
1515 "Non-options are interpreted according to the last -a, -r or -s option,\n"
1516 "defaulting to addresses if not preceeded by any of those options.\n"
1517 , fITlb ? 'i' : 'd');
1518 return;
1519
1520 default:
1521 pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
1522 return;
1523 }
1524 }
1525
1526 /*
1527 * If no action taken, we display all (-A) by default.
1528 */
1529 if (!cActionArgs)
1530 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
1531 0, RT_ELEMENTS(pVCpu->iem.s.CodeTlb.aEntries), fFlags, &fNeedHeader);
1532}
1533
1534
1535/**
1536 * @callback_method_impl{FNDBGFINFOARGVINT, itlb}
1537 */
1538static DECLCALLBACK(void) iemR3InfoITlb(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
1539{
1540 return iemR3InfoTlbCommon(pVM, pHlp, cArgs, papszArgs, true /*fITlb*/);
1541}
1542
1543
1544/**
1545 * @callback_method_impl{FNDBGFINFOARGVINT, dtlb}
1546 */
1547static DECLCALLBACK(void) iemR3InfoDTlb(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
1548{
1549 return iemR3InfoTlbCommon(pVM, pHlp, cArgs, papszArgs, false /*fITlb*/);
1550}
1551
1552
1553#ifdef IEM_WITH_TLB_TRACE
1554/**
1555 * @callback_method_impl{FNDBGFINFOARGVINT, tlbtrace}
1556 */
1557static DECLCALLBACK(void) iemR3InfoTlbTrace(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
1558{
1559 /*
1560 * Parse arguments.
1561 */
1562 static RTGETOPTDEF const s_aOptions[] =
1563 {
1564 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
1565 { "--vcpu", 'c', RTGETOPT_REQ_UINT32 },
1566 { "--last", 'l', RTGETOPT_REQ_UINT32 },
1567 { "--limit", 'l', RTGETOPT_REQ_UINT32 },
1568 { "--stop-at-global-flush", 'g', RTGETOPT_REQ_NOTHING },
1569 { "--resolve-rip", 'r', RTGETOPT_REQ_NOTHING },
1570 };
1571
1572 RTGETOPTSTATE State;
1573 int rc = RTGetOptInit(&State, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /*iFirst*/, 0 /*fFlags*/);
1574 AssertRCReturnVoid(rc);
1575
1576 uint32_t cLimit = UINT32_MAX;
1577 bool fStopAtGlobalFlush = false;
1578 bool fResolveRip = false;
1579 PVMCPU const pVCpuCall = VMMGetCpu(pVM);
1580 PVMCPU pVCpu = pVCpuCall;
1581 if (!pVCpu)
1582 pVCpu = VMMGetCpuById(pVM, 0);
1583
1584 RTGETOPTUNION ValueUnion;
1585 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
1586 {
1587 switch (rc)
1588 {
1589 case 'c':
1590 if (ValueUnion.u32 >= pVM->cCpus)
1591 pHlp->pfnPrintf(pHlp, "error: Invalid CPU ID: %u\n", ValueUnion.u32);
1592 else if (!pVCpu || pVCpu->idCpu != ValueUnion.u32)
1593 pVCpu = VMMGetCpuById(pVM, ValueUnion.u32);
1594 break;
1595
1596 case 'l':
1597 cLimit = ValueUnion.u32;
1598 break;
1599
1600 case 'g':
1601 fStopAtGlobalFlush = true;
1602 break;
1603
1604 case 'r':
1605 fResolveRip = true;
1606 break;
1607
1608 case 'h':
1609 pHlp->pfnPrintf(pHlp,
1610 "Usage: info tlbtrace [options] [n]\n"
1611 "\n"
1612 "Options:\n"
1613 " -c<n>, --cpu=<n>, --vcpu=<n>\n"
1614 " Selects the CPU which TLB trace we're looking at. Default: Caller / 0\n"
1615 " [n], -l<n>, --last=<n>\n"
1616 " Limit display to the last N entries. Default: all\n"
1617 " -g, --stop-at-global-flush\n"
1618 " Stop after the first global flush entry.\n"
1619 " -r, --resolve-rip\n"
1620 " Resolve symbols for the flattened RIP addresses.\n"
1621 );
1622 return;
1623
1624 case VINF_GETOPT_NOT_OPTION:
1625 rc = RTStrToUInt32Full(ValueUnion.psz, 0, &cLimit);
1626 if (RT_SUCCESS(rc))
1627 break;
1628 pHlp->pfnPrintf(pHlp, "error: failed to convert '%s' to a number: %Rrc\n", ValueUnion.psz, rc);
1629 return;
1630
1631 default:
1632 pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
1633 return;
1634 }
1635 }
1636
1637 /*
1638 * Get the details.
1639 */
1640 AssertReturnVoid(pVCpu);
1641 Assert(pVCpu->iem.s.cTlbTraceEntriesShift <= 28);
1642 uint32_t idx = pVCpu->iem.s.idxTlbTraceEntry;
1643 uint32_t const cShift = RT_MIN(pVCpu->iem.s.cTlbTraceEntriesShift, 28);
1644 uint32_t const fMask = RT_BIT_32(cShift) - 1;
1645 uint32_t cLeft = RT_MIN(RT_MIN(idx, RT_BIT_32(cShift)), cLimit);
1646 PCIEMTLBTRACEENTRY paEntries = pVCpu->iem.s.paTlbTraceEntries;
1647 if (cLeft && paEntries)
1648 {
1649 /*
1650 * Display the entries.
1651 */
1652 pHlp->pfnPrintf(pHlp, "TLB Trace for CPU %u:\n", pVCpu->idCpu);
1653 while (cLeft-- > 0)
1654 {
1655 PCIEMTLBTRACEENTRY const pCur = &paEntries[--idx & fMask];
1656 const char *pszSymbol = "";
1657 union
1658 {
1659 RTDBGSYMBOL Symbol;
1660 char ach[sizeof(RTDBGSYMBOL) + 32];
1661 } uBuf;
1662 if (fResolveRip)
1663 {
1664 RTGCINTPTR offDisp = 0;
1665 DBGFADDRESS Addr;
1666 rc = DBGFR3AsSymbolByAddr(pVM->pUVM, DBGF_AS_GLOBAL, DBGFR3AddrFromFlat(pVM->pUVM, &Addr, pCur->rip),
1667 RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL
1668 | RTDBGSYMADDR_FLAGS_SKIP_ABS
1669 | RTDBGSYMADDR_FLAGS_SKIP_ABS_IN_DEFERRED,
1670 &offDisp, &uBuf.Symbol, NULL);
1671 if (RT_SUCCESS(rc))
1672 {
1673 /* Add displacement. */
1674 if (offDisp)
1675 {
1676 size_t const cchName = strlen(uBuf.Symbol.szName);
1677 char * const pszEndName = &uBuf.Symbol.szName[cchName];
1678 size_t const cbLeft = sizeof(uBuf) - sizeof(uBuf.Symbol) + sizeof(uBuf.Symbol.szName) - cchName;
1679 if (offDisp > 0)
1680 RTStrPrintf(pszEndName, cbLeft, "+%#1RGv", offDisp);
1681 else
1682 RTStrPrintf(pszEndName, cbLeft, "-%#1RGv", -offDisp);
1683 }
1684
1685 /* Put a space before it. */
1686 AssertCompile(RTASSERT_OFFSET_OF(RTDBGSYMBOL, szName) > 0);
1687 char *pszName = uBuf.Symbol.szName;
1688 *--pszName = ' ';
1689 pszSymbol = pszName;
1690 }
1691 }
1692 static const char *s_apszTlbType[2] = { "code", "data" };
1693 static const char *s_apszScanType[4] = { "skipped", "global", "non-global", "both" };
1694 switch (pCur->enmType)
1695 {
1696 case kIemTlbTraceType_InvlPg:
1697 pHlp->pfnPrintf(pHlp, "%u: %016RX64 invlpg %RGv slot=" IEMTLB_SLOT_FMT "%s\n", idx, pCur->rip,
1698 pCur->u64Param, (uint32_t)IEMTLB_ADDR_TO_EVEN_INDEX(pCur->u64Param), pszSymbol);
1699 break;
1700 case kIemTlbTraceType_EvictSlot:
1701 pHlp->pfnPrintf(pHlp, "%u: %016RX64 evict %s slot=" IEMTLB_SLOT_FMT " %RGv (%#RX64) gcphys=%RGp%s\n",
1702 idx, pCur->rip, s_apszTlbType[pCur->bParam & 1], pCur->u32Param,
1703 (RTGCINTPTR)((pCur->u64Param & ~IEMTLB_REVISION_MASK) << (64 - IEMTLB_TAG_ADDR_WIDTH))
1704 >> (64 - IEMTLB_TAG_ADDR_WIDTH - GUEST_PAGE_SHIFT), pCur->u64Param,
1705 pCur->u64Param2, pszSymbol);
1706 break;
1707 case kIemTlbTraceType_LargeEvictSlot:
1708 pHlp->pfnPrintf(pHlp, "%u: %016RX64 large evict %s slot=" IEMTLB_SLOT_FMT " %RGv (%#RX64) gcphys=%RGp%s\n",
1709 idx, pCur->rip, s_apszTlbType[pCur->bParam & 1], pCur->u32Param,
1710 (RTGCINTPTR)((pCur->u64Param & ~IEMTLB_REVISION_MASK) << (64 - IEMTLB_TAG_ADDR_WIDTH))
1711 >> (64 - IEMTLB_TAG_ADDR_WIDTH - GUEST_PAGE_SHIFT), pCur->u64Param,
1712 pCur->u64Param2, pszSymbol);
1713 break;
1714 case kIemTlbTraceType_LargeScan:
1715 pHlp->pfnPrintf(pHlp, "%u: %016RX64 large scan %s %s%s\n", idx, pCur->rip, s_apszTlbType[pCur->bParam & 1],
1716 s_apszScanType[pCur->u32Param & 3], pszSymbol);
1717 break;
1718
1719 case kIemTlbTraceType_Flush:
1720 pHlp->pfnPrintf(pHlp, "%u: %016RX64 flush %s rev=%#RX64%s\n", idx, pCur->rip,
1721 s_apszTlbType[pCur->bParam & 1], pCur->u64Param, pszSymbol);
1722 break;
1723 case kIemTlbTraceType_FlushGlobal:
1724 pHlp->pfnPrintf(pHlp, "%u: %016RX64 flush %s rev=%#RX64 grev=%#RX64%s\n", idx, pCur->rip,
1725 s_apszTlbType[pCur->bParam & 1], pCur->u64Param, pCur->u64Param2, pszSymbol);
1726 if (fStopAtGlobalFlush)
1727 return;
1728 break;
1729 case kIemTlbTraceType_Load:
1730 case kIemTlbTraceType_LoadGlobal:
1731 pHlp->pfnPrintf(pHlp, "%u: %016RX64 %cload %s %RGv slot=" IEMTLB_SLOT_FMT " gcphys=%RGp fTlb=%#RX32%s\n",
1732 idx, pCur->rip,
1733 pCur->enmType == kIemTlbTraceType_LoadGlobal ? 'g' : 'l', s_apszTlbType[pCur->bParam & 1],
1734 pCur->u64Param,
1735 (uint32_t)IEMTLB_ADDR_TO_EVEN_INDEX(pCur->u64Param)
1736 | (pCur->enmType == kIemTlbTraceType_LoadGlobal),
1737 (RTGCPTR)pCur->u64Param2, pCur->u32Param, pszSymbol);
1738 break;
1739
1740 case kIemTlbTraceType_Load_Cr0:
1741 pHlp->pfnPrintf(pHlp, "%u: %016RX64 load cr0 %08RX64 (was %08RX64)%s\n",
1742 idx, pCur->rip, pCur->u64Param, pCur->u64Param2, pszSymbol);
1743 break;
1744 case kIemTlbTraceType_Load_Cr3:
1745 pHlp->pfnPrintf(pHlp, "%u: %016RX64 load cr3 %016RX64 (was %016RX64)%s\n",
1746 idx, pCur->rip, pCur->u64Param, pCur->u64Param2, pszSymbol);
1747 break;
1748 case kIemTlbTraceType_Load_Cr4:
1749 pHlp->pfnPrintf(pHlp, "%u: %016RX64 load cr4 %08RX64 (was %08RX64)%s\n",
1750 idx, pCur->rip, pCur->u64Param, pCur->u64Param2, pszSymbol);
1751 break;
1752 case kIemTlbTraceType_Load_Efer:
1753 pHlp->pfnPrintf(pHlp, "%u: %016RX64 load efer %016RX64 (was %016RX64)%s\n",
1754 idx, pCur->rip, pCur->u64Param, pCur->u64Param2, pszSymbol);
1755 break;
1756
1757 case kIemTlbTraceType_Irq:
1758 pHlp->pfnPrintf(pHlp, "%u: %016RX64 irq %#04x flags=%#x eflboth=%#RX64%s\n",
1759 idx, pCur->rip, pCur->bParam, pCur->u32Param,
1760 pCur->u64Param & ((RT_BIT_64(CPUMX86EFLAGS_HW_BITS) - 1) | CPUMX86EFLAGS_INT_MASK_64),
1761 pszSymbol);
1762 break;
1763 case kIemTlbTraceType_Xcpt:
1764 if (pCur->u32Param & IEM_XCPT_FLAGS_CR2)
1765 pHlp->pfnPrintf(pHlp, "%u: %016RX64 xcpt %#04x flags=%#x errcd=%#x cr2=%RX64%s\n",
1766 idx, pCur->rip, pCur->bParam, pCur->u32Param, pCur->u64Param, pCur->u64Param2, pszSymbol);
1767 else if (pCur->u32Param & IEM_XCPT_FLAGS_ERR)
1768 pHlp->pfnPrintf(pHlp, "%u: %016RX64 xcpt %#04x flags=%#x errcd=%#x%s\n",
1769 idx, pCur->rip, pCur->bParam, pCur->u32Param, pCur->u64Param, pszSymbol);
1770 else
1771 pHlp->pfnPrintf(pHlp, "%u: %016RX64 xcpt %#04x flags=%#x%s\n",
1772 idx, pCur->rip, pCur->bParam, pCur->u32Param, pszSymbol);
1773 break;
1774 case kIemTlbTraceType_IRet:
1775 pHlp->pfnPrintf(pHlp, "%u: %016RX64 iret cs:rip=%04x:%016RX64 efl=%08RX32%s\n",
1776 idx, pCur->rip, pCur->u32Param, pCur->u64Param, (uint32_t)pCur->u64Param2, pszSymbol);
1777 break;
1778
1779 case kIemTlbTraceType_Tb_Compile:
1780 pHlp->pfnPrintf(pHlp, "%u: %016RX64 tb comp GCPhysPc=%012RX64%s\n",
1781 idx, pCur->rip, pCur->u64Param, pszSymbol);
1782 break;
1783 case kIemTlbTraceType_Tb_Exec_Threaded:
1784 pHlp->pfnPrintf(pHlp, "%u: %016RX64 tb thrd GCPhysPc=%012RX64 tb=%p used=%u%s\n",
1785 idx, pCur->rip, pCur->u64Param, (uintptr_t)pCur->u64Param2, pCur->u32Param, pszSymbol);
1786 break;
1787 case kIemTlbTraceType_Tb_Exec_Native:
1788 pHlp->pfnPrintf(pHlp, "%u: %016RX64 tb n8ve GCPhysPc=%012RX64 tb=%p used=%u%s\n",
1789 idx, pCur->rip, pCur->u64Param, (uintptr_t)pCur->u64Param2, pCur->u32Param, pszSymbol);
1790 break;
1791
1792 case kIemTlbTraceType_User0:
1793 pHlp->pfnPrintf(pHlp, "%u: %016RX64 user0 %016RX64 %016RX64 %08RX32 %02RX8%s\n",
1794 idx, pCur->rip, pCur->u64Param, pCur->u64Param2, pCur->u32Param, pCur->bParam, pszSymbol);
1795 break;
1796 case kIemTlbTraceType_User1:
1797 pHlp->pfnPrintf(pHlp, "%u: %016RX64 user1 %016RX64 %016RX64 %08RX32 %02RX8%s\n",
1798 idx, pCur->rip, pCur->u64Param, pCur->u64Param2, pCur->u32Param, pCur->bParam, pszSymbol);
1799 break;
1800 case kIemTlbTraceType_User2:
1801 pHlp->pfnPrintf(pHlp, "%u: %016RX64 user2 %016RX64 %016RX64 %08RX32 %02RX8%s\n",
1802 idx, pCur->rip, pCur->u64Param, pCur->u64Param2, pCur->u32Param, pCur->bParam, pszSymbol);
1803 break;
1804 case kIemTlbTraceType_User3:
1805 pHlp->pfnPrintf(pHlp, "%u: %016RX64 user3 %016RX64 %016RX64 %08RX32 %02RX8%s\n",
1806 idx, pCur->rip, pCur->u64Param, pCur->u64Param2, pCur->u32Param, pCur->bParam, pszSymbol);
1807 break;
1808
1809 case kIemTlbTraceType_Invalid:
1810 pHlp->pfnPrintf(pHlp, "%u: Invalid!\n");
1811 break;
1812 }
1813 }
1814 }
1815 else
1816 pHlp->pfnPrintf(pHlp, "No trace entries to display\n");
1817}
1818#endif /* IEM_WITH_TLB_TRACE */
1819
1820#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
1821
1822/**
1823 * Get get compile time flat PC for the TB.
1824 */
1825DECL_FORCE_INLINE(RTGCPTR) iemR3GetTbFlatPc(PCIEMTB pTb)
1826{
1827#ifdef IEMNATIVE_WITH_TB_DEBUG_INFO
1828 if (pTb->fFlags & IEMTB_F_TYPE_NATIVE)
1829 {
1830 PCIEMTBDBG const pDbgInfo = pTb->pDbgInfo;
1831 return pDbgInfo ? pDbgInfo->FlatPc : RTGCPTR_MAX;
1832 }
1833#endif
1834 return pTb->FlatPc;
1835}
1836
1837
1838/**
1839 * @callback_method_impl{FNDBGFINFOARGVINT, tb}
1840 */
1841static DECLCALLBACK(void) iemR3InfoTb(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
1842{
1843 /*
1844 * Parse arguments.
1845 */
1846 static RTGETOPTDEF const s_aOptions[] =
1847 {
1848 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
1849 { "--vcpu", 'c', RTGETOPT_REQ_UINT32 },
1850 { "--addr", 'a', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1851 { "--address", 'a', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1852 { "--phys", 'p', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1853 { "--physical", 'p', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1854 { "--phys-addr", 'p', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1855 { "--phys-address", 'p', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1856 { "--physical-address", 'p', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
1857 { "--flags", 'f', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX },
1858 { "--tb", 't', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX },
1859 { "--tb-id", 't', RTGETOPT_REQ_UINT32 },
1860 };
1861
1862 RTGETOPTSTATE State;
1863 int rc = RTGetOptInit(&State, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /*iFirst*/, 0 /*fFlags*/);
1864 AssertRCReturnVoid(rc);
1865
1866 PVMCPU const pVCpuThis = VMMGetCpu(pVM);
1867 PVMCPU pVCpu = pVCpuThis ? pVCpuThis : VMMGetCpuById(pVM, 0);
1868 RTGCPHYS GCPhysPc = NIL_RTGCPHYS;
1869 RTGCPHYS GCVirt = NIL_RTGCPTR;
1870 uint32_t fFlags = UINT32_MAX;
1871 uint32_t idTb = UINT32_MAX;
1872
1873 RTGETOPTUNION ValueUnion;
1874 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
1875 {
1876 switch (rc)
1877 {
1878 case 'c':
1879 if (ValueUnion.u32 >= pVM->cCpus)
1880 pHlp->pfnPrintf(pHlp, "error: Invalid CPU ID: %u\n", ValueUnion.u32);
1881 else if (!pVCpu || pVCpu->idCpu != ValueUnion.u32)
1882 pVCpu = VMMGetCpuById(pVM, ValueUnion.u32);
1883 break;
1884
1885 case 'a':
1886 GCVirt = ValueUnion.u64;
1887 GCPhysPc = NIL_RTGCPHYS;
1888 idTb = UINT32_MAX;
1889 break;
1890
1891 case 'p':
1892 GCVirt = NIL_RTGCPHYS;
1893 GCPhysPc = ValueUnion.u64;
1894 idTb = UINT32_MAX;
1895 break;
1896
1897 case 'f':
1898 fFlags = ValueUnion.u32;
1899 break;
1900
1901 case 't':
1902 GCVirt = NIL_RTGCPHYS;
1903 GCPhysPc = NIL_RTGCPHYS;
1904 idTb = ValueUnion.u32;
1905 break;
1906
1907 case VINF_GETOPT_NOT_OPTION:
1908 {
1909 if ( (ValueUnion.psz[0] == 'T' || ValueUnion.psz[0] == 't')
1910 && (ValueUnion.psz[1] == 'B' || ValueUnion.psz[1] == 'b')
1911 && ValueUnion.psz[2] == '#')
1912 {
1913 rc = RTStrToUInt32Full(&ValueUnion.psz[3], 0, &idTb);
1914 if (RT_SUCCESS(rc))
1915 {
1916 GCVirt = NIL_RTGCPHYS;
1917 GCPhysPc = NIL_RTGCPHYS;
1918 break;
1919 }
1920 pHlp->pfnPrintf(pHlp, "error: failed to convert '%s' to TD ID: %Rrc\n", ValueUnion.psz, rc);
1921 }
1922 else
1923 pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
1924 return;
1925 }
1926
1927 case 'h':
1928 pHlp->pfnPrintf(pHlp,
1929 "Usage: info tb [options]\n"
1930 "\n"
1931 "Options:\n"
1932 " -c<n>, --cpu=<n>, --vcpu=<n>\n"
1933 " Selects the CPU which TBs we're looking at. Default: Caller / 0\n"
1934 " -a<virt>, --address=<virt>\n"
1935 " Shows the TB for the specified guest virtual address.\n"
1936 " -p<phys>, --phys=<phys>, --phys-addr=<phys>\n"
1937 " Shows the TB for the specified guest physical address.\n"
1938 " -t<id>, --tb=<id>, --tb-id=<id>, TD#<id>\n"
1939 " Show the TB specified by the identifier/number (from tbtop).\n"
1940 " -f<flags>,--flags=<flags>\n"
1941 " The TB flags value (hex) to use when looking up the TB.\n"
1942 "\n"
1943 "The default is to use CS:RIP and derive flags from the CPU mode.\n");
1944 return;
1945
1946 default:
1947 pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
1948 return;
1949 }
1950 }
1951
1952 /* Currently, only do work on the same EMT. */
1953 if (pVCpu != pVCpuThis)
1954 {
1955 pHlp->pfnPrintf(pHlp, "TODO: Cross EMT calling not supported yet: targeting %u, caller on %d\n",
1956 pVCpu->idCpu, pVCpuThis ? (int)pVCpuThis->idCpu : -1);
1957 return;
1958 }
1959
1960 /*
1961 * Defaults.
1962 */
1963 if (GCPhysPc == NIL_RTGCPHYS && idTb == UINT32_MAX)
1964 {
1965 if (GCVirt == NIL_RTGCPTR)
1966 GCVirt = CPUMGetGuestFlatPC(pVCpu);
1967 rc = PGMPhysGCPtr2GCPhys(pVCpu, GCVirt, &GCPhysPc);
1968 if (RT_FAILURE(rc))
1969 {
1970 pHlp->pfnPrintf(pHlp, "Failed to convert %%%RGv to an guest physical address: %Rrc\n", GCVirt, rc);
1971 return;
1972 }
1973 }
1974 if (fFlags == UINT32_MAX && idTb == UINT32_MAX)
1975 {
1976 /* Note! This is duplicating code in IEMAllThrdRecompiler. */
1977 fFlags = iemCalcExecFlags(pVCpu);
1978 if (pVM->cCpus == 1)
1979 fFlags |= IEM_F_X86_DISREGARD_LOCK;
1980 if (CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx))
1981 fFlags |= IEMTB_F_INHIBIT_SHADOW;
1982 if (CPUMAreInterruptsInhibitedByNmiEx(&pVCpu->cpum.GstCtx))
1983 fFlags |= IEMTB_F_INHIBIT_NMI;
1984 if ((IEM_F_MODE_CPUMODE_MASK & fFlags) != IEMMODE_64BIT)
1985 {
1986 int64_t const offFromLim = (int64_t)pVCpu->cpum.GstCtx.cs.u32Limit - (int64_t)pVCpu->cpum.GstCtx.eip;
1987 if (offFromLim < X86_PAGE_SIZE + 16 - (int32_t)(pVCpu->cpum.GstCtx.cs.u64Base & GUEST_PAGE_OFFSET_MASK))
1988 fFlags |= IEMTB_F_CS_LIM_CHECKS;
1989 }
1990 }
1991
1992 PCIEMTB pTb;
1993 if (idTb == UINT32_MAX)
1994 {
1995 /*
1996 * Do the lookup...
1997 *
1998 * Note! This is also duplicating code in IEMAllThrdRecompiler. We don't
1999 * have much choice since we don't want to increase use counters and
2000 * trigger native recompilation.
2001 */
2002 fFlags &= IEMTB_F_KEY_MASK;
2003 IEMTBCACHE const * const pTbCache = pVCpu->iem.s.pTbCacheR3;
2004 uint32_t const idxHash = IEMTBCACHE_HASH(pTbCache, fFlags, GCPhysPc);
2005 pTb = IEMTBCACHE_PTR_GET_TB(pTbCache->apHash[idxHash]);
2006 while (pTb)
2007 {
2008 if (pTb->GCPhysPc == GCPhysPc)
2009 {
2010 if ((pTb->fFlags & IEMTB_F_KEY_MASK) == fFlags)
2011 {
2012 /// @todo if (pTb->x86.fAttr == (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u)
2013 break;
2014 }
2015 }
2016 pTb = pTb->pNext;
2017 }
2018 if (!pTb)
2019 pHlp->pfnPrintf(pHlp, "PC=%RGp fFlags=%#x - no TB found on #%u\n", GCPhysPc, fFlags, pVCpu->idCpu);
2020 }
2021 else
2022 {
2023 /*
2024 * Use the TB ID for indexing.
2025 */
2026 pTb = NULL;
2027 PIEMTBALLOCATOR const pTbAllocator = pVCpu->iem.s.pTbAllocatorR3;
2028 if (pTbAllocator)
2029 {
2030 size_t const idxTbChunk = idTb / pTbAllocator->cTbsPerChunk;
2031 size_t const idxTbInChunk = idTb % pTbAllocator->cTbsPerChunk;
2032 if (idxTbChunk < pTbAllocator->cAllocatedChunks)
2033 pTb = &pTbAllocator->aChunks[idxTbChunk].paTbs[idxTbInChunk];
2034 else
2035 pHlp->pfnPrintf(pHlp, "Invalid TB ID: %u (%#x)\n", idTb, idTb);
2036 }
2037 }
2038
2039 if (pTb)
2040 {
2041 /*
2042 * Disassemble according to type.
2043 */
2044 size_t const idxTbChunk = pTb->idxAllocChunk;
2045 size_t const idxTbNo = (pTb - &pVCpu->iem.s.pTbAllocatorR3->aChunks[idxTbChunk].paTbs[0])
2046 + idxTbChunk * pVCpu->iem.s.pTbAllocatorR3->cTbsPerChunk;
2047 switch (pTb->fFlags & IEMTB_F_TYPE_MASK)
2048 {
2049# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
2050 case IEMTB_F_TYPE_NATIVE:
2051 pHlp->pfnPrintf(pHlp, "PC=%RGp (%%%RGv) fFlags=%#x on #%u: TB#%#zx/%p - native\n",
2052 GCPhysPc, iemR3GetTbFlatPc(pTb), fFlags, pVCpu->idCpu, idxTbNo, pTb);
2053 iemNativeDisassembleTb(pVCpu, pTb, pHlp);
2054 break;
2055# endif
2056
2057 case IEMTB_F_TYPE_THREADED:
2058 pHlp->pfnPrintf(pHlp, "PC=%RGp (%%%RGv) fFlags=%#x on #%u: TB#%#zx/%p - threaded\n",
2059 GCPhysPc, pTb->FlatPc, fFlags, pVCpu->idCpu, idxTbNo, pTb);
2060 iemThreadedDisassembleTb(pTb, pHlp);
2061 break;
2062
2063 default:
2064 pHlp->pfnPrintf(pHlp, "PC=%RGp (%%%RGv) fFlags=%#x on #%u: TB#%#zx/%p - ??? %#x\n",
2065 GCPhysPc, pTb->FlatPc, fFlags, pVCpu->idCpu, idxTbNo, pTb, pTb->fFlags);
2066 break;
2067 }
2068 }
2069}
2070
2071
2072/**
2073 * @callback_method_impl{FNDBGFINFOARGVINT, tbtop}
2074 */
2075static DECLCALLBACK(void) iemR3InfoTbTop(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
2076{
2077 /*
2078 * Parse arguments.
2079 */
2080 static RTGETOPTDEF const s_aOptions[] =
2081 {
2082 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
2083 { "--vcpu", 'c', RTGETOPT_REQ_UINT32 },
2084 { "--dis", 'd', RTGETOPT_REQ_NOTHING },
2085 { "--disas", 'd', RTGETOPT_REQ_NOTHING },
2086 { "--disasm", 'd', RTGETOPT_REQ_NOTHING },
2087 { "--disassemble", 'd', RTGETOPT_REQ_NOTHING },
2088 { "--no-dis", 'D', RTGETOPT_REQ_NOTHING },
2089 { "--no-disas", 'D', RTGETOPT_REQ_NOTHING },
2090 { "--no-disasm", 'D', RTGETOPT_REQ_NOTHING },
2091 { "--no-disassemble", 'D', RTGETOPT_REQ_NOTHING },
2092 { "--most-freq", 'f', RTGETOPT_REQ_NOTHING },
2093 { "--most-frequent", 'f', RTGETOPT_REQ_NOTHING },
2094 { "--most-frequently", 'f', RTGETOPT_REQ_NOTHING },
2095 { "--most-frequently-used", 'f', RTGETOPT_REQ_NOTHING },
2096 { "--most-recent", 'r', RTGETOPT_REQ_NOTHING },
2097 { "--most-recently", 'r', RTGETOPT_REQ_NOTHING },
2098 { "--most-recently-used", 'r', RTGETOPT_REQ_NOTHING },
2099 { "--count", 'n', RTGETOPT_REQ_UINT32 },
2100 };
2101
2102 RTGETOPTSTATE State;
2103 int rc = RTGetOptInit(&State, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /*iFirst*/, 0 /*fFlags*/);
2104 AssertRCReturnVoid(rc);
2105
2106 PVMCPU const pVCpuThis = VMMGetCpu(pVM);
2107 PVMCPU pVCpu = pVCpuThis ? pVCpuThis : VMMGetCpuById(pVM, 0);
2108 enum { kTbTop_MostFrequentlyUsed, kTbTop_MostRececentlyUsed }
2109 enmTop = kTbTop_MostFrequentlyUsed;
2110 bool fDisassemble = false;
2111 uint32_t const cTopDefault = 64;
2112 uint32_t const cTopMin = 1;
2113 uint32_t const cTopMax = 1024;
2114 uint32_t cTop = cTopDefault;
2115
2116 RTGETOPTUNION ValueUnion;
2117 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
2118 {
2119 switch (rc)
2120 {
2121 case 'c':
2122 if (ValueUnion.u32 >= pVM->cCpus)
2123 pHlp->pfnPrintf(pHlp, "error: Invalid CPU ID: %u\n", ValueUnion.u32);
2124 else if (!pVCpu || pVCpu->idCpu != ValueUnion.u32)
2125 pVCpu = VMMGetCpuById(pVM, ValueUnion.u32);
2126 break;
2127
2128 case 'd':
2129 fDisassemble = true;
2130 break;
2131
2132 case 'D':
2133 fDisassemble = true;
2134 break;
2135
2136 case 'f':
2137 enmTop = kTbTop_MostFrequentlyUsed;
2138 break;
2139
2140 case 'r':
2141 enmTop = kTbTop_MostRececentlyUsed;
2142 break;
2143
2144 case VINF_GETOPT_NOT_OPTION:
2145 rc = RTStrToUInt32Full(ValueUnion.psz, 0, &cTop);
2146 if (RT_FAILURE(rc))
2147 {
2148 pHlp->pfnPrintf(pHlp, "error: failed to convert '%s' to a number: %Rrc\n", ValueUnion.psz, rc);
2149 return;
2150 }
2151 ValueUnion.u32 = cTop;
2152 RT_FALL_THROUGH();
2153 case 'n':
2154 if (!ValueUnion.u32)
2155 cTop = cTopDefault;
2156 else
2157 {
2158 cTop = RT_MAX(RT_MIN(ValueUnion.u32, cTopMax), cTopMin);
2159 if (cTop != ValueUnion.u32)
2160 pHlp->pfnPrintf(pHlp, "warning: adjusted %u to %u (valid range: [%u..%u], 0 for default (%d))",
2161 ValueUnion.u32, cTop, cTopMin, cTopMax, cTopDefault);
2162 }
2163 break;
2164
2165 case 'h':
2166 pHlp->pfnPrintf(pHlp,
2167 "Usage: info tbtop [options]\n"
2168 "\n"
2169 "Options:\n"
2170 " -c<n>, --cpu=<n>, --vcpu=<n>\n"
2171 " Selects the CPU which TBs we're looking at. Default: Caller / 0\n"
2172 " -d, --dis[as[m]], --disassemble\n"
2173 " Show full TB disassembly.\n"
2174 " -D, --no-dis[as[m]], --no-disassemble\n"
2175 " Do not show TB diassembly. The default.\n"
2176 " -f, --most-freq[ent[ly[-used]]]\n"
2177 " Shows the most frequently used TBs (IEMTB::cUsed). The default.\n"
2178 " -r, --most-recent[ly[-used]]\n"
2179 " Shows the most recently used TBs (IEMTB::msLastUsed).\n"
2180 " -n<num>, --count=<num>\n"
2181 " The number of TBs to display. Default: %u\n"
2182 " This is also what non-option arguments will be taken as.\n"
2183 , cTopDefault);
2184 return;
2185
2186 default:
2187 pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
2188 return;
2189 }
2190 }
2191
2192 /* Currently, only do work on the same EMT. */
2193 if (pVCpu != pVCpuThis)
2194 {
2195 pHlp->pfnPrintf(pHlp, "TODO: Cross EMT calling not supported yet: targeting %u, caller on %d\n",
2196 pVCpu->idCpu, pVCpuThis ? (int)pVCpuThis->idCpu : -1);
2197 return;
2198 }
2199
2200 /*
2201 * Collect the data by scanning the TB allocation map.
2202 */
2203 struct IEMTBTOPENTRY
2204 {
2205 /** Pointer to the translation block. */
2206 PCIEMTB pTb;
2207 /** The sorting key. */
2208 uint64_t uSortKey;
2209 } aTop[cTopMax] = { { NULL, 0 }, };
2210 uint32_t cValid = 0;
2211 PIEMTBALLOCATOR pTbAllocator = pVCpu->iem.s.pTbAllocatorR3;
2212 if (pTbAllocator)
2213 {
2214 uint32_t const cTbsPerChunk = pTbAllocator->cTbsPerChunk;
2215 for (uint32_t iChunk = 0; iChunk < pTbAllocator->cAllocatedChunks; iChunk++)
2216 {
2217 for (uint32_t iTb = 0; iTb < cTbsPerChunk; iTb++)
2218 {
2219 PCIEMTB const pTb = &pTbAllocator->aChunks[iChunk].paTbs[iTb];
2220 AssertContinue(pTb);
2221 if (pTb->fFlags & IEMTB_F_TYPE_MASK)
2222 {
2223 /* Extract and compose the sort key. */
2224 uint64_t const uSortKey = enmTop == kTbTop_MostFrequentlyUsed
2225 ? RT_MAKE_U64(pTb->msLastUsed, pTb->cUsed)
2226 : RT_MAKE_U64(pTb->cUsed, pTb->msLastUsed);
2227
2228 /*
2229 * Discard the key if it's smaller than the smallest in the table when it is full.
2230 */
2231 if ( cValid >= cTop
2232 && uSortKey <= aTop[cTop - 1].uSortKey)
2233 { /* discard it */ }
2234 else
2235 {
2236 /*
2237 * Do binary search to find the insert location
2238 */
2239 uint32_t idx;
2240 if (cValid > 0)
2241 {
2242 uint32_t idxEnd = cValid;
2243 uint32_t idxStart = 0;
2244 idx = cValid / 2;
2245 for (;;)
2246 {
2247 if (uSortKey > aTop[idx].uSortKey)
2248 {
2249 if (idx > idxStart)
2250 idxEnd = idx;
2251 else
2252 break;
2253 }
2254 else if (uSortKey < aTop[idx].uSortKey)
2255 {
2256 idx += 1;
2257 if (idx < idxEnd)
2258 idxStart = idx;
2259 else
2260 break;
2261 }
2262 else
2263 {
2264 do
2265 idx++;
2266 while (idx < cValid && uSortKey == aTop[idx].uSortKey);
2267 break;
2268 }
2269 idx = idxStart + (idxEnd - idxStart) / 2;
2270 }
2271 AssertContinue(idx < RT_ELEMENTS(aTop));
2272
2273 /*
2274 * Shift entries as needed.
2275 */
2276 if (cValid >= cTop)
2277 {
2278 if (idx != cTop - 1U)
2279 memmove(&aTop[idx + 1], &aTop[idx], (cTop - idx - 1) * sizeof(aTop[0]));
2280 }
2281 else
2282 {
2283 if (idx != cValid)
2284 memmove(&aTop[idx + 1], &aTop[idx], (cValid - idx) * sizeof(aTop[0]));
2285 cValid++;
2286 }
2287 }
2288 else
2289 {
2290 /* Special case: The first insertion. */
2291 cValid = 1;
2292 idx = 0;
2293 }
2294
2295 /*
2296 * Fill in the new entry.
2297 */
2298 aTop[idx].uSortKey = uSortKey;
2299 aTop[idx].pTb = pTb;
2300 }
2301 }
2302 }
2303 }
2304 }
2305
2306 /*
2307 * Display the result.
2308 */
2309 if (cTop > cValid)
2310 cTop = cValid;
2311 pHlp->pfnPrintf(pHlp, "Displaying the top %u TBs for CPU #%u ordered by %s:\n",
2312 cTop, pVCpu->idCpu, enmTop == kTbTop_MostFrequentlyUsed ? "cUsed" : "msLastUsed");
2313 if (fDisassemble)
2314 pHlp->pfnPrintf(pHlp, "================================================================================\n");
2315
2316 for (uint32_t idx = 0; idx < cTop; idx++)
2317 {
2318 if (fDisassemble && idx)
2319 pHlp->pfnPrintf(pHlp, "\n------------------------------- %u -------------------------------\n", idx);
2320
2321 PCIEMTB const pTb = aTop[idx].pTb;
2322 size_t const idxTbChunk = pTb->idxAllocChunk;
2323 Assert(idxTbChunk < pTbAllocator->cAllocatedChunks);
2324 size_t const idxTbNo = (pTb - &pTbAllocator->aChunks[idxTbChunk].paTbs[0])
2325 + idxTbChunk * pTbAllocator->cTbsPerChunk;
2326 switch (pTb->fFlags & IEMTB_F_TYPE_MASK)
2327 {
2328# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
2329 case IEMTB_F_TYPE_NATIVE:
2330 pHlp->pfnPrintf(pHlp, "TB#%#zx: PC=%RGp (%%%RGv) cUsed=%u msLastUsed=%u fFlags=%#010x - native\n",
2331 idxTbNo, pTb->GCPhysPc, iemR3GetTbFlatPc(pTb), pTb->cUsed, pTb->msLastUsed, pTb->fFlags);
2332 if (fDisassemble)
2333 iemNativeDisassembleTb(pVCpu, pTb, pHlp);
2334 break;
2335# endif
2336
2337 case IEMTB_F_TYPE_THREADED:
2338 pHlp->pfnPrintf(pHlp, "TB#%#zx: PC=%RGp (%%%RGv) cUsed=%u msLastUsed=%u fFlags=%#010x - threaded\n",
2339 idxTbNo, pTb->GCPhysPc, pTb->FlatPc, pTb->cUsed, pTb->msLastUsed, pTb->fFlags);
2340 if (fDisassemble)
2341 iemThreadedDisassembleTb(pTb, pHlp);
2342 break;
2343
2344 default:
2345 pHlp->pfnPrintf(pHlp, "TB#%#zx: PC=%RGp (%%%RGv) cUsed=%u msLastUsed=%u fFlags=%#010x - ???\n",
2346 idxTbNo, pTb->GCPhysPc, pTb->FlatPc, pTb->cUsed, pTb->msLastUsed, pTb->fFlags);
2347 break;
2348 }
2349 }
2350}
2351
2352#endif /* VBOX_WITH_IEM_RECOMPILER && !VBOX_VMM_TARGET_ARMV8 */
2353
2354
2355#ifdef VBOX_WITH_DEBUGGER
2356
2357/** @callback_method_impl{FNDBGCCMD,
2358 * Implements the '.alliem' command. }
2359 */
2360static DECLCALLBACK(int) iemR3DbgFlushTlbs(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
2361{
2362 VMCPUID idCpu = DBGCCmdHlpGetCurrentCpu(pCmdHlp);
2363 PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, idCpu);
2364 if (pVCpu)
2365 {
2366 VMR3ReqPriorityCallVoidWaitU(pUVM, idCpu, (PFNRT)IEMTlbInvalidateAllGlobal, 1, pVCpu);
2367 return VINF_SUCCESS;
2368 }
2369 RT_NOREF(paArgs, cArgs);
2370 return DBGCCmdHlpFail(pCmdHlp, pCmd, "failed to get the PVMCPU for the current CPU");
2371}
2372
2373
2374/**
2375 * Called by IEMR3Init to register debugger commands.
2376 */
2377static void iemR3RegisterDebuggerCommands(void)
2378{
2379 /*
2380 * Register debugger commands.
2381 */
2382 static DBGCCMD const s_aCmds[] =
2383 {
2384 {
2385 /* .pszCmd = */ "iemflushtlb",
2386 /* .cArgsMin = */ 0,
2387 /* .cArgsMax = */ 0,
2388 /* .paArgDescs = */ NULL,
2389 /* .cArgDescs = */ 0,
2390 /* .fFlags = */ 0,
2391 /* .pfnHandler = */ iemR3DbgFlushTlbs,
2392 /* .pszSyntax = */ "",
2393 /* .pszDescription = */ "Flushed the code and data TLBs"
2394 },
2395 };
2396
2397 int rc = DBGCRegisterCommands(&s_aCmds[0], RT_ELEMENTS(s_aCmds));
2398 AssertLogRelRC(rc);
2399}
2400
2401#endif /* VBOX_WITH_DEBUGGER */
2402
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