VirtualBox

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

Last change on this file since 95395 was 95308, checked in by vboxsync, 3 years ago

VMM/IEM: Implemented ANDN, BEXTR, SHLX, SARX, SHRX, RORX, TZCNT, and LZCNT. Fixed long-mod bug in 32-bit version of BSR and BSF (would clear the upper 32 bits of the destination register when ZF=1). bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.2 KB
Line 
1/* $Id: IEMR3.cpp 95308 2022-06-19 20:40:26Z vboxsync $ */
2/** @file
3 * IEM - Interpreted Execution Manager.
4 */
5
6/*
7 * Copyright (C) 2011-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_EM
23#include <VBox/vmm/iem.h>
24#include <VBox/vmm/cpum.h>
25#include <VBox/vmm/dbgf.h>
26#include <VBox/vmm/mm.h>
27#include "IEMInternal.h"
28#include <VBox/vmm/vm.h>
29#include <VBox/err.h>
30
31#include <iprt/assert.h>
32#include <iprt/getopt.h>
33#include <iprt/string.h>
34
35
36/*********************************************************************************************************************************
37* Internal Functions *
38*********************************************************************************************************************************/
39static FNDBGFINFOARGVINT iemR3InfoITlb;
40static FNDBGFINFOARGVINT iemR3InfoDTlb;
41
42
43static const char *iemGetTargetCpuName(uint32_t enmTargetCpu)
44{
45 switch (enmTargetCpu)
46 {
47#define CASE_RET_STR(enmValue) case enmValue: return #enmValue + (sizeof("IEMTARGETCPU_") - 1)
48 CASE_RET_STR(IEMTARGETCPU_8086);
49 CASE_RET_STR(IEMTARGETCPU_V20);
50 CASE_RET_STR(IEMTARGETCPU_186);
51 CASE_RET_STR(IEMTARGETCPU_286);
52 CASE_RET_STR(IEMTARGETCPU_386);
53 CASE_RET_STR(IEMTARGETCPU_486);
54 CASE_RET_STR(IEMTARGETCPU_PENTIUM);
55 CASE_RET_STR(IEMTARGETCPU_PPRO);
56 CASE_RET_STR(IEMTARGETCPU_CURRENT);
57#undef CASE_RET_STR
58 default: return "Unknown";
59 }
60}
61
62
63/**
64 * Initializes the interpreted execution manager.
65 *
66 * This must be called after CPUM as we're quering information from CPUM about
67 * the guest and host CPUs.
68 *
69 * @returns VBox status code.
70 * @param pVM The cross context VM structure.
71 */
72VMMR3DECL(int) IEMR3Init(PVM pVM)
73{
74 uint64_t const uInitialTlbRevision = UINT64_C(0) - (IEMTLB_REVISION_INCR * 200U);
75 uint64_t const uInitialTlbPhysRev = UINT64_C(0) - (IEMTLB_PHYS_REV_INCR * 100U);
76
77 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
78 {
79 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
80 AssertCompile(sizeof(pVCpu->iem.s) <= sizeof(pVCpu->iem.padding)); /* (tstVMStruct can't do it's job w/o instruction stats) */
81
82 pVCpu->iem.s.CodeTlb.uTlbRevision = pVCpu->iem.s.DataTlb.uTlbRevision = uInitialTlbRevision;
83 pVCpu->iem.s.CodeTlb.uTlbPhysRev = pVCpu->iem.s.DataTlb.uTlbPhysRev = uInitialTlbPhysRev;
84
85 STAMR3RegisterF(pVM, &pVCpu->iem.s.cInstructions, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
86 "Instructions interpreted", "/IEM/CPU%u/cInstructions", idCpu);
87 STAMR3RegisterF(pVM, &pVCpu->iem.s.cLongJumps, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
88 "Number of longjmp calls", "/IEM/CPU%u/cLongJumps", idCpu);
89 STAMR3RegisterF(pVM, &pVCpu->iem.s.cPotentialExits, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
90 "Potential exits", "/IEM/CPU%u/cPotentialExits", idCpu);
91 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetAspectNotImplemented, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
92 "VERR_IEM_ASPECT_NOT_IMPLEMENTED", "/IEM/CPU%u/cRetAspectNotImplemented", idCpu);
93 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetInstrNotImplemented, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
94 "VERR_IEM_INSTR_NOT_IMPLEMENTED", "/IEM/CPU%u/cRetInstrNotImplemented", idCpu);
95 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetInfStatuses, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
96 "Informational statuses returned", "/IEM/CPU%u/cRetInfStatuses", idCpu);
97 STAMR3RegisterF(pVM, &pVCpu->iem.s.cRetErrStatuses, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
98 "Error statuses returned", "/IEM/CPU%u/cRetErrStatuses", idCpu);
99 STAMR3RegisterF(pVM, &pVCpu->iem.s.cbWritten, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
100 "Approx bytes written", "/IEM/CPU%u/cbWritten", idCpu);
101 STAMR3RegisterF(pVM, &pVCpu->iem.s.cPendingCommit, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
102 "Times RC/R0 had to postpone instruction committing to ring-3", "/IEM/CPU%u/cPendingCommit", idCpu);
103
104#ifdef VBOX_WITH_STATISTICS
105 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbHits, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
106 "Code TLB hits", "/IEM/CPU%u/CodeTlb-Hits", idCpu);
107 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbHits, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
108 "Data TLB hits", "/IEM/CPU%u/DataTlb-Hits", idCpu);
109#endif
110 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbMisses, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
111 "Code TLB misses", "/IEM/CPU%u/CodeTlb-Misses", idCpu);
112 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.uTlbRevision, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
113 "Code TLB revision", "/IEM/CPU%u/CodeTlb-Revision", idCpu);
114 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.CodeTlb.uTlbPhysRev, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
115 "Code TLB physical revision", "/IEM/CPU%u/CodeTlb-PhysRev", idCpu);
116 STAMR3RegisterF(pVM, &pVCpu->iem.s.CodeTlb.cTlbSlowReadPath, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
117 "Code TLB slow read path", "/IEM/CPU%u/CodeTlb-SlowReads", idCpu);
118
119 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.cTlbMisses, STAMTYPE_U32_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
120 "Data TLB misses", "/IEM/CPU%u/DataTlb-Misses", idCpu);
121 STAMR3RegisterF(pVM, &pVCpu->iem.s.DataTlb.uTlbRevision, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
122 "Data TLB revision", "/IEM/CPU%u/DataTlb-Revision", idCpu);
123 STAMR3RegisterF(pVM, (void *)&pVCpu->iem.s.DataTlb.uTlbPhysRev, STAMTYPE_X64, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
124 "Data TLB physical revision", "/IEM/CPU%u/DataTlb-PhysRev", idCpu);
125
126#if defined(VBOX_WITH_STATISTICS) && !defined(DOXYGEN_RUNNING)
127 /* Instruction statistics: */
128# define IEM_DO_INSTR_STAT(a_Name, a_szDesc) \
129 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatsRZ.a_Name, STAMTYPE_U32_RESET, STAMVISIBILITY_USED, \
130 STAMUNIT_COUNT, a_szDesc, "/IEM/CPU%u/instr-RZ/" #a_Name, idCpu); \
131 STAMR3RegisterF(pVM, &pVCpu->iem.s.StatsR3.a_Name, STAMTYPE_U32_RESET, STAMVISIBILITY_USED, \
132 STAMUNIT_COUNT, a_szDesc, "/IEM/CPU%u/instr-R3/" #a_Name, idCpu);
133# include "IEMInstructionStatisticsTmpl.h"
134# undef IEM_DO_INSTR_STAT
135#endif
136
137 /*
138 * Host and guest CPU information.
139 */
140 if (idCpu == 0)
141 {
142 pVCpu->iem.s.enmCpuVendor = CPUMGetGuestCpuVendor(pVM);
143 pVCpu->iem.s.enmHostCpuVendor = CPUMGetHostCpuVendor(pVM);
144 pVCpu->iem.s.aidxTargetCpuEflFlavour[0] = pVCpu->iem.s.enmCpuVendor == CPUMCPUVENDOR_INTEL
145 || pVCpu->iem.s.enmCpuVendor == CPUMCPUVENDOR_VIA /*??*/
146 ? IEMTARGETCPU_EFL_BEHAVIOR_INTEL : IEMTARGETCPU_EFL_BEHAVIOR_AMD;
147#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
148 if (pVCpu->iem.s.enmCpuVendor == pVCpu->iem.s.enmHostCpuVendor)
149 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = IEMTARGETCPU_EFL_BEHAVIOR_NATIVE;
150 else
151#endif
152 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = pVCpu->iem.s.aidxTargetCpuEflFlavour[0];
153
154#if IEM_CFG_TARGET_CPU == IEMTARGETCPU_DYNAMIC
155 switch (pVM->cpum.ro.GuestFeatures.enmMicroarch)
156 {
157 case kCpumMicroarch_Intel_8086: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_8086; break;
158 case kCpumMicroarch_Intel_80186: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_186; break;
159 case kCpumMicroarch_Intel_80286: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_286; break;
160 case kCpumMicroarch_Intel_80386: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_386; break;
161 case kCpumMicroarch_Intel_80486: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_486; break;
162 case kCpumMicroarch_Intel_P5: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_PENTIUM; break;
163 case kCpumMicroarch_Intel_P6: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_PPRO; break;
164 case kCpumMicroarch_NEC_V20: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_V20; break;
165 case kCpumMicroarch_NEC_V30: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_V20; break;
166 default: pVCpu->iem.s.uTargetCpu = IEMTARGETCPU_CURRENT; break;
167 }
168 LogRel(("IEM: TargetCpu=%s, Microarch=%s aidxTargetCpuEflFlavour={%d,%d}\n",
169 iemGetTargetCpuName(pVCpu->iem.s.uTargetCpu), CPUMMicroarchName(pVM->cpum.ro.GuestFeatures.enmMicroarch),
170 pVCpu->iem.s.aidxTargetCpuEflFlavour[0], pVCpu->iem.s.aidxTargetCpuEflFlavour[1]));
171#else
172 LogRel(("IEM: Microarch=%s aidxTargetCpuEflFlavour={%d,%d}\n",
173 CPUMMicroarchName(pVM->cpum.ro.GuestFeatures.enmMicroarch),
174 pVCpu->iem.s.aidxTargetCpuEflFlavour[0], pVCpu->iem.s.aidxTargetCpuEflFlavour[1]));
175#endif
176 }
177 else
178 {
179 pVCpu->iem.s.enmCpuVendor = pVM->apCpusR3[0]->iem.s.enmCpuVendor;
180 pVCpu->iem.s.enmHostCpuVendor = pVM->apCpusR3[0]->iem.s.enmHostCpuVendor;
181 pVCpu->iem.s.aidxTargetCpuEflFlavour[0] = pVM->apCpusR3[0]->iem.s.aidxTargetCpuEflFlavour[0];
182 pVCpu->iem.s.aidxTargetCpuEflFlavour[1] = pVM->apCpusR3[0]->iem.s.aidxTargetCpuEflFlavour[1];
183#if IEM_CFG_TARGET_CPU == IEMTARGETCPU_DYNAMIC
184 pVCpu->iem.s.uTargetCpu = pVM->apCpusR3[0]->iem.s.uTargetCpu;
185#endif
186 }
187
188 /*
189 * Mark all buffers free.
190 */
191 uint32_t iMemMap = RT_ELEMENTS(pVCpu->iem.s.aMemMappings);
192 while (iMemMap-- > 0)
193 pVCpu->iem.s.aMemMappings[iMemMap].fAccess = IEM_ACCESS_INVALID;
194 }
195
196#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
197 /*
198 * Register the per-VM VMX APIC-access page handler type.
199 */
200 if (pVM->cpum.ro.GuestFeatures.fVmx)
201 {
202 int rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_ALL, 0 /*fFlags*/,
203 iemVmxApicAccessPageHandler,
204 "VMX APIC-access page", &pVM->iem.s.hVmxApicAccessPage);
205 AssertLogRelRCReturn(rc, rc);
206 }
207#endif
208
209 DBGFR3InfoRegisterInternalArgv(pVM, "itlb", "IEM instruction TLB", iemR3InfoITlb, DBGFINFO_FLAGS_RUN_ON_EMT);
210 DBGFR3InfoRegisterInternalArgv(pVM, "dtlb", "IEM instruction TLB", iemR3InfoDTlb, DBGFINFO_FLAGS_RUN_ON_EMT);
211
212 return VINF_SUCCESS;
213}
214
215
216VMMR3DECL(int) IEMR3Term(PVM pVM)
217{
218 NOREF(pVM);
219 return VINF_SUCCESS;
220}
221
222
223VMMR3DECL(void) IEMR3Relocate(PVM pVM)
224{
225 RT_NOREF(pVM);
226}
227
228
229/** Worker for iemR3InfoTlbPrintSlots and iemR3InfoTlbPrintAddress. */
230static void iemR3InfoTlbPrintHeader(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb, bool *pfHeader)
231{
232 if (*pfHeader)
233 return;
234 pHlp->pfnPrintf(pHlp, "%cTLB for CPU %u:\n", &pVCpu->iem.s.CodeTlb == pTlb ? 'I' : 'D', pVCpu->idCpu);
235 *pfHeader = true;
236}
237
238
239/** Worker for iemR3InfoTlbPrintSlots and iemR3InfoTlbPrintAddress. */
240static void iemR3InfoTlbPrintSlot(PCDBGFINFOHLP pHlp, IEMTLB const *pTlb, IEMTLBENTRY const *pTlbe, uint32_t uSlot)
241{
242 pHlp->pfnPrintf(pHlp, "%02x: %s %#018RX64 -> %RGp / %p / %#05x %s%s%s%s/%s%s%s/%s %s\n",
243 uSlot,
244 (pTlbe->uTag & IEMTLB_REVISION_MASK) == pTlb->uTlbRevision ? "valid "
245 : (pTlbe->uTag & IEMTLB_REVISION_MASK) == 0 ? "empty "
246 : "expired",
247 (pTlbe->uTag & ~IEMTLB_REVISION_MASK) << X86_PAGE_SHIFT,
248 pTlbe->GCPhys, pTlbe->pbMappingR3,
249 (uint32_t)(pTlbe->fFlagsAndPhysRev & ~IEMTLBE_F_PHYS_REV),
250 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC ? "NX" : " X",
251 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE ? "RO" : "RW",
252 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED ? "-" : "A",
253 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_DIRTY ? "-" : "D",
254 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_WRITE ? "-" : "w",
255 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_NO_READ ? "-" : "r",
256 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PG_UNASSIGNED ? "U" : "-",
257 pTlbe->fFlagsAndPhysRev & IEMTLBE_F_NO_MAPPINGR3 ? "S" : "M",
258 (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pTlb->uTlbPhysRev ? "phys-valid"
259 : (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == 0 ? "phys-empty" : "phys-expired");
260}
261
262
263/** Displays one or more TLB slots. */
264static void iemR3InfoTlbPrintSlots(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb,
265 uint32_t uSlot, uint32_t cSlots, bool *pfHeader)
266{
267 if (uSlot < RT_ELEMENTS(pTlb->aEntries))
268 {
269 if (cSlots > RT_ELEMENTS(pTlb->aEntries))
270 {
271 pHlp->pfnPrintf(pHlp, "error: Too many slots given: %u, adjusting it down to the max (%u)\n",
272 cSlots, RT_ELEMENTS(pTlb->aEntries));
273 cSlots = RT_ELEMENTS(pTlb->aEntries);
274 }
275
276 iemR3InfoTlbPrintHeader(pVCpu, pHlp, pTlb, pfHeader);
277 while (cSlots-- > 0)
278 {
279 IEMTLBENTRY const Tlbe = pTlb->aEntries[uSlot];
280 iemR3InfoTlbPrintSlot(pHlp, pTlb, &Tlbe, uSlot);
281 uSlot = (uSlot + 1) % RT_ELEMENTS(pTlb->aEntries);
282 }
283 }
284 else
285 pHlp->pfnPrintf(pHlp, "error: TLB slot is out of range: %u (%#x), max %u (%#x)\n",
286 uSlot, uSlot, RT_ELEMENTS(pTlb->aEntries) - 1, RT_ELEMENTS(pTlb->aEntries) - 1);
287}
288
289
290/** Displays the TLB slot for the given address. */
291static void iemR3InfoTlbPrintAddress(PVMCPU pVCpu, PCDBGFINFOHLP pHlp, IEMTLB const *pTlb,
292 uint64_t uAddress, bool *pfHeader)
293{
294 iemR3InfoTlbPrintHeader(pVCpu, pHlp, pTlb, pfHeader);
295
296 uint64_t const uTag = (uAddress << 16) >> (X86_PAGE_SHIFT + 16);
297 uint32_t const uSlot = (uint8_t)uTag;
298 IEMTLBENTRY const Tlbe = pTlb->aEntries[uSlot];
299 pHlp->pfnPrintf(pHlp, "Address %#RX64 -> slot %#x - %s\n", uAddress, uSlot,
300 Tlbe.uTag == (uTag | pTlb->uTlbRevision) ? "match"
301 : (Tlbe.uTag & ~IEMTLB_REVISION_MASK) == uTag ? "expired" : "mismatch");
302 iemR3InfoTlbPrintSlot(pHlp, pTlb, &Tlbe, uSlot);
303}
304
305
306/** Common worker for iemR3InfoDTlb and iemR3InfoITlb. */
307static void iemR3InfoTlbCommon(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs, bool fITlb)
308{
309 /*
310 * This is entirely argument driven.
311 */
312 static RTGETOPTDEF const s_aOptions[] =
313 {
314 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
315 { "--vcpu", 'c', RTGETOPT_REQ_UINT32 },
316 { "all", 'A', RTGETOPT_REQ_NOTHING },
317 { "--all", 'A', RTGETOPT_REQ_NOTHING },
318 { "--address", 'a', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
319 { "--range", 'r', RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_HEX },
320 { "--slot", 's', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX },
321 };
322
323 char szDefault[] = "-A";
324 char *papszDefaults[2] = { szDefault, NULL };
325 if (cArgs == 0)
326 {
327 cArgs = 1;
328 papszArgs = papszDefaults;
329 }
330
331 RTGETOPTSTATE State;
332 int rc = RTGetOptInit(&State, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /*iFirst*/, 0 /*fFlags*/);
333 AssertRCReturnVoid(rc);
334
335 bool fNeedHeader = true;
336 bool fAddressMode = true;
337 PVMCPU pVCpu = VMMGetCpu(pVM);
338 if (!pVCpu)
339 pVCpu = VMMGetCpuById(pVM, 0);
340
341 RTGETOPTUNION ValueUnion;
342 while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
343 {
344 switch (rc)
345 {
346 case 'c':
347 if (ValueUnion.u32 >= pVM->cCpus)
348 pHlp->pfnPrintf(pHlp, "error: Invalid CPU ID: %u\n", ValueUnion.u32);
349 else if (!pVCpu || pVCpu->idCpu != ValueUnion.u32)
350 {
351 pVCpu = VMMGetCpuById(pVM, ValueUnion.u32);
352 fNeedHeader = true;
353 }
354 break;
355
356 case 'a':
357 iemR3InfoTlbPrintAddress(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
358 ValueUnion.u64, &fNeedHeader);
359 fAddressMode = true;
360 break;
361
362 case 'A':
363 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
364 0, RT_ELEMENTS(pVCpu->iem.s.CodeTlb.aEntries), &fNeedHeader);
365 break;
366
367 case 'r':
368 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
369 ValueUnion.PairU32.uFirst, ValueUnion.PairU32.uSecond, &fNeedHeader);
370 fAddressMode = false;
371 break;
372
373 case 's':
374 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
375 ValueUnion.u32, 1, &fNeedHeader);
376 fAddressMode = false;
377 break;
378
379 case VINF_GETOPT_NOT_OPTION:
380 if (fAddressMode)
381 {
382 uint64_t uAddr;
383 rc = RTStrToUInt64Full(ValueUnion.psz, 16, &uAddr);
384 if (RT_SUCCESS(rc) && rc != VWRN_NUMBER_TOO_BIG)
385 iemR3InfoTlbPrintAddress(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
386 uAddr, &fNeedHeader);
387 else
388 pHlp->pfnPrintf(pHlp, "error: Invalid or malformed guest address '%s': %Rrc\n", ValueUnion.psz, rc);
389 }
390 else
391 {
392 uint32_t uSlot;
393 rc = RTStrToUInt32Full(ValueUnion.psz, 16, &uSlot);
394 if (RT_SUCCESS(rc) && rc != VWRN_NUMBER_TOO_BIG)
395 iemR3InfoTlbPrintSlots(pVCpu, pHlp, fITlb ? &pVCpu->iem.s.CodeTlb : &pVCpu->iem.s.DataTlb,
396 uSlot, 1, &fNeedHeader);
397 else
398 pHlp->pfnPrintf(pHlp, "error: Invalid or malformed TLB slot number '%s': %Rrc\n", ValueUnion.psz, rc);
399 }
400 break;
401
402 case 'h':
403 pHlp->pfnPrintf(pHlp,
404 "Usage: info %ctlb [options]\n"
405 "\n"
406 "Options:\n"
407 " -c<n>, --cpu=<n>, --vcpu=<n>\n"
408 " Selects the CPU which TLBs we're looking at. Default: Caller / 0\n"
409 " -A, --all, all\n"
410 " Display all the TLB entries (default if no other args).\n"
411 " -a<virt>, --address=<virt>\n"
412 " Shows the TLB entry for the specified guest virtual address.\n"
413 " -r<slot:count>, --range=<slot:count>\n"
414 " Shows the TLB entries for the specified slot range.\n"
415 " -s<slot>,--slot=<slot>\n"
416 " Shows the given TLB slot.\n"
417 "\n"
418 "Non-options are interpreted according to the last -a, -r or -s option,\n"
419 "defaulting to addresses if not preceeded by any of those options.\n"
420 , fITlb ? 'i' : 'd');
421 return;
422
423 default:
424 pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
425 return;
426 }
427 }
428}
429
430
431/**
432 * @callback_method_impl{FNDBGFINFOARGVINT, itlb}
433 */
434static DECLCALLBACK(void) iemR3InfoITlb(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
435{
436 return iemR3InfoTlbCommon(pVM, pHlp, cArgs, papszArgs, true /*fITlb*/);
437}
438
439
440/**
441 * @callback_method_impl{FNDBGFINFOARGVINT, dtlb}
442 */
443static DECLCALLBACK(void) iemR3InfoDTlb(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
444{
445 return iemR3InfoTlbCommon(pVM, pHlp, cArgs, papszArgs, false /*fITlb*/);
446}
447
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