VirtualBox

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

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

add information about number of logical processors and processor active mask to release log

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