VirtualBox

source: vbox/trunk/src/VBox/VMM/CPUM.cpp@ 23

Last change on this file since 23 was 23, checked in by vboxsync, 18 years ago

string.h & stdio.h + header cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 72.3 KB
Line 
1/* $Id: CPUM.cpp 23 2007-01-15 14:08:28Z vboxsync $ */
2/** @file
3 * CPUM - CPU Monitor(/Manager)
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_CPUM
27#include <VBox/cpum.h>
28#include <VBox/cpumdis.h>
29#include <VBox/pgm.h>
30#include <VBox/mm.h>
31#include <VBox/selm.h>
32#include <VBox/dbgf.h>
33#include <VBox/patm.h>
34#include <VBox/ssm.h>
35#include "CPUMInternal.h"
36#include <VBox/vm.h>
37
38#include <VBox/param.h>
39#include <VBox/dis.h>
40#include <VBox/err.h>
41#include <VBox/log.h>
42#include <iprt/assert.h>
43#include <iprt/asm.h>
44#include <iprt/string.h>
45#include "x86context.h"
46
47/*******************************************************************************
48* Defined Constants And Macros *
49*******************************************************************************/
50/** The saved state version. */
51#define CPUM_SAVED_STATE_VERSION 3
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57
58/**
59 * What kind of cpu info dump to performe.
60 */
61typedef enum CPUMDUMPTYPE
62{
63 CPUMDUMPTYPE_TERSE,
64 CPUMDUMPTYPE_DEFAULT,
65 CPUMDUMPTYPE_VERBOSE
66
67} CPUMDUMPTYPE, *PCPUMDUMPTYPE;
68
69
70/*******************************************************************************
71* Internal Functions *
72*******************************************************************************/
73static int cpumR3CpuIdInit(PVM pVM);
74static DECLCALLBACK(int) cpumR3Save(PVM pVM, PSSMHANDLE pSSM);
75static DECLCALLBACK(int) cpumR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
76static DECLCALLBACK(void) cpumR3InfoAll(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
77static DECLCALLBACK(void) cpumR3InfoGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
78static DECLCALLBACK(void) cpumR3InfoHyper(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
79static DECLCALLBACK(void) cpumR3InfoHost(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
80static DECLCALLBACK(void) cpumR3CpuIdInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
81
82
83/**
84 * Initializes the CPUM.
85 *
86 * @returns VBox status code.
87 * @param pVM The VM to operate on.
88 */
89CPUMR3DECL(int) CPUMR3Init(PVM pVM)
90{
91 LogFlow(("CPUMR3Init\n"));
92
93 /*
94 * Assert alignment and sizes.
95 */
96 AssertRelease(!(RT_OFFSETOF(VM, cpum.s) & 31));
97 AssertRelease(sizeof(pVM->cpum.s) <= sizeof(pVM->cpum.padding));
98
99 /*
100 * Setup any fixed pointers and offsets.
101 */
102 pVM->cpum.s.offVM = RT_OFFSETOF(VM, cpum);
103 pVM->cpum.s.pCPUMHC = &pVM->cpum.s;
104 pVM->cpum.s.pHyperCoreHC = CPUMCTX2CORE(&pVM->cpum.s.Hyper);
105
106 /* Hidden selector registers are invalid by default. */
107 pVM->cpum.s.fValidHiddenSelRegs = false;
108
109 /*
110 * Check that the CPU supports the minimum features we require.
111 */
112 /** @todo check the contract! */
113 if (!ASMHasCpuId())
114 {
115 Log(("The CPU doesn't support CPUID!\n"));
116 return VERR_UNSUPPORTED_CPU;
117 }
118 ASMCpuId_ECX_EDX(1, &pVM->cpum.s.CPUFeatures.ecx, &pVM->cpum.s.CPUFeatures.edx);
119
120 /* Setup the CR4 AND and OR masks used in the switcher */
121 /* Depends on the presence of FXSAVE(SSE) support on the host CPU */
122 if (!pVM->cpum.s.CPUFeatures.edx.u1FXSR)
123 {
124 Log(("The CPU doesn't support FXSAVE/FXRSTOR!\n"));
125 /* No FXSAVE implies no SSE */
126 pVM->cpum.s.CR4.Mask = X86_CR4_PVI | X86_CR4_VME;
127 pVM->cpum.s.CR4.OSFSXR = 0;
128 }
129 else
130 {
131 pVM->cpum.s.CR4.Mask = X86_CR4_OSXMMEEXCPT | X86_CR4_PVI | X86_CR4_VME;
132 pVM->cpum.s.CR4.OSFSXR = X86_CR4_OSFSXR;
133 }
134
135 if (!pVM->cpum.s.CPUFeatures.edx.u1MMX)
136 {
137 Log(("The CPU doesn't support MMX!\n"));
138 return VERR_UNSUPPORTED_CPU;
139 }
140 if (!pVM->cpum.s.CPUFeatures.edx.u1TSC)
141 {
142 Log(("The CPU doesn't support TSC!\n"));
143 return VERR_UNSUPPORTED_CPU;
144 }
145 /* Bogus on AMD? */
146 if (!pVM->cpum.s.CPUFeatures.edx.u1SEP)
147 {
148 Log(("The CPU doesn't support SYSENTER/SYSEXIT!\n"));
149 }
150
151 /*
152 * Setup hypervisor startup values.
153 */
154
155 /*
156 * Register saved state data item.
157 */
158 int rc = SSMR3RegisterInternal(pVM, "cpum", 1, CPUM_SAVED_STATE_VERSION, sizeof(CPUM),
159 NULL, cpumR3Save, NULL,
160 NULL, cpumR3Load, NULL);
161 if (VBOX_FAILURE(rc))
162 return rc;
163
164 /*
165 * Register info handlers.
166 */
167 DBGFR3InfoRegisterInternal(pVM, "cpum", "Displays the all the cpu states.", &cpumR3InfoAll);
168 DBGFR3InfoRegisterInternal(pVM, "cpumguest", "Displays the guest cpu state.", &cpumR3InfoGuest);
169 DBGFR3InfoRegisterInternal(pVM, "cpumhyper", "Displays the hypervisor cpu state.", &cpumR3InfoHyper);
170 DBGFR3InfoRegisterInternal(pVM, "cpumhost", "Displays the host cpu state.", &cpumR3InfoHost);
171 DBGFR3InfoRegisterInternal(pVM, "cpuid", "Displays the guest cpuid leafs.", &cpumR3CpuIdInfo);
172
173 /*
174 * Initialize the Guest CPU state.
175 */
176 rc = cpumR3CpuIdInit(pVM);
177 if (VBOX_FAILURE(rc))
178 return rc;
179 CPUMR3Reset(pVM);
180 return VINF_SUCCESS;
181}
182
183
184/**
185 * Initializes the emulated CPU's cpuid information.
186 *
187 * @returns VBox status code.
188 * @param pVM The VM to operate on.
189 */
190static int cpumR3CpuIdInit(PVM pVM)
191{
192 PCPUM pCPUM = &pVM->cpum.s;
193 uint32_t i;
194
195 /*
196 * Get the host CPUIDs.
197 */
198 for (i = 0; i < ELEMENTS(pVM->cpum.s.aGuestCpuIdStd); i++)
199 ASMCpuId(i,
200 &pCPUM->aGuestCpuIdStd[i].eax, &pCPUM->aGuestCpuIdStd[i].ebx,
201 &pCPUM->aGuestCpuIdStd[i].ecx, &pCPUM->aGuestCpuIdStd[i].edx);
202 for (i = 0; i < ELEMENTS(pCPUM->aGuestCpuIdExt); i++)
203 ASMCpuId(0x80000000 + i,
204 &pCPUM->aGuestCpuIdExt[i].eax, &pCPUM->aGuestCpuIdExt[i].ebx,
205 &pCPUM->aGuestCpuIdExt[i].ecx, &pCPUM->aGuestCpuIdExt[i].edx);
206
207 /*
208 * Only report features we can support.
209 */
210 pCPUM->aGuestCpuIdStd[1].edx &= X86_CPUID_FEATURE_EDX_FPU
211 //| X86_CPUID_FEATURE_EDX_VME - recompiler doesn't do this.
212 | X86_CPUID_FEATURE_EDX_DE
213 | X86_CPUID_FEATURE_EDX_PSE
214 | X86_CPUID_FEATURE_EDX_TSC
215 | X86_CPUID_FEATURE_EDX_MSR
216 //| X86_CPUID_FEATURE_EDX_PAE - not implemented yet.
217 | X86_CPUID_FEATURE_EDX_MCE
218 | X86_CPUID_FEATURE_EDX_CX8
219 //| X86_CPUID_FEATURE_EDX_APIC - set by the APIC device if present.
220 | X86_CPUID_FEATURE_EDX_SEP
221 //| X86_CPUID_FEATURE_EDX_MTRR - no MTRRs.
222 | X86_CPUID_FEATURE_EDX_PGE
223 //| X86_CPUID_FEATURE_EDX_MCA - not virtualized.
224 | X86_CPUID_FEATURE_EDX_CMOV
225 //| X86_CPUID_FEATURE_EDX_PAT - not virtualized.
226 //| X86_CPUID_FEATURE_EDX_PSE36 - not virtualized.
227 //| X86_CPUID_FEATURE_EDX_PSN - no serial number.
228 //| X86_CPUID_FEATURE_EDX_CLFSH - no CLFLUSH instruction.
229 //| X86_CPUID_FEATURE_EDX_DS - no debug store.
230 //| X86_CPUID_FEATURE_EDX_ACPI - not virtualized yet.
231 | X86_CPUID_FEATURE_EDX_MMX
232 | X86_CPUID_FEATURE_EDX_FXSR
233 | X86_CPUID_FEATURE_EDX_SSE
234 | X86_CPUID_FEATURE_EDX_SSE2
235 //| X86_CPUID_FEATURE_EDX_SS - no self snoop.
236 //| X86_CPUID_FEATURE_EDX_HTT - no hyperthreading.
237 //| X86_CPUID_FEATURE_EDX_TM - no thermal monitor.
238 //| X86_CPUID_FEATURE_EDX_PBE - no pneding break enabled.
239 | 0;
240 pCPUM->aGuestCpuIdStd[1].ecx &= 0//X86_CPUID_FEATURE_ECX_SSE3 - not supported by the recompiler yet.
241 | X86_CPUID_FEATURE_ECX_MONITOR
242 //| X86_CPUID_FEATURE_ECX_CPLDS - no CPL qualified debug store.
243 //| X86_CPUID_FEATURE_ECX_VMX - not virtualized.
244 //| X86_CPUID_FEATURE_ECX_EST - no extended speed step.
245 //| X86_CPUID_FEATURE_ECX_TM2 - no thermal monitor 2.
246 //| X86_CPUID_FEATURE_ECX_CNTXID - no L1 context id (MSR++).
247 | 0;
248
249#if 1 /* we didn't used to do this, but I guess we should */
250 /* ASSUMES that this is ALLWAYS the AMD define feature set if present. */
251 pCPUM->aGuestCpuIdExt[1].edx &= X86_CPUID_AMD_FEATURE_EDX_FPU
252 //| X86_CPUID_AMD_FEATURE_EDX_VME - recompiler doesn't do this.
253 | X86_CPUID_AMD_FEATURE_EDX_DE
254 | X86_CPUID_AMD_FEATURE_EDX_PSE
255 | X86_CPUID_AMD_FEATURE_EDX_TSC
256 | X86_CPUID_AMD_FEATURE_EDX_MSR //?? this means AMD MSRs..
257 //| X86_CPUID_AMD_FEATURE_EDX_PAE - not implemented yet.
258 //| X86_CPUID_AMD_FEATURE_EDX_MCE - not virtualized yet.
259 | X86_CPUID_AMD_FEATURE_EDX_CX8
260 //| X86_CPUID_AMD_FEATURE_EDX_APIC - set by the APIC device if present.
261 | X86_CPUID_AMD_FEATURE_EDX_SEP
262 //| X86_CPUID_AMD_FEATURE_EDX_MTRR - not virtualized.
263 | X86_CPUID_AMD_FEATURE_EDX_PGE
264 //| X86_CPUID_AMD_FEATURE_EDX_MCA - not virtualized.
265 | X86_CPUID_AMD_FEATURE_EDX_CMOV
266 | X86_CPUID_AMD_FEATURE_EDX_PAT
267 //| X86_CPUID_AMD_FEATURE_EDX_PSE36 - not virtualized.
268 //| X86_CPUID_AMD_FEATURE_EDX_NX - not virtualized, requires PAE.
269 | X86_CPUID_AMD_FEATURE_EDX_MMX
270 | X86_CPUID_AMD_FEATURE_EDX_FXSR
271 | X86_CPUID_AMD_FEATURE_EDX_FFXSR
272 //| X86_CPUID_AMD_FEATURE_EDX_LONG_MODE - definintly not.
273 | X86_CPUID_AMD_FEATURE_EDX_3DNOW_EX
274 | X86_CPUID_AMD_FEATURE_EDX_3DNOW
275 | 0;
276 pCPUM->aGuestCpuIdExt[1].ecx &= 0//X86_CPUID_AMD_FEATURE_ECX_SVM - not virtualized.
277 | 0;
278#endif
279
280#if 0 /* this is what we used to do. */
281 /*
282 * Set BrandIndex=0, CLFLUSH-line-size=0, Num-Logical-Cpus=0 and APIC-ID=0.
283 */
284 pCPUM->aGuestCpuIdStd[1].ebx = 0;
285
286 /*
287 * Set the max standard index to 2.
288 */
289 pCPUM->aGuestCpuIdStd[0].eax = 2;
290 pCPUM->GuestCpuIdDef = pCPUM->aGuestCpuIdStd[2]; /** @todo this default is *NOT* right for AMD, only Intel CPUs. (see tstInlineAsm) */
291
292#else /* this is what we probably should do */
293 /*
294 * Hide HTT, multicode, SMP, whatever.
295 * (APIC-ID := 0 and #LogCpus := 0)
296 */
297 pCPUM->aGuestCpuIdStd[1].ebx = 0x0000ffff;
298
299 /*
300 * Determin the default value and limit it the number of entries.
301 * Intel returns values of the highest standard function, while AMD returns zeros.
302 */
303 ASMCpuId(pCPUM->aGuestCpuIdStd[0].eax + 10,
304 &pCPUM->GuestCpuIdDef.eax, &pCPUM->GuestCpuIdDef.ebx,
305 &pCPUM->GuestCpuIdDef.ecx, &pCPUM->GuestCpuIdDef.edx);
306
307 if (pCPUM->aGuestCpuIdStd[0].eax > 2)
308 pCPUM->aGuestCpuIdStd[0].eax = 2;
309
310 if (pCPUM->aGuestCpuIdExt[0].eax > 0x80000004)
311 pCPUM->aGuestCpuIdExt[0].eax = 0x80000004;
312
313#endif
314
315 /*
316 * Assign defaults to the entries we chopped off.
317 */
318 for (i = pCPUM->aGuestCpuIdStd[0].eax + 1; i < ELEMENTS(pCPUM->aGuestCpuIdStd); i++)
319 pCPUM->aGuestCpuIdStd[i] = pCPUM->GuestCpuIdDef;
320 for (i = pCPUM->aGuestCpuIdExt[0].eax - 0x80000000 + 1; i < ELEMENTS(pCPUM->aGuestCpuIdExt); i++)
321 pCPUM->aGuestCpuIdExt[i] = pCPUM->GuestCpuIdDef;
322
323 /*
324 * Load CPUID overrides from configuration.
325 */
326 PCPUMCPUID pCpuId = &pCPUM->aGuestCpuIdStd[0];
327 uint32_t cElements = ELEMENTS(pCPUM->aGuestCpuIdStd);
328 for (;;)
329 {
330 while (cElements-- < 0)
331 {
332 PCFGMNODE pNode = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "CPUM/CPUID/%RX32", i);
333 if (pNode)
334 {
335 uint32_t u32;
336 int rc = CFGMR3QueryU32(pNode, "eax", &u32);
337 if (VBOX_SUCCESS(rc))
338 pCpuId->eax = u32;
339 else
340 AssertReturn(rc == VERR_CFGM_VALUE_NOT_FOUND, rc);
341
342 rc = CFGMR3QueryU32(pNode, "ebx", &u32);
343 if (VBOX_SUCCESS(rc))
344 pCpuId->ebx = u32;
345 else
346 AssertReturn(rc == VERR_CFGM_VALUE_NOT_FOUND, rc);
347
348 rc = CFGMR3QueryU32(pNode, "ecx", &u32);
349 if (VBOX_SUCCESS(rc))
350 pCpuId->ecx = u32;
351 else
352 AssertReturn(rc == VERR_CFGM_VALUE_NOT_FOUND, rc);
353
354 rc = CFGMR3QueryU32(pNode, "edx", &u32);
355 if (VBOX_SUCCESS(rc))
356 pCpuId->edx = u32;
357 else
358 AssertReturn(rc == VERR_CFGM_VALUE_NOT_FOUND, rc);
359 }
360 }
361
362 /* next */
363 if (i & 0x80000000)
364 break;
365 pCpuId = &pCPUM->aGuestCpuIdExt[0];
366 cElements = ELEMENTS(pCPUM->aGuestCpuIdExt);
367 i = 0x80000000;
368 }
369
370 /*
371 * Log the cpuid and we're good.
372 */
373 LogRel(("************************* CPUID dump ************************\n"));
374 DBGFR3Info(pVM, "cpuid", "verbose", DBGFR3InfoLogRelHlp());
375 LogRel(("\n"));
376 DBGFR3InfoLog(pVM, "cpuid", "verbose"); /* macro */
377 LogRel(("******************** End of CPUID dump **********************\n"));
378 return VINF_SUCCESS;
379}
380
381
382
383
384/**
385 * Applies relocations to data and code managed by this
386 * component. This function will be called at init and
387 * whenever the VMM need to relocate it self inside the GC.
388 *
389 * The CPUM will update the addresses used by the switcher.
390 *
391 * @param pVM The VM.
392 */
393CPUMR3DECL(void) CPUMR3Relocate(PVM pVM)
394{
395 LogFlow(("CPUMR3Relocate\n"));
396 /*
397 * Switcher pointers.
398 */
399 pVM->cpum.s.pCPUMGC = VM_GUEST_ADDR(pVM, &pVM->cpum.s);
400 pVM->cpum.s.pHyperCoreGC = MMHyperHC2GC(pVM, pVM->cpum.s.pHyperCoreHC);
401}
402
403
404/**
405 * Queries the pointer to the internal CPUMCTX structure
406 *
407 * @returns VBox status code.
408 * @param pVM Handle to the virtual machine.
409 * @param ppCtx Receives the CPUMCTX GC pointer when successful.
410 */
411CPUMR3DECL(int) CPUMR3QueryGuestCtxGCPtr(PVM pVM, GCPTRTYPE(PCPUMCTX) *ppCtx)
412{
413 LogFlow(("CPUMR3QueryGuestCtxGCPtr\n"));
414 /*
415 * Store the address. (Later we might check how's calling, thus the RC.)
416 */
417 *ppCtx = VM_GUEST_ADDR(pVM, &pVM->cpum.s.Guest);
418 return VINF_SUCCESS;
419}
420
421
422/**
423 * Terminates the CPUM.
424 *
425 * Termination means cleaning up and freeing all resources,
426 * the VM it self is at this point powered off or suspended.
427 *
428 * @returns VBox status code.
429 * @param pVM The VM to operate on.
430 */
431CPUMR3DECL(int) CPUMR3Term(PVM pVM)
432{
433 /** @todo */
434 return 0;
435}
436
437
438/**
439 * Resets the CPU.
440 *
441 * @returns VINF_SUCCESS.
442 * @param pVM The VM handle.
443 */
444CPUMR3DECL(void) CPUMR3Reset(PVM pVM)
445{
446 PCPUMCTX pCtx = &pVM->cpum.s.Guest;
447
448 /*
449 * Initialize everything to ZERO first.
450 */
451 uint32_t fUseFlags = pVM->cpum.s.fUseFlags & ~CPUM_USED_FPU_SINCE_REM;
452 memset(pCtx, 0, sizeof(*pCtx));
453 pVM->cpum.s.fUseFlags = fUseFlags;
454
455 pCtx->cr0 = X86_CR0_CD | X86_CR0_NW | X86_CR0_ET; //0x60000010
456 pCtx->eip = 0x0000fff0;
457 pCtx->edx = 0x00000600; /* P6 processor */
458 pCtx->eflags.Bits.u1Reserved0 = 1;
459
460 pCtx->cs = 0xf000;
461 pCtx->csHid.u32Base = 0xffff0000;
462 pCtx->csHid.u32Limit = 0x0000ffff;
463 pCtx->dsHid.u32Limit = 0x0000ffff;
464 pCtx->esHid.u32Limit = 0x0000ffff;
465 pCtx->fsHid.u32Limit = 0x0000ffff;
466 pCtx->gsHid.u32Limit = 0x0000ffff;
467 pCtx->ssHid.u32Limit = 0x0000ffff;
468 pCtx->idtr.cbIdt = 0xffff;
469 pCtx->gdtr.cbGdt = 0xffff;
470 pCtx->ldtrHid.u32Limit = 0xffff;
471 pCtx->ldtrHid.Attr.u = X86_DESC_P;
472 pCtx->trHid.u32Limit = 0xffff;
473 pCtx->trHid.Attr.u = X86_DESC_P;
474
475 pCtx->fpu.FTW = 0xff; /* All tags are set, i.e. the regs are empty. */
476 pCtx->fpu.FCW = 0x37f;
477}
478
479
480
481/**
482 * Execute state save operation.
483 *
484 * @returns VBox status code.
485 * @param pVM VM Handle.
486 * @param pSSM SSM operation handle.
487 */
488static DECLCALLBACK(int) cpumR3Save(PVM pVM, PSSMHANDLE pSSM)
489{
490 /*
491 * Save.
492 */
493 SSMR3PutMem(pSSM, &pVM->cpum.s.Hyper, sizeof(pVM->cpum.s.Hyper));
494 SSMR3PutMem(pSSM, &pVM->cpum.s.Guest, sizeof(pVM->cpum.s.Guest));
495 SSMR3PutU32(pSSM, pVM->cpum.s.fUseFlags);
496 SSMR3PutU32(pSSM, pVM->cpum.s.fChanged);
497
498 SSMR3PutU32(pSSM, ELEMENTS(pVM->cpum.s.aGuestCpuIdStd));
499 SSMR3PutMem(pSSM, &pVM->cpum.s.aGuestCpuIdStd[0], sizeof(pVM->cpum.s.aGuestCpuIdStd));
500
501 SSMR3PutU32(pSSM, ELEMENTS(pVM->cpum.s.aGuestCpuIdExt));
502 SSMR3PutMem(pSSM, &pVM->cpum.s.aGuestCpuIdExt[0], sizeof(pVM->cpum.s.aGuestCpuIdExt));
503
504 SSMR3PutMem(pSSM, &pVM->cpum.s.GuestCpuIdDef, sizeof(pVM->cpum.s.GuestCpuIdDef));
505
506 /* Add the cpuid for checking that the cpu is unchanged. */
507 uint32_t au32CpuId[8] = {0};
508 ASMCpuId(0, &au32CpuId[0], &au32CpuId[1], &au32CpuId[2], &au32CpuId[3]);
509 ASMCpuId(1, &au32CpuId[4], &au32CpuId[5], &au32CpuId[6], &au32CpuId[7]);
510 return SSMR3PutMem(pSSM, &au32CpuId[0], sizeof(au32CpuId));
511}
512
513
514/**
515 * Execute state load operation.
516 *
517 * @returns VBox status code.
518 * @param pVM VM Handle.
519 * @param pSSM SSM operation handle.
520 * @param u32Version Data layout version.
521 */
522static DECLCALLBACK(int) cpumR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
523{
524 /*
525 * Validate version.
526 */
527 if (u32Version != CPUM_SAVED_STATE_VERSION)
528 {
529 Log(("cpuR3Load: Invalid version u32Version=%d!\n", u32Version));
530 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
531 }
532
533 /*
534 * Restore.
535 */
536 uint32_t uCR3 = pVM->cpum.s.Hyper.cr3;
537 uint32_t uESP = pVM->cpum.s.Hyper.esp; /* see VMMR3Relocate(). */
538 SSMR3GetMem(pSSM, &pVM->cpum.s.Hyper, sizeof(pVM->cpum.s.Hyper));
539 pVM->cpum.s.Hyper.cr3 = uCR3;
540 pVM->cpum.s.Hyper.esp = uESP;
541 SSMR3GetMem(pSSM, &pVM->cpum.s.Guest, sizeof(pVM->cpum.s.Guest));
542 SSMR3GetU32(pSSM, &pVM->cpum.s.fUseFlags);
543 SSMR3GetU32(pSSM, &pVM->cpum.s.fChanged);
544
545 uint32_t cElements;
546 int rc = SSMR3GetU32(pSSM, &cElements); AssertRCReturn(rc, rc);
547 if (cElements != ELEMENTS(pVM->cpum.s.aGuestCpuIdStd))
548 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
549 SSMR3GetMem(pSSM, &pVM->cpum.s.aGuestCpuIdStd[0], sizeof(pVM->cpum.s.aGuestCpuIdStd));
550
551 rc = SSMR3GetU32(pSSM, &cElements); AssertRCReturn(rc, rc);
552 if (cElements != ELEMENTS(pVM->cpum.s.aGuestCpuIdExt))
553 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
554 SSMR3GetMem(pSSM, &pVM->cpum.s.aGuestCpuIdExt[0], sizeof(pVM->cpum.s.aGuestCpuIdExt));
555
556 SSMR3GetMem(pSSM, &pVM->cpum.s.GuestCpuIdDef, sizeof(pVM->cpum.s.GuestCpuIdDef));
557
558 /*
559 * Check that the basic cpuid id information is unchanged.
560 */
561 uint32_t au32CpuId[8] = {0};
562 ASMCpuId(0, &au32CpuId[0], &au32CpuId[1], &au32CpuId[2], &au32CpuId[3]);
563 ASMCpuId(1, &au32CpuId[4], &au32CpuId[5], &au32CpuId[6], &au32CpuId[7]);
564 uint32_t au32CpuIdSaved[8];
565 rc = SSMR3GetMem(pSSM, &au32CpuIdSaved[0], sizeof(au32CpuIdSaved));
566 if (VBOX_SUCCESS(rc))
567 {
568 /* Ignore APIC ID (AMD specs). */
569 au32CpuId[5] &= ~0xff000000;
570 au32CpuIdSaved[5] &= ~0xff000000;
571 /* Ignore the number of Logical CPUs (AMD specs). */
572 au32CpuId[5] &= ~0x00ff0000;
573 au32CpuIdSaved[5] &= ~0x00ff0000;
574
575 /* do the compare */
576 if (memcmp(au32CpuIdSaved, au32CpuId, sizeof(au32CpuIdSaved)))
577 {
578 Log(("cpumR3Load: CpuId mismatch!\n"
579 "Saved=%.*Vhxs\n"
580 "Real =%.*Vhxs\n",
581 sizeof(au32CpuIdSaved), au32CpuIdSaved,
582 sizeof(au32CpuId), au32CpuId));
583 rc = VERR_SSM_LOAD_CPUID_MISMATCH;
584 }
585 }
586
587 return rc;
588}
589
590
591/**
592 * Formats the EFLAGS value into mnemonics.
593 *
594 * @param pszEFlags Where to write the mnemonics. (Assumes sufficient buffer space.)
595 * @param efl The EFLAGS value.
596 */
597static void cpumR3InfoFormatFlags(char *pszEFlags, uint32_t efl)
598{
599 /*
600 * Format the flags.
601 */
602 static struct
603 {
604 const char *pszSet; const char *pszClear; uint32_t fFlag;
605 } s_aFlags[] =
606 {
607 { "vip",NULL, X86_EFL_VIP },
608 { "vif",NULL, X86_EFL_VIF },
609 { "ac", NULL, X86_EFL_AC },
610 { "vm", NULL, X86_EFL_VM },
611 { "rf", NULL, X86_EFL_RF },
612 { "nt", NULL, X86_EFL_NT },
613 { "ov", "nv", X86_EFL_OF },
614 { "dn", "up", X86_EFL_DF },
615 { "ei", "di", X86_EFL_IF },
616 { "tf", NULL, X86_EFL_TF },
617 { "nt", "pl", X86_EFL_SF },
618 { "nz", "zr", X86_EFL_ZF },
619 { "ac", "na", X86_EFL_AF },
620 { "po", "pe", X86_EFL_PF },
621 { "cy", "nc", X86_EFL_CF },
622 };
623 char *psz = pszEFlags;
624 for (unsigned i = 0; i < ELEMENTS(s_aFlags); i++)
625 {
626 const char *pszAdd = s_aFlags[i].fFlag & efl ? s_aFlags[i].pszSet : s_aFlags[i].pszClear;
627 if (pszAdd)
628 {
629 strcpy(psz, pszAdd);
630 psz += strlen(pszAdd);
631 *psz++ = ' ';
632 }
633 }
634 psz[-1] = '\0';
635}
636
637
638/**
639 * Formats a full register dump.
640 *
641 * @param pCtx The context to format.
642 * @param pCtxCore The context core to format.
643 * @param pHlp Output functions.
644 * @param enmType The dump type.
645 * @param pszPrefix Register name prefix.
646 */
647static void cpumR3InfoOne(PCPUMCTX pCtx, PCCPUMCTXCORE pCtxCore, PCDBGFINFOHLP pHlp, CPUMDUMPTYPE enmType, const char *pszPrefix)
648{
649 /*
650 * Format the EFLAGS.
651 */
652 uint32_t efl = pCtxCore->eflags.u32;
653 char szEFlags[80];
654 cpumR3InfoFormatFlags(&szEFlags[0], efl);
655
656 /*
657 * Format the registers.
658 */
659 switch (enmType)
660 {
661 case CPUMDUMPTYPE_TERSE:
662 pHlp->pfnPrintf(pHlp,
663 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
664 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
665 "%scs=%04x %sds=%04x %ses=%04x %sfs=%04x %sgs=%04x %seflags=%08x\n",
666 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,
667 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 33 : 31, szEFlags,
668 pszPrefix, (RTSEL)pCtxCore->cs, pszPrefix, (RTSEL)pCtxCore->ds, pszPrefix, (RTSEL)pCtxCore->es,
669 pszPrefix, (RTSEL)pCtxCore->fs, pszPrefix, (RTSEL)pCtxCore->gs, pszPrefix, efl);
670 break;
671
672 case CPUMDUMPTYPE_DEFAULT:
673 pHlp->pfnPrintf(pHlp,
674 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
675 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
676 "%scs=%04x %sds=%04x %ses=%04x %sfs=%04x %sgs=%04x %seflags=%08x\n"
677 "%scr0=%08x %scr2=%08x %scr3=%08x %scr4=%08x %sgdtr=%08x:%04x %sldtr=%04x\n"
678 ,
679 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,
680 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 33 : 31, szEFlags,
681 pszPrefix, (RTSEL)pCtxCore->cs, pszPrefix, (RTSEL)pCtxCore->ds, pszPrefix, (RTSEL)pCtxCore->es,
682 pszPrefix, (RTSEL)pCtxCore->fs, pszPrefix, (RTSEL)pCtxCore->gs, pszPrefix, efl,
683 pszPrefix, pCtx->cr0, pszPrefix, pCtx->cr2, pszPrefix, pCtx->cr3, pszPrefix, pCtx->cr4,
684 pszPrefix, pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt, pszPrefix, (RTSEL)pCtx->ldtr);
685 break;
686
687 case CPUMDUMPTYPE_VERBOSE:
688 pHlp->pfnPrintf(pHlp,
689 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
690 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
691 "%scs={%04x base=%08x limit=%08x flags=%08x} %sdr0=%08x %sdr1=%08x\n"
692 "%sds={%04x base=%08x limit=%08x flags=%08x} %sdr2=%08x %sdr3=%08x\n"
693 "%ses={%04x base=%08x limit=%08x flags=%08x} %sdr4=%08x %sdr5=%08x\n"
694 "%sfs={%04x base=%08x limit=%08x flags=%08x} %sdr6=%08x %sdr7=%08x\n"
695 "%sgs={%04x base=%08x limit=%08x flags=%08x} %scr0=%08x %scr2=%08x\n"
696 "%sss={%04x base=%08x limit=%08x flags=%08x} %scr3=%08x %scr4=%08x\n"
697 "%sgdtr=%08x:%04x %sidtr=%08x:%04x %seflags=%08x\n"
698 "%sldtr={%04x base=%08x limit=%08x flags=%08x}\n"
699 "%str ={%04x base=%08x limit=%08x flags=%08x}\n"
700 "%sSysEnter={cs=%04llx eip=%08llx esp=%08llx}\n"
701 "%sFCW=%04x %sFSW=%04x %sFTW=%04x\n"
702 ,
703 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,
704 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 33 : 31, szEFlags,
705 pszPrefix, (RTSEL)pCtxCore->cs, pCtx->csHid.u32Base, pCtx->csHid.u32Limit, pCtx->csHid.Attr.u, pszPrefix, pCtx->dr0, pszPrefix, pCtx->dr1,
706 pszPrefix, (RTSEL)pCtxCore->ds, pCtx->dsHid.u32Base, pCtx->dsHid.u32Limit, pCtx->dsHid.Attr.u, pszPrefix, pCtx->dr2, pszPrefix, pCtx->dr3,
707 pszPrefix, (RTSEL)pCtxCore->es, pCtx->esHid.u32Base, pCtx->esHid.u32Limit, pCtx->esHid.Attr.u, pszPrefix, pCtx->dr4, pszPrefix, pCtx->dr5,
708 pszPrefix, (RTSEL)pCtxCore->fs, pCtx->fsHid.u32Base, pCtx->fsHid.u32Limit, pCtx->fsHid.Attr.u, pszPrefix, pCtx->dr6, pszPrefix, pCtx->dr7,
709 pszPrefix, (RTSEL)pCtxCore->gs, pCtx->gsHid.u32Base, pCtx->gsHid.u32Limit, pCtx->gsHid.Attr.u, pszPrefix, pCtx->cr0, pszPrefix, pCtx->cr2,
710 pszPrefix, (RTSEL)pCtxCore->ss, pCtx->ssHid.u32Base, pCtx->ssHid.u32Limit, pCtx->ssHid.Attr.u, pszPrefix, pCtx->cr3, pszPrefix, pCtx->cr4,
711 pszPrefix, pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt, pszPrefix, pCtx->idtr.pIdt, pCtx->idtr.cbIdt, pszPrefix, efl,
712 pszPrefix, (RTSEL)pCtx->ldtr, pCtx->ldtrHid.u32Base, pCtx->ldtrHid.u32Limit, pCtx->ldtrHid.Attr.u,
713 pszPrefix, (RTSEL)pCtx->tr, pCtx->trHid.u32Base, pCtx->trHid.u32Limit, pCtx->trHid.Attr.u,
714 pszPrefix, pCtx->SysEnter.cs, pCtx->SysEnter.eip, pCtx->SysEnter.esp,
715 pszPrefix, pCtx->fpu.FCW, pszPrefix, pCtx->fpu.FSW, pszPrefix, pCtx->fpu.FTW);
716 break;
717 }
718}
719
720
721/**
722 * Display all cpu states and any other cpum info.
723 *
724 * @param pVM VM Handle.
725 * @param pHlp The info helper functions.
726 * @param pszArgs Arguments, ignored.
727 */
728static DECLCALLBACK(void) cpumR3InfoAll(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
729{
730 cpumR3InfoGuest(pVM, pHlp, pszArgs);
731 cpumR3InfoHyper(pVM, pHlp, pszArgs);
732 cpumR3InfoHost(pVM, pHlp, pszArgs);
733}
734
735
736/**
737 * Parses the info argument.
738 *
739 * The argument starts with 'verbose', 'terse' or 'default' and then
740 * continues with the comment string.
741 *
742 * @param pszArgs The pointer to the argument string.
743 * @param penmType Where to store the dump type request.
744 * @param ppszComment Where to store the pointer to the comment string.
745 */
746static void cpumR3InfoParseArg(const char *pszArgs, CPUMDUMPTYPE *penmType, const char **ppszComment)
747{
748 if (!pszArgs)
749 {
750 *penmType = CPUMDUMPTYPE_DEFAULT;
751 *ppszComment = "";
752 }
753 else
754 {
755 if (!strncmp(pszArgs, "verbose", sizeof("verbose") - 1))
756 {
757 pszArgs += 5;
758 *penmType = CPUMDUMPTYPE_VERBOSE;
759 }
760 else if (!strncmp(pszArgs, "terse", sizeof("terse") - 1))
761 {
762 pszArgs += 5;
763 *penmType = CPUMDUMPTYPE_TERSE;
764 }
765 else if (!strncmp(pszArgs, "default", sizeof("default") - 1))
766 {
767 pszArgs += 7;
768 *penmType = CPUMDUMPTYPE_DEFAULT;
769 }
770 else
771 *penmType = CPUMDUMPTYPE_DEFAULT;
772 *ppszComment = RTStrStripL(pszArgs);
773 }
774}
775
776
777/**
778 * Display the guest cpu state.
779 *
780 * @param pVM VM Handle.
781 * @param pHlp The info helper functions.
782 * @param pszArgs Arguments, ignored.
783 */
784static DECLCALLBACK(void) cpumR3InfoGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
785{
786 CPUMDUMPTYPE enmType;
787 const char *pszComment;
788 cpumR3InfoParseArg(pszArgs, &enmType, &pszComment);
789 pHlp->pfnPrintf(pHlp, "Guest CPUM state: %s\n", pszComment);
790 cpumR3InfoOne(&pVM->cpum.s.Guest, CPUMCTX2CORE(&pVM->cpum.s.Guest), pHlp, enmType, "");
791}
792
793
794/**
795 * Display the hypervisor cpu state.
796 *
797 * @param pVM VM Handle.
798 * @param pHlp The info helper functions.
799 * @param pszArgs Arguments, ignored.
800 */
801static DECLCALLBACK(void) cpumR3InfoHyper(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
802{
803 CPUMDUMPTYPE enmType;
804 const char *pszComment;
805 cpumR3InfoParseArg(pszArgs, &enmType, &pszComment);
806 pHlp->pfnPrintf(pHlp, "Hypervisor CPUM state: %s\n", pszComment);
807 cpumR3InfoOne(&pVM->cpum.s.Hyper, pVM->cpum.s.pHyperCoreHC, pHlp, enmType, ".");
808}
809
810
811/**
812 * Display the host cpu state.
813 *
814 * @param pVM VM Handle.
815 * @param pHlp The info helper functions.
816 * @param pszArgs Arguments, ignored.
817 */
818static DECLCALLBACK(void) cpumR3InfoHost(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
819{
820 CPUMDUMPTYPE enmType;
821 const char *pszComment;
822 cpumR3InfoParseArg(pszArgs, &enmType, &pszComment);
823 pHlp->pfnPrintf(pHlp, "Host CPUM state: %s\n", pszComment);
824
825 /*
826 * Format the EFLAGS.
827 */
828 PCPUMHOSTCTX pCtx = &pVM->cpum.s.Host;
829#if HC_ARCH_BITS == 32
830 uint32_t efl = pCtx->eflags.u32;
831#else
832 uint64_t efl = pCtx->rflags;
833#endif
834 char szEFlags[80];
835 cpumR3InfoFormatFlags(&szEFlags[0], efl);
836
837 /*
838 * Format the registers.
839 */
840#if HC_ARCH_BITS == 32
841 pHlp->pfnPrintf(pHlp,
842 "eax=xxxxxxxx ebx=%08x ecx=xxxxxxxx edx=xxxxxxxx esi=%08x edi=%08x\n"
843 "eip=xxxxxxxx esp=%08x ebp=%08x iopl=%d %31s\n"
844 "cs=%04x ds=%04x es=%04x fs=%04x gs=%04x eflags=%08x\n"
845 "cr0=%08x cr2=xxxxxxxx cr3=%08x cr4=%08x gdtr=%08x:%04x ldtr=%04x\n"
846 "dr0=%08x dr1=%08x dr2=%08x dr3=%08x dr6=%08x dr7=%08x\n"
847 "SysEnter={cs=%04x eip=%08x esp=%08x}\n"
848 ,
849 /*pCtx->eax,*/ pCtx->ebx, /*pCtx->ecx, pCtx->edx,*/ pCtx->esi, pCtx->edi,
850 /*pCtx->eip,*/ pCtx->esp, pCtx->ebp, X86_EFL_GET_IOPL(efl), szEFlags,
851 (RTSEL)pCtx->cs, (RTSEL)pCtx->ds, (RTSEL)pCtx->es, (RTSEL)pCtx->fs, (RTSEL)pCtx->gs, efl,
852 pCtx->cr0, /*pCtx->cr2,*/ pCtx->cr3, pCtx->cr4,
853 pCtx->dr0, pCtx->dr1, pCtx->dr2, pCtx->dr3, pCtx->dr6, pCtx->dr7,
854 pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt, (RTSEL)pCtx->ldtr,
855 pCtx->SysEnter.cs, pCtx->SysEnter.eip, pCtx->SysEnter.esp);
856#else /* 64-bit */
857 pHlp->pfnPrintf(pHlp,
858 "rax=xxxxxxxxxxxxxxxx rbx=%016RX64 rcx=xxxxxxxxxxxxxxxx\n"
859 "rdx=xxxxxxxxxxxxxxxx rsi=%016RX64 rdi=%016RX64\n"
860 "rip=xxxxxxxxxxxxxxxx rsp=%016RX64 rbp=%016RX64\n"
861 " r8=xxxxxxxxxxxxxxxx r9=xxxxxxxxxxxxxxxx r10=%016RX64\n"
862 "r11=%016RX64 r12=%016RX64 r13=%016RX64\n"
863 "r14=%016RX64 r15=%016RX64\n"
864 "iopl=%d %31s\n"
865 "cs=%04x ds=%04x es=%04x fs=%04x gs=%04x eflags=%08RX64\n"
866 "cr0=%016RX64 cr2=xxxxxxxxxxxxxxxx cr3=%016RX64\n"
867 "cr4=%016RX64 cr8=%016RX64 ldtr=%04x tr=%04x\n"
868 "dr0=%016RX64 dr1=%016RX64 dr2=%016RX64\n"
869 "dr3=%016RX64 dr6=%016RX64 dr7=%016RX64\n"
870 "gdtr=%016RX64:%04x idtr=%016RX64:%04x\n"
871 "SysEnter={cs=%04x eip=%08x esp=%08x}\n"
872 "FSbase=%016RX64 GSbase=%016RX64 efer=%08RX64\n"
873 ,
874 /*pCtx->rax,*/ pCtx->rbx, /*pCtx->rcx,
875 pCtx->rdx,*/ pCtx->rsi, pCtx->rdi,
876 /*pCtx->rip,*/ pCtx->rsp, pCtx->rbp,
877 /*pCtx->r8, pCtx->r9,*/ pCtx->r10,
878 pCtx->r11, pCtx->r12, pCtx->r13,
879 pCtx->r14, pCtx->r15,
880 X86_EFL_GET_IOPL(efl), szEFlags,
881 (RTSEL)pCtx->cs, (RTSEL)pCtx->ds, (RTSEL)pCtx->es, (RTSEL)pCtx->fs, (RTSEL)pCtx->gs, efl,
882 pCtx->cr0, /*pCtx->cr2,*/ pCtx->cr3,
883 pCtx->cr4, pCtx->cr8, pCtx->ldtr, pCtx->tr,
884 pCtx->dr0, pCtx->dr1, pCtx->dr2,
885 pCtx->dr3, pCtx->dr6, pCtx->dr7,
886 *(uint64_t *)&pCtx->gdtr[2], *(uint16_t *)&pCtx->gdtr[0], *(uint64_t *)&pCtx->idtr[2], *(uint16_t *)&pCtx->idtr[0],
887 pCtx->SysEnter.cs, pCtx->SysEnter.eip, pCtx->SysEnter.esp,
888 pCtx->FSbase, pCtx->GSbase, pCtx->efer);
889#endif
890}
891
892/**
893 * Get L1 cache / TLS associativity.
894 */
895static const char *getCacheAss(unsigned u, char *pszBuf)
896{
897 if (u == 0)
898 return "res0 ";
899 if (u == 1)
900 return "direct";
901 if (u >= 256)
902 return "???";
903
904 RTStrPrintf(pszBuf, 16, "%d way", u);
905 return pszBuf;
906}
907
908
909/**
910 * Get L2 cache soociativity.
911 */
912const char *getL2CacheAss(unsigned u)
913{
914 switch (u)
915 {
916 case 0: return "off ";
917 case 1: return "direct";
918 case 2: return "2 way ";
919 case 3: return "res3 ";
920 case 4: return "4 way ";
921 case 5: return "res5 ";
922 case 6: return "8 way ";
923 case 7: return "res7 ";
924 case 8: return "16 way";
925 case 9: return "res9 ";
926 case 10: return "res10 ";
927 case 11: return "res11 ";
928 case 12: return "res12 ";
929 case 13: return "res13 ";
930 case 14: return "res14 ";
931 case 15: return "fully ";
932 default:
933 return "????";
934 }
935}
936
937
938/**
939 * Display the guest CpuId leafs.
940 *
941 * @param pVM VM Handle.
942 * @param pHlp The info helper functions.
943 * @param pszArgs "terse", "default" or "verbose".
944 */
945static DECLCALLBACK(void) cpumR3CpuIdInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
946{
947 /*
948 * Parse the argument.
949 */
950 unsigned iVerbosity = 1;
951 if (pszArgs)
952 {
953 pszArgs = RTStrStripL(pszArgs);
954 if (!strcmp(pszArgs, "terse"))
955 iVerbosity--;
956 else if (!strcmp(pszArgs, "verbose"))
957 iVerbosity++;
958 }
959
960 /*
961 * Start cracking.
962 */
963 CPUMCPUID Host;
964 CPUMCPUID Guest;
965 unsigned cStdMax = pVM->cpum.s.aGuestCpuIdStd[0].eax;
966
967 pHlp->pfnPrintf(pHlp,
968 " RAW Standard CPUIDs\n"
969 " Function eax ebx ecx edx\n");
970 for (unsigned i = 0; i <= ELEMENTS(pVM->cpum.s.aGuestCpuIdStd); i++)
971 {
972 Guest = pVM->cpum.s.aGuestCpuIdStd[i];
973 ASMCpuId(i, &Host.eax, &Host.ebx, &Host.ecx, &Host.edx);
974
975 pHlp->pfnPrintf(pHlp,
976 "Gst: %08x %08x %08x %08x %08x%s\n"
977 "Hst: %08x %08x %08x %08x\n",
978 i, Guest.eax, Guest.ebx, Guest.ecx, Guest.edx,
979 i <= cStdMax ? "" : "*",
980 Host.eax, Host.ebx, Host.ecx, Host.edx);
981 }
982
983 /*
984 * If verbose, decode it.
985 */
986 if (iVerbosity)
987 {
988 Guest = pVM->cpum.s.aGuestCpuIdStd[0];
989 pHlp->pfnPrintf(pHlp,
990 "Name: %.04s%.04s%.04s\n"
991 "Supports: 0-%x\n",
992 &Guest.ebx, &Guest.edx, &Guest.ecx, Guest.eax);
993 }
994
995 /*
996 * Get Features.
997 */
998 if (cStdMax >= 1 && iVerbosity)
999 {
1000 Guest = pVM->cpum.s.aGuestCpuIdStd[1];
1001 uint32_t uEAX = Guest.eax;
1002
1003 pHlp->pfnPrintf(pHlp,
1004 "Family: %d \tExtended: %d \tEffectiv: %d\n"
1005 "Model: %d \tExtended: %d \tEffectiv: %d\n"
1006 "Stepping: %d\n"
1007 "APIC ID: %#04x\n"
1008 "Logical CPUs: %d\n"
1009 "CLFLUSH Size: %d\n"
1010 "Brand ID: %#04x\n",
1011 (uEAX >> 8) & 0xf, (uEAX >> 20) & 0x7f, ((uEAX >> 8) & 0xf) + (((uEAX >> 8) & 0xf) == 0xf ? (uEAX >> 20) & 0x7f : 0),
1012 (uEAX >> 4) & 0xf, (uEAX >> 16) & 0x0f, ((uEAX >> 4) & 0xf) | (((uEAX >> 4) & 0xf) == 0xf ? (uEAX >> 16) & 0x0f : 0),
1013 (uEAX >> 0) & 0xf,
1014 (Guest.ebx >> 24) & 0xff,
1015 (Guest.ebx >> 16) & 0xff,
1016 (Guest.ebx >> 8) & 0xff,
1017 (Guest.ebx >> 0) & 0xff);
1018 if (iVerbosity == 1)
1019 {
1020 uint32_t uEDX = Guest.edx;
1021 pHlp->pfnPrintf(pHlp, "Features EDX: ");
1022 if (uEDX & BIT(0)) pHlp->pfnPrintf(pHlp, " FPU");
1023 if (uEDX & BIT(1)) pHlp->pfnPrintf(pHlp, " VME");
1024 if (uEDX & BIT(2)) pHlp->pfnPrintf(pHlp, " DE");
1025 if (uEDX & BIT(3)) pHlp->pfnPrintf(pHlp, " PSE");
1026 if (uEDX & BIT(4)) pHlp->pfnPrintf(pHlp, " TSC");
1027 if (uEDX & BIT(5)) pHlp->pfnPrintf(pHlp, " MSR");
1028 if (uEDX & BIT(6)) pHlp->pfnPrintf(pHlp, " PAE");
1029 if (uEDX & BIT(7)) pHlp->pfnPrintf(pHlp, " MCE");
1030 if (uEDX & BIT(8)) pHlp->pfnPrintf(pHlp, " CX8");
1031 if (uEDX & BIT(9)) pHlp->pfnPrintf(pHlp, " APIC");
1032 if (uEDX & BIT(10)) pHlp->pfnPrintf(pHlp, " 10");
1033 if (uEDX & BIT(11)) pHlp->pfnPrintf(pHlp, " SEP");
1034 if (uEDX & BIT(12)) pHlp->pfnPrintf(pHlp, " MTRR");
1035 if (uEDX & BIT(13)) pHlp->pfnPrintf(pHlp, " PGE");
1036 if (uEDX & BIT(14)) pHlp->pfnPrintf(pHlp, " MCA");
1037 if (uEDX & BIT(15)) pHlp->pfnPrintf(pHlp, " CMOV");
1038 if (uEDX & BIT(16)) pHlp->pfnPrintf(pHlp, " PAT");
1039 if (uEDX & BIT(17)) pHlp->pfnPrintf(pHlp, " PSE36");
1040 if (uEDX & BIT(18)) pHlp->pfnPrintf(pHlp, " PSN");
1041 if (uEDX & BIT(19)) pHlp->pfnPrintf(pHlp, " CLFSH");
1042 if (uEDX & BIT(20)) pHlp->pfnPrintf(pHlp, " 20");
1043 if (uEDX & BIT(21)) pHlp->pfnPrintf(pHlp, " DS");
1044 if (uEDX & BIT(22)) pHlp->pfnPrintf(pHlp, " ACPI");
1045 if (uEDX & BIT(23)) pHlp->pfnPrintf(pHlp, " MMX");
1046 if (uEDX & BIT(24)) pHlp->pfnPrintf(pHlp, " FXSR");
1047 if (uEDX & BIT(25)) pHlp->pfnPrintf(pHlp, " SSE");
1048 if (uEDX & BIT(26)) pHlp->pfnPrintf(pHlp, " SSE2");
1049 if (uEDX & BIT(27)) pHlp->pfnPrintf(pHlp, " SS");
1050 if (uEDX & BIT(28)) pHlp->pfnPrintf(pHlp, " HTT");
1051 if (uEDX & BIT(29)) pHlp->pfnPrintf(pHlp, " TM");
1052 if (uEDX & BIT(30)) pHlp->pfnPrintf(pHlp, " 30");
1053 if (uEDX & BIT(31)) pHlp->pfnPrintf(pHlp, " PBE");
1054 pHlp->pfnPrintf(pHlp, "\n");
1055
1056 uint32_t uECX = Guest.ecx;
1057 pHlp->pfnPrintf(pHlp, "Features ECX: ");
1058 if (uECX & BIT(0)) pHlp->pfnPrintf(pHlp, " SSE3");
1059 if (uECX & BIT(1)) pHlp->pfnPrintf(pHlp, " 1");
1060 if (uECX & BIT(2)) pHlp->pfnPrintf(pHlp, " 2");
1061 if (uECX & BIT(3)) pHlp->pfnPrintf(pHlp, " MONITOR");
1062 if (uECX & BIT(4)) pHlp->pfnPrintf(pHlp, " DS-CPL");
1063 if (uECX & BIT(5)) pHlp->pfnPrintf(pHlp, " VMX");
1064 if (uECX & BIT(6)) pHlp->pfnPrintf(pHlp, " 6");
1065 if (uECX & BIT(7)) pHlp->pfnPrintf(pHlp, " EST");
1066 if (uECX & BIT(8)) pHlp->pfnPrintf(pHlp, " TM2");
1067 if (uECX & BIT(9)) pHlp->pfnPrintf(pHlp, " 9");
1068 if (uECX & BIT(10)) pHlp->pfnPrintf(pHlp, " CNXT-ID");
1069 if (uECX & BIT(11)) pHlp->pfnPrintf(pHlp, " 11");
1070 if (uECX & BIT(12)) pHlp->pfnPrintf(pHlp, " 12");
1071 if (uECX & BIT(13)) pHlp->pfnPrintf(pHlp, " CX16");
1072 for (unsigned iBit = 14; iBit < 32; iBit++)
1073 if (uECX & BIT(iBit))
1074 pHlp->pfnPrintf(pHlp, " %d", iBit);
1075 pHlp->pfnPrintf(pHlp, "\n");
1076 }
1077 else
1078 {
1079 ASMCpuId(1, &Host.eax, &Host.ebx, &Host.ecx, &Host.edx);
1080
1081 X86CPUIDFEATEDX EdxHost = *(PX86CPUIDFEATEDX)&Host.edx;
1082 X86CPUIDFEATECX EcxHost = *(PX86CPUIDFEATECX)&Host.ecx;
1083 X86CPUIDFEATEDX EdxGuest = *(PX86CPUIDFEATEDX)&Guest.edx;
1084 X86CPUIDFEATECX EcxGuest = *(PX86CPUIDFEATECX)&Guest.ecx;
1085
1086 pHlp->pfnPrintf(pHlp, "Mnemonic - Description = guest (host)\n");
1087 pHlp->pfnPrintf(pHlp, "FPU - x87 FPU on Chip = %d (%d)\n", EdxGuest.u1FPU, EdxHost.u1FPU);
1088 pHlp->pfnPrintf(pHlp, "VME - Virtual 8086 Mode Enhancements = %d (%d)\n", EdxGuest.u1VME, EdxHost.u1VME);
1089 pHlp->pfnPrintf(pHlp, "DE - Debugging extensions = %d (%d)\n", EdxGuest.u1DE, EdxHost.u1DE);
1090 pHlp->pfnPrintf(pHlp, "PSE - Page Size Extension = %d (%d)\n", EdxGuest.u1PSE, EdxHost.u1PSE);
1091 pHlp->pfnPrintf(pHlp, "TSC - Time Stamp Counter = %d (%d)\n", EdxGuest.u1TSC, EdxHost.u1TSC);
1092 pHlp->pfnPrintf(pHlp, "MSR - Model Specific Registers = %d (%d)\n", EdxGuest.u1MSR, EdxHost.u1MSR);
1093 pHlp->pfnPrintf(pHlp, "PAE - Physical Address Extension = %d (%d)\n", EdxGuest.u1PAE, EdxHost.u1PAE);
1094 pHlp->pfnPrintf(pHlp, "MCE - Machine Check Exception = %d (%d)\n", EdxGuest.u1MCE, EdxHost.u1MCE);
1095 pHlp->pfnPrintf(pHlp, "CX8 - CMPXCHG8B instruction = %d (%d)\n", EdxGuest.u1CX8, EdxHost.u1CX8);
1096 pHlp->pfnPrintf(pHlp, "APIC - APIC On-Chip = %d (%d)\n", EdxGuest.u1APIC, EdxHost.u1APIC);
1097 pHlp->pfnPrintf(pHlp, "Reserved = %d (%d)\n", EdxGuest.u1Reserved1, EdxHost.u1Reserved1);
1098 pHlp->pfnPrintf(pHlp, "SEP - SYSENTER and SYSEXIT = %d (%d)\n", EdxGuest.u1SEP, EdxHost.u1SEP);
1099 pHlp->pfnPrintf(pHlp, "MTRR - Memory Type Range Registers = %d (%d)\n", EdxGuest.u1MTRR, EdxHost.u1MTRR);
1100 pHlp->pfnPrintf(pHlp, "PGE - PTE Global Bit = %d (%d)\n", EdxGuest.u1PGE, EdxHost.u1PGE);
1101 pHlp->pfnPrintf(pHlp, "MCA - Machine Check Architecture = %d (%d)\n", EdxGuest.u1MCA, EdxHost.u1MCA);
1102 pHlp->pfnPrintf(pHlp, "CMOV - Conditional Move Instructions = %d (%d)\n", EdxGuest.u1CMOV, EdxHost.u1CMOV);
1103 pHlp->pfnPrintf(pHlp, "PAT - Page Attribute Table = %d (%d)\n", EdxGuest.u1PAT, EdxHost.u1PAT);
1104 pHlp->pfnPrintf(pHlp, "PSE-36 - 36-bit Page Size Extention = %d (%d)\n", EdxGuest.u1PSE36, EdxHost.u1PSE36);
1105 pHlp->pfnPrintf(pHlp, "PSN - Processor Serial Number = %d (%d)\n", EdxGuest.u1PSN, EdxHost.u1PSN);
1106 pHlp->pfnPrintf(pHlp, "CLFSH - CLFLUSH Instruction. = %d (%d)\n", EdxGuest.u1CLFSH, EdxHost.u1CLFSH);
1107 pHlp->pfnPrintf(pHlp, "Reserved = %d (%d)\n", EdxGuest.u1Reserved2, EdxHost.u1Reserved2);
1108 pHlp->pfnPrintf(pHlp, "DS - Debug Store = %d (%d)\n", EdxGuest.u1DS, EdxHost.u1DS);
1109 pHlp->pfnPrintf(pHlp, "ACPI - Thermal Mon. & Soft. Clock Ctrl.= %d (%d)\n", EdxGuest.u1ACPI, EdxHost.u1ACPI);
1110 pHlp->pfnPrintf(pHlp, "MMX - Intel MMX Technology = %d (%d)\n", EdxGuest.u1MMX, EdxHost.u1MMX);
1111 pHlp->pfnPrintf(pHlp, "FXSR - FXSAVE and FXRSTOR Instructions = %d (%d)\n", EdxGuest.u1FXSR, EdxHost.u1FXSR);
1112 pHlp->pfnPrintf(pHlp, "SSE - SSE Support = %d (%d)\n", EdxGuest.u1SSE, EdxHost.u1SSE);
1113 pHlp->pfnPrintf(pHlp, "SSE2 - SSE2 Support = %d (%d)\n", EdxGuest.u1SSE2, EdxHost.u1SSE2);
1114 pHlp->pfnPrintf(pHlp, "SS - Self Snoop = %d (%d)\n", EdxGuest.u1SS, EdxHost.u1SS);
1115 pHlp->pfnPrintf(pHlp, "HTT - Hyper-Threading Technolog = %d (%d)\n", EdxGuest.u1HTT, EdxHost.u1HTT);
1116 pHlp->pfnPrintf(pHlp, "TM - Thermal Monitor = %d (%d)\n", EdxGuest.u1TM, EdxHost.u1TM);
1117 pHlp->pfnPrintf(pHlp, "30 - Reserved = %d (%d)\n", EdxGuest.u1Reserved3, EdxHost.u1Reserved3);
1118 pHlp->pfnPrintf(pHlp, "PBE - Pending Break Enable = %d (%d)\n", EdxGuest.u1PBE, EdxHost.u1PBE);
1119
1120 pHlp->pfnPrintf(pHlp, "Supports SSE3 or not = %d (%d)\n", EcxGuest.u1SSE3, EcxHost.u1SSE3);
1121 pHlp->pfnPrintf(pHlp, "Reserved = %d (%d)\n", EcxGuest.u2Reserved1, EcxHost.u2Reserved1);
1122 pHlp->pfnPrintf(pHlp, "Supports MONITOR/MWAIT = %d (%d)\n", EcxGuest.u1Monitor, EcxHost.u1Monitor);
1123 pHlp->pfnPrintf(pHlp, "CPL-DS - CPL Qualified Debug Store = %d (%d)\n", EcxGuest.u1CPLDS, EcxHost.u1CPLDS);
1124 pHlp->pfnPrintf(pHlp, "VMX - Virtual Machine Technology = %d (%d)\n", EcxGuest.u1VMX, EcxHost.u1VMX);
1125 pHlp->pfnPrintf(pHlp, "Reserved = %d (%d)\n", EcxGuest.u1Reserved2, EcxHost.u1Reserved2);
1126 pHlp->pfnPrintf(pHlp, "Enh. SpeedStep Tech = %d (%d)\n", EcxGuest.u1EST, EcxHost.u1EST);
1127 pHlp->pfnPrintf(pHlp, "Terminal Monitor 2 = %d (%d)\n", EcxGuest.u1TM2, EcxHost.u1TM2);
1128 pHlp->pfnPrintf(pHlp, "Reserved = %d (%d)\n", EcxGuest.u1Reserved3, EcxHost.u1Reserved3);
1129 pHlp->pfnPrintf(pHlp, "L1 Context ID = %d (%d)\n", EcxGuest.u1CNTXID, EcxHost.u1CNTXID);
1130 pHlp->pfnPrintf(pHlp, "Reserved = %#x (%#x)\n",EcxGuest.u2Reserved4, EcxHost.u2Reserved4);
1131 pHlp->pfnPrintf(pHlp, "L1 Context ID = %d (%d)\n", EcxGuest.u1CNTXID, EcxHost.u1CNTXID);
1132 pHlp->pfnPrintf(pHlp, "Reserved = %#x (%#x)\n",EcxGuest.u18Reserved5, EcxHost.u18Reserved5);
1133 }
1134 }
1135 if (cStdMax >= 2 && iVerbosity)
1136 {
1137 /** @todo */
1138 }
1139
1140 /*
1141 * Extended.
1142 * Implemented after AMD specs.
1143 */
1144 unsigned cExtMax = pVM->cpum.s.aGuestCpuIdExt[0].eax & 0xffff;
1145
1146 pHlp->pfnPrintf(pHlp,
1147 "\n"
1148 " RAW Extended CPUIDs\n"
1149 " Function eax ebx ecx edx\n");
1150 for (unsigned i = 0; i <= ELEMENTS(pVM->cpum.s.aGuestCpuIdExt); i++)
1151 {
1152 Guest = pVM->cpum.s.aGuestCpuIdExt[i];
1153 ASMCpuId(0x80000000 | i, &Host.eax, &Host.ebx, &Host.ecx, &Host.edx);
1154
1155 pHlp->pfnPrintf(pHlp,
1156 "Gst: %08x %08x %08x %08x %08x%s\n"
1157 "Hst: %08x %08x %08x %08x\n",
1158 0x80000000 | i, Guest.eax, Guest.ebx, Guest.ecx, Guest.edx,
1159 i <= cExtMax ? "" : "*",
1160 Host.eax, Host.ebx, Host.ecx, Host.edx);
1161 }
1162
1163 /*
1164 * Understandable output
1165 */
1166 if (iVerbosity && cExtMax >= 0)
1167 {
1168 Guest = pVM->cpum.s.aGuestCpuIdExt[0];
1169 pHlp->pfnPrintf(pHlp,
1170 "Ext Name: %.4s%.4s%.4s\n"
1171 "Ext Supports: 0x80000000-%#010x\n",
1172 &Guest.ebx, &Guest.edx, &Guest.ecx, Guest.eax);
1173 }
1174
1175 if (iVerbosity && cExtMax >= 1)
1176 {
1177 Guest = pVM->cpum.s.aGuestCpuIdExt[1];
1178 uint32_t uEAX = Guest.eax;
1179 pHlp->pfnPrintf(pHlp,
1180 "Family: %d \tExtended: %d \tEffectiv: %d\n"
1181 "Model: %d \tExtended: %d \tEffectiv: %d\n"
1182 "Stepping: %d\n"
1183 "Brand ID: %#05x\n",
1184 (uEAX >> 8) & 0xf, (uEAX >> 20) & 0x7f, ((uEAX >> 8) & 0xf) + (((uEAX >> 8) & 0xf) == 0xf ? (uEAX >> 20) & 0x7f : 0),
1185 (uEAX >> 4) & 0xf, (uEAX >> 16) & 0x0f, ((uEAX >> 4) & 0xf) | (((uEAX >> 4) & 0xf) == 0xf ? (uEAX >> 16) & 0x0f : 0),
1186 (uEAX >> 0) & 0xf,
1187 Guest.ebx & 0xfff);
1188
1189 if (iVerbosity == 1)
1190 {
1191 uint32_t uEDX = Guest.edx;
1192 pHlp->pfnPrintf(pHlp, "Features EDX: ");
1193 if (uEDX & BIT(0)) pHlp->pfnPrintf(pHlp, " FPU");
1194 if (uEDX & BIT(1)) pHlp->pfnPrintf(pHlp, " VME");
1195 if (uEDX & BIT(2)) pHlp->pfnPrintf(pHlp, " DE");
1196 if (uEDX & BIT(3)) pHlp->pfnPrintf(pHlp, " PSE");
1197 if (uEDX & BIT(4)) pHlp->pfnPrintf(pHlp, " TSC");
1198 if (uEDX & BIT(5)) pHlp->pfnPrintf(pHlp, " MSR");
1199 if (uEDX & BIT(6)) pHlp->pfnPrintf(pHlp, " PAE");
1200 if (uEDX & BIT(7)) pHlp->pfnPrintf(pHlp, " MCE");
1201 if (uEDX & BIT(8)) pHlp->pfnPrintf(pHlp, " CX8");
1202 if (uEDX & BIT(9)) pHlp->pfnPrintf(pHlp, " APIC");
1203 if (uEDX & BIT(10)) pHlp->pfnPrintf(pHlp, " 10");
1204 if (uEDX & BIT(11)) pHlp->pfnPrintf(pHlp, " SCR");
1205 if (uEDX & BIT(12)) pHlp->pfnPrintf(pHlp, " MTRR");
1206 if (uEDX & BIT(13)) pHlp->pfnPrintf(pHlp, " PGE");
1207 if (uEDX & BIT(14)) pHlp->pfnPrintf(pHlp, " MCA");
1208 if (uEDX & BIT(15)) pHlp->pfnPrintf(pHlp, " CMOV");
1209 if (uEDX & BIT(16)) pHlp->pfnPrintf(pHlp, " PAT");
1210 if (uEDX & BIT(17)) pHlp->pfnPrintf(pHlp, " PSE36");
1211 if (uEDX & BIT(18)) pHlp->pfnPrintf(pHlp, " 18");
1212 if (uEDX & BIT(19)) pHlp->pfnPrintf(pHlp, " 19");
1213 if (uEDX & BIT(20)) pHlp->pfnPrintf(pHlp, " NX");
1214 if (uEDX & BIT(21)) pHlp->pfnPrintf(pHlp, " 21");
1215 if (uEDX & BIT(22)) pHlp->pfnPrintf(pHlp, " ExtMMX");
1216 if (uEDX & BIT(23)) pHlp->pfnPrintf(pHlp, " MMX");
1217 if (uEDX & BIT(24)) pHlp->pfnPrintf(pHlp, " FXSR");
1218 if (uEDX & BIT(25)) pHlp->pfnPrintf(pHlp, " FastFXSR");
1219 if (uEDX & BIT(26)) pHlp->pfnPrintf(pHlp, " 26");
1220 if (uEDX & BIT(27)) pHlp->pfnPrintf(pHlp, " RDTSCP");
1221 if (uEDX & BIT(28)) pHlp->pfnPrintf(pHlp, " 29");
1222 if (uEDX & BIT(29)) pHlp->pfnPrintf(pHlp, " LongMode");
1223 if (uEDX & BIT(30)) pHlp->pfnPrintf(pHlp, " Ext3DNow");
1224 if (uEDX & BIT(31)) pHlp->pfnPrintf(pHlp, " 3DNow");
1225 pHlp->pfnPrintf(pHlp, "\n");
1226
1227 uint32_t uECX = Guest.ecx;
1228 pHlp->pfnPrintf(pHlp, "Features ECX: ");
1229 if (uECX & BIT(0)) pHlp->pfnPrintf(pHlp, " LAHF/SAHF");
1230 if (uECX & BIT(1)) pHlp->pfnPrintf(pHlp, " CMPL");
1231 if (uECX & BIT(2)) pHlp->pfnPrintf(pHlp, " 2");
1232 if (uECX & BIT(3)) pHlp->pfnPrintf(pHlp, " SVM");
1233 if (uECX & BIT(4)) pHlp->pfnPrintf(pHlp, " CR8L");
1234 for (unsigned iBit = 5; iBit < 32; iBit++)
1235 if (uECX & BIT(iBit))
1236 pHlp->pfnPrintf(pHlp, " %d", iBit);
1237 pHlp->pfnPrintf(pHlp, "\n");
1238 }
1239 else
1240 {
1241 ASMCpuId(0x80000001, &Host.eax, &Host.ebx, &Host.ecx, &Host.edx);
1242
1243 uint32_t uEdxGst = Guest.edx;
1244 uint32_t uEdxHst = Host.edx;
1245 pHlp->pfnPrintf(pHlp, "Mnemonic - Description = guest (host)\n");
1246 pHlp->pfnPrintf(pHlp, "FPU - x87 FPU on Chip = %d (%d)\n", !!(uEdxGst & BIT( 0)), !!(uEdxHst & BIT( 0)));
1247 pHlp->pfnPrintf(pHlp, "VME - Virtual 8086 Mode Enhancements = %d (%d)\n", !!(uEdxGst & BIT( 1)), !!(uEdxHst & BIT( 1)));
1248 pHlp->pfnPrintf(pHlp, "DE - Debugging extensions = %d (%d)\n", !!(uEdxGst & BIT( 2)), !!(uEdxHst & BIT( 2)));
1249 pHlp->pfnPrintf(pHlp, "PSE - Page Size Extension = %d (%d)\n", !!(uEdxGst & BIT( 3)), !!(uEdxHst & BIT( 3)));
1250 pHlp->pfnPrintf(pHlp, "TSC - Time Stamp Counter = %d (%d)\n", !!(uEdxGst & BIT( 4)), !!(uEdxHst & BIT( 4)));
1251 pHlp->pfnPrintf(pHlp, "MSR - K86 Model Specific Registers = %d (%d)\n", !!(uEdxGst & BIT( 5)), !!(uEdxHst & BIT( 5)));
1252 pHlp->pfnPrintf(pHlp, "PAE - Physical Address Extension = %d (%d)\n", !!(uEdxGst & BIT( 6)), !!(uEdxHst & BIT( 6)));
1253 pHlp->pfnPrintf(pHlp, "MCE - Machine Check Exception = %d (%d)\n", !!(uEdxGst & BIT( 7)), !!(uEdxHst & BIT( 7)));
1254 pHlp->pfnPrintf(pHlp, "CX8 - CMPXCHG8B instruction = %d (%d)\n", !!(uEdxGst & BIT( 8)), !!(uEdxHst & BIT( 8)));
1255 pHlp->pfnPrintf(pHlp, "APIC - APIC On-Chip = %d (%d)\n", !!(uEdxGst & BIT( 9)), !!(uEdxHst & BIT( 9)));
1256 pHlp->pfnPrintf(pHlp, "10 - Reserved = %d (%d)\n", !!(uEdxGst & BIT(10)), !!(uEdxHst & BIT(10)));
1257 pHlp->pfnPrintf(pHlp, "SEP - SYSCALL and SYSRET = %d (%d)\n", !!(uEdxGst & BIT(11)), !!(uEdxHst & BIT(11)));
1258 pHlp->pfnPrintf(pHlp, "MTRR - Memory Type Range Registers = %d (%d)\n", !!(uEdxGst & BIT(12)), !!(uEdxHst & BIT(12)));
1259 pHlp->pfnPrintf(pHlp, "PGE - PTE Global Bit = %d (%d)\n", !!(uEdxGst & BIT(13)), !!(uEdxHst & BIT(13)));
1260 pHlp->pfnPrintf(pHlp, "MCA - Machine Check Architecture = %d (%d)\n", !!(uEdxGst & BIT(14)), !!(uEdxHst & BIT(14)));
1261 pHlp->pfnPrintf(pHlp, "CMOV - Conditional Move Instructions = %d (%d)\n", !!(uEdxGst & BIT(15)), !!(uEdxHst & BIT(15)));
1262 pHlp->pfnPrintf(pHlp, "PAT - Page Attribute Table = %d (%d)\n", !!(uEdxGst & BIT(16)), !!(uEdxHst & BIT(16)));
1263 pHlp->pfnPrintf(pHlp, "PSE-36 - 36-bit Page Size Extention = %d (%d)\n", !!(uEdxGst & BIT(17)), !!(uEdxHst & BIT(17)));
1264 pHlp->pfnPrintf(pHlp, "18 - Reserved = %d (%d)\n", !!(uEdxGst & BIT(18)), !!(uEdxHst & BIT(18)));
1265 pHlp->pfnPrintf(pHlp, "19 - Reserved = %d (%d)\n", !!(uEdxGst & BIT(19)), !!(uEdxHst & BIT(19)));
1266 pHlp->pfnPrintf(pHlp, "NX - No-Execute Page Protection = %d (%d)\n", !!(uEdxGst & BIT(20)), !!(uEdxHst & BIT(20)));
1267 pHlp->pfnPrintf(pHlp, "DS - Debug Store = %d (%d)\n", !!(uEdxGst & BIT(21)), !!(uEdxHst & BIT(21)));
1268 pHlp->pfnPrintf(pHlp, "AXMMX - AMD Extensions to MMX Instr. = %d (%d)\n", !!(uEdxGst & BIT(22)), !!(uEdxHst & BIT(22)));
1269 pHlp->pfnPrintf(pHlp, "MMX - Intel MMX Technology = %d (%d)\n", !!(uEdxGst & BIT(23)), !!(uEdxHst & BIT(23)));
1270 pHlp->pfnPrintf(pHlp, "FXSR - FXSAVE and FXRSTOR Instructions = %d (%d)\n", !!(uEdxGst & BIT(24)), !!(uEdxHst & BIT(24)));
1271 pHlp->pfnPrintf(pHlp, "?? - AMD fast FXSAVE and FXRSTOR Instr.= %d (%d)\n", !!(uEdxGst & BIT(25)), !!(uEdxHst & BIT(25)));
1272 pHlp->pfnPrintf(pHlp, "26 - Reserved = %d (%d)\n", !!(uEdxGst & BIT(26)), !!(uEdxHst & BIT(26)));
1273 pHlp->pfnPrintf(pHlp, "27 - Reserved = %d (%d)\n", !!(uEdxGst & BIT(27)), !!(uEdxHst & BIT(27)));
1274 pHlp->pfnPrintf(pHlp, "28 - Reserved = %d (%d)\n", !!(uEdxGst & BIT(28)), !!(uEdxHst & BIT(28)));
1275 pHlp->pfnPrintf(pHlp, "?? - AMD Long Mode = %d (%d)\n", !!(uEdxGst & BIT(29)), !!(uEdxHst & BIT(29)));
1276 pHlp->pfnPrintf(pHlp, "?? - AMD Extensions to 3DNow = %d (%d)\n", !!(uEdxGst & BIT(30)), !!(uEdxHst & BIT(30)));
1277 pHlp->pfnPrintf(pHlp, "?? - AMD 3DNow = %d (%d)\n", !!(uEdxGst & BIT(31)), !!(uEdxHst & BIT(31)));
1278
1279 uint32_t uEcxGst = Guest.ecx;
1280 uint32_t uEcxHst = Host.ecx;
1281 pHlp->pfnPrintf(pHlp, "LahfSahf - LAHF/SAHF in 64-bit mode = %d (%d)\n", !!(uEcxGst & BIT( 0)), !!(uEcxHst & BIT( 0)));
1282 pHlp->pfnPrintf(pHlp, "CmpLegacy - Core MP legacy mode (depr) = %d (%d)\n", !!(uEcxGst & BIT( 1)), !!(uEcxHst & BIT( 1)));
1283 pHlp->pfnPrintf(pHlp, "SVM - AMD VM Extensions = %d (%d)\n", !!(uEcxGst & BIT( 2)), !!(uEcxHst & BIT( 2)));
1284 pHlp->pfnPrintf(pHlp, "3 - Reserved = %d (%d)\n", !!(uEcxGst & BIT( 3)), !!(uEcxHst & BIT( 3)));
1285 pHlp->pfnPrintf(pHlp, "AltMovCR8 - LOCK MOV CR0 means MOV CR8 = %d (%d)\n", !!(uEcxGst & BIT( 4)), !!(uEcxHst & BIT( 4)));
1286 pHlp->pfnPrintf(pHlp, "31:5 - Reserved = %#x (%#x)\n", uEcxGst >> 5, uEcxHst >> 5);
1287 }
1288 }
1289
1290 if (iVerbosity && cExtMax >= 2)
1291 {
1292 char szString[4*4*3+1] = {0};
1293 uint32_t *pu32 = (uint32_t *)szString;
1294 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[2].eax;
1295 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[2].ebx;
1296 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[2].ecx;
1297 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[2].edx;
1298 if (cExtMax >= 3)
1299 {
1300 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[3].eax;
1301 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[3].ebx;
1302 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[3].ecx;
1303 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[3].edx;
1304 }
1305 if (cExtMax >= 4)
1306 {
1307 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[4].eax;
1308 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[4].ebx;
1309 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[4].ecx;
1310 *pu32++ = pVM->cpum.s.aGuestCpuIdExt[4].edx;
1311 }
1312 pHlp->pfnPrintf(pHlp, "Full Name: %s\n", szString);
1313 }
1314
1315 if (iVerbosity && cExtMax >= 5)
1316 {
1317 uint32_t uEAX = pVM->cpum.s.aGuestCpuIdExt[5].eax;
1318 uint32_t uEBX = pVM->cpum.s.aGuestCpuIdExt[5].ebx;
1319 uint32_t uECX = pVM->cpum.s.aGuestCpuIdExt[5].ecx;
1320 uint32_t uEDX = pVM->cpum.s.aGuestCpuIdExt[5].edx;
1321 char sz1[32];
1322 char sz2[32];
1323
1324 pHlp->pfnPrintf(pHlp,
1325 "TLB 2/4M Instr/Uni: %s %3d entries\n"
1326 "TLB 2/4M Data: %s %3d entries\n",
1327 getCacheAss((uEAX >> 8) & 0xff, sz1), (uEAX >> 0) & 0xff,
1328 getCacheAss((uEAX >> 24) & 0xff, sz2), (uEAX >> 16) & 0xff);
1329 pHlp->pfnPrintf(pHlp,
1330 "TLB 4K Instr/Uni: %s %3d entries\n"
1331 "TLB 4K Data: %s %3d entries\n",
1332 getCacheAss((uEBX >> 8) & 0xff, sz1), (uEBX >> 0) & 0xff,
1333 getCacheAss((uEBX >> 24) & 0xff, sz2), (uEBX >> 16) & 0xff);
1334 pHlp->pfnPrintf(pHlp, "L1 Instr Cache Line Size: %d bytes\n"
1335 "L1 Instr Cache Lines Per Tag: %d\n"
1336 "L1 Instr Cache Associativity: %s\n"
1337 "L1 Instr Cache Size: %d KB\n",
1338 (uEDX >> 0) & 0xff,
1339 (uEDX >> 8) & 0xff,
1340 getCacheAss((uEDX >> 16) & 0xff, sz1),
1341 (uEDX >> 24) & 0xff);
1342 pHlp->pfnPrintf(pHlp,
1343 "L1 Data Cache Line Size: %d bytes\n"
1344 "L1 Data Cache Lines Per Tag: %d\n"
1345 "L1 Data Cache Associativity: %s\n"
1346 "L1 Data Cache Size: %d KB\n",
1347 (uECX >> 0) & 0xff,
1348 (uECX >> 8) & 0xff,
1349 getCacheAss((uECX >> 16) & 0xff, sz1),
1350 (uECX >> 24) & 0xff);
1351 }
1352
1353 if (iVerbosity && cExtMax >= 6)
1354 {
1355 uint32_t uEAX = pVM->cpum.s.aGuestCpuIdExt[6].eax;
1356 uint32_t uEBX = pVM->cpum.s.aGuestCpuIdExt[6].ebx;
1357 uint32_t uEDX = pVM->cpum.s.aGuestCpuIdExt[6].edx;
1358
1359 pHlp->pfnPrintf(pHlp,
1360 "L2 TLB 2/4M Instr/Uni: %s %4d entries\n"
1361 "L2 TLB 2/4M Data: %s %4d entries\n",
1362 getL2CacheAss((uEAX >> 12) & 0xf), (uEAX >> 0) & 0xfff,
1363 getL2CacheAss((uEAX >> 28) & 0xf), (uEAX >> 16) & 0xfff);
1364 pHlp->pfnPrintf(pHlp,
1365 "L2 TLB 4K Instr/Uni: %s %4d entries\n"
1366 "L2 TLB 4K Data: %s %4d entries\n",
1367 getL2CacheAss((uEBX >> 12) & 0xf), (uEBX >> 0) & 0xfff,
1368 getL2CacheAss((uEBX >> 28) & 0xf), (uEBX >> 16) & 0xfff);
1369 pHlp->pfnPrintf(pHlp,
1370 "L2 Cache Line Size: %d bytes\n"
1371 "L2 Cache Lines Per Tag: %d\n"
1372 "L2 Cache Associativity: %s\n"
1373 "L2 Cache Size: %d KB\n",
1374 (uEDX >> 0) & 0xff,
1375 (uEDX >> 8) & 0xf,
1376 getL2CacheAss((uEDX >> 12) & 0xf),
1377 (uEDX >> 16) & 0xffff);
1378 }
1379
1380 if (iVerbosity && cExtMax >= 7)
1381 {
1382 uint32_t uEDX = pVM->cpum.s.aGuestCpuIdExt[7].edx;
1383
1384 pHlp->pfnPrintf(pHlp, "APM Features: ");
1385 if (uEDX & BIT(0)) pHlp->pfnPrintf(pHlp, " TS");
1386 if (uEDX & BIT(1)) pHlp->pfnPrintf(pHlp, " FID");
1387 if (uEDX & BIT(2)) pHlp->pfnPrintf(pHlp, " VID");
1388 if (uEDX & BIT(3)) pHlp->pfnPrintf(pHlp, " TTP");
1389 if (uEDX & BIT(4)) pHlp->pfnPrintf(pHlp, " TM");
1390 if (uEDX & BIT(5)) pHlp->pfnPrintf(pHlp, " STC");
1391 for (unsigned iBit = 6; iBit < 32; iBit++)
1392 if (uEDX & BIT(iBit))
1393 pHlp->pfnPrintf(pHlp, " %d", iBit);
1394 pHlp->pfnPrintf(pHlp, "\n");
1395 }
1396
1397 if (iVerbosity && cExtMax >= 8)
1398 {
1399 uint32_t uEAX = pVM->cpum.s.aGuestCpuIdExt[8].eax;
1400 uint32_t uECX = pVM->cpum.s.aGuestCpuIdExt[8].ecx;
1401
1402 pHlp->pfnPrintf(pHlp,
1403 "Physical Address Width: %d bits\n"
1404 "Virtual Address Width: %d bits\n",
1405 (uEAX >> 0) & 0xff,
1406 (uEAX >> 8) & 0xff);
1407 pHlp->pfnPrintf(pHlp,
1408 "Physical Core Count: %d\n",
1409 (uECX >> 0) & 0xff);
1410 }
1411}
1412
1413
1414/**
1415 * Structure used when disassembling and instructions in DBGF.
1416 * This is used so the reader function can get the stuff it needs.
1417 */
1418typedef struct CPUMDISASSTATE
1419{
1420 /** Pointer to the CPU structure. */
1421 PDISCPUSTATE pCpu;
1422 /** The VM handle. */
1423 PVM pVM;
1424 /** Pointer to the first byte in the segemnt. */
1425 RTGCUINTPTR GCPtrSegBase;
1426 /** Pointer to the byte after the end of the segment. (might have wrapped!) */
1427 RTGCUINTPTR GCPtrSegEnd;
1428 /** The size of the segment minus 1. */
1429 RTGCUINTPTR cbSegLimit;
1430 /** Pointer to the current page - HC Ptr. */
1431 void *pvPageHC;
1432 /** Pointer to the current page - GC Ptr. */
1433 RTGCPTR pvPageGC;
1434 /** The rc of the operation.
1435 *
1436 * @todo r=bird: it's rather annoying that we have to keep track of the status code of the operation.
1437 * When we've got time we should adjust the disassembler to use VBox status codes and not
1438 * boolean returns.
1439 */
1440 int rc;
1441} CPUMDISASSTATE, *PCPUMDISASSTATE;
1442
1443
1444/**
1445 * Instruction reader.
1446 *
1447 * @returns VBox status code. (Why this is a int32_t and not just an int is also beyond me.)
1448 * @param PtrSrc Address to read from.
1449 * In our case this is relative to the selector pointed to by the 2nd user argument of uDisCpu.
1450 * @param pu8Dst Where to store the bytes.
1451 * @param cbRead Number of bytes to read.
1452 * @param uDisCpu Pointer to the disassembler cpu state. (Why this is a VBOXHUINTPTR is beyond me...)
1453 * In this context it's always pointer to the Core of a DBGFDISASSTATE.
1454 * @todo r=bird: The status code should be an int. The PtrSrc should *NOT* be a RTHCUINTPTR. The uDisCpu could just as well be
1455 * declared as what it actually is a PDISCPUSTATE.
1456 */
1457static DECLCALLBACK(int32_t) cpumR3DisasInstrRead(RTHCUINTPTR PtrSrc, uint8_t *pu8Dst, uint32_t cbRead, RTHCUINTPTR uDisCpu)
1458{
1459 PDISCPUSTATE pCpu = (PDISCPUSTATE)uDisCpu;
1460 PCPUMDISASSTATE pState = (PCPUMDISASSTATE)pCpu->dwUserData[0]; /** @todo r=bird: Invalid prefix, dw='double word' which it isn't. Besides it's an array too. And btw. RTHCUINTPTR isn't the right thing either in a 32-bit host 64-bit guest situation */
1461 Assert(cbRead > 0);
1462 for (;;)
1463 {
1464 RTGCUINTPTR GCPtr = PtrSrc + pState->GCPtrSegBase;
1465
1466 /* Need to update the page translation? */
1467 if ( !pState->pvPageHC
1468 || (GCPtr >> PAGE_SHIFT) != (pState->pvPageGC >> PAGE_SHIFT))
1469 {
1470 /* translate the address */
1471 pState->pvPageGC = GCPtr & PAGE_BASE_GC_MASK;
1472 if (MMHyperIsInsideArea(pState->pVM, pState->pvPageGC))
1473 {
1474 pState->pvPageHC = MMHyperGC2HC(pState->pVM, pState->pvPageGC);
1475 if (!pState->pvPageHC)
1476 pState->rc = VERR_INVALID_POINTER;
1477 }
1478 else
1479 pState->rc = PGMPhysGCPtr2HCPtr(pState->pVM, pState->pvPageGC, &pState->pvPageHC);
1480 if (VBOX_FAILURE(pState->rc))
1481 {
1482 pState->pvPageHC = NULL;
1483 return pState->rc;
1484 }
1485 }
1486
1487 /* check the segemnt limit */
1488 if (PtrSrc > pState->cbSegLimit)
1489 return pState->rc = VERR_OUT_OF_SELECTOR_BOUNDS;
1490
1491 /* calc how much we can read */
1492 uint32_t cb = PAGE_SIZE - (GCPtr & PAGE_OFFSET_MASK);
1493 RTGCUINTPTR cbSeg = pState->GCPtrSegEnd - GCPtr;
1494 if (cb > cbSeg && !cbSeg)
1495 cb = cbSeg;
1496 if (cb > cbRead)
1497 cb = cbRead;
1498
1499 /* read and advance */
1500 memcpy(pu8Dst, (char *)pState->pvPageHC + (GCPtr & PAGE_OFFSET_MASK), cb);
1501 cbRead -= cb;
1502 if (!cbRead)
1503 return VINF_SUCCESS;
1504 pu8Dst += cb;
1505 PtrSrc += cb;
1506 }
1507}
1508
1509
1510/**
1511 * Disassemble an instruction and return the information in the provided structure.
1512 *
1513 * @returns VBox status code.
1514 * @param pVM VM Handle
1515 * @param pCtx CPU context
1516 * @param GCPtrPC Program counter (relative to CS) to disassemble from.
1517 * @param pCpu Disassembly state
1518 * @param pszPrefix String prefix for logging (debug only)
1519 *
1520 */
1521CPUMR3DECL(int) CPUMR3DisasmInstrCPU(PVM pVM, PCPUMCTX pCtx, RTGCPTR GCPtrPC, PDISCPUSTATE pCpu, const char *pszPrefix)
1522{
1523 CPUMDISASSTATE State;
1524 int rc;
1525
1526 State.pCpu = pCpu;
1527 State.pvPageGC = 0;
1528 State.pvPageHC = NULL;
1529 State.rc = VINF_SUCCESS;
1530 State.pVM = pVM;
1531 /*
1532 * Get selector information.
1533 */
1534 if (pCtx->eflags.Bits.u1VM == 0)
1535 {
1536 if (CPUMAreHiddenSelRegsValid(pVM))
1537 {
1538 State.GCPtrSegBase = pCtx->csHid.u32Base;
1539 State.GCPtrSegEnd = pCtx->csHid.u32Limit + 1 + (RTGCUINTPTR)pCtx->csHid.u32Base;
1540 State.cbSegLimit = pCtx->csHid.u32Limit;
1541 pCpu->mode = pCtx->csHid.Attr.n.u1DefBig ? CPUMODE_32BIT : CPUMODE_16BIT;
1542 }
1543 else
1544 {
1545 SELMSELINFO SelInfo;
1546
1547 rc = SELMR3GetShadowSelectorInfo(pVM, pCtx->cs, &SelInfo);
1548 if (!VBOX_SUCCESS(rc))
1549 {
1550 AssertMsgFailed(("SELMR3GetShadowSelectorInfo failed for %04X:%VGv rc=%d\n", pCtx->cs, GCPtrPC, rc));
1551 return rc;
1552 }
1553
1554 /*
1555 * Validate the selector.
1556 */
1557 rc = SELMSelInfoValidateCS(&SelInfo, pCtx->ss);
1558 if (!VBOX_SUCCESS(rc))
1559 {
1560 AssertMsgFailed(("SELMSelInfoValidateCS failed for %04X:%VGv rc=%d\n", pCtx->cs, GCPtrPC, rc));
1561 return rc;
1562 }
1563 State.GCPtrSegBase = SelInfo.GCPtrBase;
1564 State.GCPtrSegEnd = SelInfo.cbLimit + 1 + (RTGCUINTPTR)SelInfo.GCPtrBase;
1565 State.cbSegLimit = SelInfo.cbLimit;
1566 pCpu->mode = SelInfo.Raw.Gen.u1DefBig ? CPUMODE_32BIT : CPUMODE_16BIT;
1567 }
1568 }
1569 else
1570 {
1571 /* V86 mode */
1572 pCpu->mode = CPUMODE_16BIT; /* @todo */
1573 State.GCPtrSegBase = pCtx->cs * 16;
1574 State.GCPtrSegEnd = 0xFFFFFFFF;
1575 State.cbSegLimit = 0xFFFFFFFF;
1576 }
1577
1578 /*
1579 * Disassemble the instruction.
1580 */
1581 pCpu->pfnReadBytes = cpumR3DisasInstrRead;
1582 pCpu->dwUserData[0] = (uintptr_t)&State;
1583
1584 uint32_t cbInstr;
1585#ifdef LOG_ENABLED
1586 if (DISInstr(pCpu, GCPtrPC, 0, &cbInstr, NULL))
1587 {
1588#else
1589 char szOutput[160];
1590 if (DISInstr(pCpu, GCPtrPC, 0, &cbInstr, &szOutput[0]))
1591 {
1592 /* log it */
1593 if (pszPrefix)
1594 Log(("%s: %s", pszPrefix, szOutput));
1595 else
1596 Log(("%s", szOutput));
1597#endif
1598 return VINF_SUCCESS;
1599 }
1600
1601 /* DISInstr failure */
1602 if (VBOX_FAILURE(State.rc))
1603 {
1604 Log(("CPUMR3DisasmInstrCPU: DISInstr failed for %04X:%VGv rc=%Vrc\n", pCtx->cs, GCPtrPC, State.rc));
1605 return State.rc;
1606 }
1607 Log(("CPUMR3DisasmInstrCPU: DISInstr failed for %04X:%VGv\n", pCtx->cs, GCPtrPC));
1608 rc = VERR_GENERAL_FAILURE;
1609 return rc;
1610}
1611
1612
1613#ifdef DEBUG
1614/**
1615 * Disassemble an instruction and dump it to the log
1616 *
1617 * @returns VBox status code.
1618 * @param pVM VM Handle
1619 * @param pCtx CPU context
1620 * @param pc GC instruction pointer
1621 * @param prefix String prefix for logging
1622 * @deprecated Use DBGFR3DisasInstrCurrentLog().
1623 *
1624 */
1625CPUMR3DECL(void) CPUMR3DisasmInstr(PVM pVM, PCPUMCTX pCtx, RTGCPTR pc, char *prefix)
1626{
1627 DISCPUSTATE cpu;
1628
1629 CPUMR3DisasmInstrCPU(pVM, pCtx, pc, &cpu, prefix);
1630}
1631
1632/**
1633 * Disassemble an instruction and dump it to the log
1634 *
1635 * @returns VBox status code.
1636 * @param pVM VM Handle
1637 * @param pCtx CPU context
1638 * @param pc GC instruction pointer
1639 * @param prefix String prefix for logging
1640 * @param nrInstructions
1641 *
1642 */
1643CPUMR3DECL(void) CPUMR3DisasmBlock(PVM pVM, PCPUMCTX pCtx, RTGCPTR pc, char *prefix, int nrInstructions)
1644{
1645 for(int i=0;i<nrInstructions;i++)
1646 {
1647 DISCPUSTATE cpu;
1648
1649 CPUMR3DisasmInstrCPU(pVM, pCtx, pc, &cpu, prefix);
1650 pc += cpu.opsize;
1651 }
1652}
1653
1654#endif
1655
1656#ifdef DEBUG
1657/**
1658 * Debug helper - Saves guest context on raw mode entry (for fatal dump)
1659 *
1660 * @internal
1661 */
1662CPUMR3DECL(void) CPUMR3SaveEntryCtx(PVM pVM)
1663{
1664 pVM->cpum.s.GuestEntry = pVM->cpum.s.Guest;
1665}
1666#endif
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