VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp@ 22037

最後變更 在這個檔案從22037是 22037,由 vboxsync 提交於 16 年 前

VMM: correct report cores count, also expose more CPUID leaves by default

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 53.7 KB
 
1/* $Id: CPUMAllRegs.cpp 22037 2009-08-06 15:27:25Z vboxsync $ */
2/** @file
3 * CPUM - CPU Monitor(/Manager) - Getters and Setters.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_CPUM
27#include <VBox/cpum.h>
28#include <VBox/patm.h>
29#include <VBox/dbgf.h>
30#include <VBox/mm.h>
31#include "CPUMInternal.h"
32#include <VBox/vm.h>
33#include <VBox/err.h>
34#include <VBox/dis.h>
35#include <VBox/log.h>
36#include <VBox/hwaccm.h>
37#include <VBox/tm.h>
38#include <iprt/assert.h>
39#include <iprt/asm.h>
40#ifdef IN_RING3
41#include <iprt/thread.h>
42#endif
43
44/** Disable stack frame pointer generation here. */
45#if defined(_MSC_VER) && !defined(DEBUG)
46# pragma optimize("y", off)
47#endif
48
49
50/**
51 * Sets or resets an alternative hypervisor context core.
52 *
53 * This is called when we get a hypervisor trap set switch the context
54 * core with the trap frame on the stack. It is called again to reset
55 * back to the default context core when resuming hypervisor execution.
56 *
57 * @param pVCpu The VMCPU handle.
58 * @param pCtxCore Pointer to the alternative context core or NULL
59 * to go back to the default context core.
60 */
61VMMDECL(void) CPUMHyperSetCtxCore(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
62{
63 PVM pVM = pVCpu->CTX_SUFF(pVM);
64
65 LogFlow(("CPUMHyperSetCtxCore: %p/%p/%p -> %p\n", pVCpu->cpum.s.CTX_SUFF(pHyperCore), pCtxCore));
66 if (!pCtxCore)
67 {
68 pCtxCore = CPUMCTX2CORE(&pVCpu->cpum.s.Hyper);
69 pVCpu->cpum.s.pHyperCoreR3 = (R3PTRTYPE(PCPUMCTXCORE))VM_R3_ADDR(pVM, pCtxCore);
70 pVCpu->cpum.s.pHyperCoreR0 = (R0PTRTYPE(PCPUMCTXCORE))VM_R0_ADDR(pVM, pCtxCore);
71 pVCpu->cpum.s.pHyperCoreRC = (RCPTRTYPE(PCPUMCTXCORE))VM_RC_ADDR(pVM, pCtxCore);
72 }
73 else
74 {
75 pVCpu->cpum.s.pHyperCoreR3 = (R3PTRTYPE(PCPUMCTXCORE))MMHyperCCToR3(pVM, pCtxCore);
76 pVCpu->cpum.s.pHyperCoreR0 = (R0PTRTYPE(PCPUMCTXCORE))MMHyperCCToR0(pVM, pCtxCore);
77 pVCpu->cpum.s.pHyperCoreRC = (RCPTRTYPE(PCPUMCTXCORE))MMHyperCCToRC(pVM, pCtxCore);
78 }
79}
80
81
82/**
83 * Gets the pointer to the internal CPUMCTXCORE structure for the hypervisor.
84 * This is only for reading in order to save a few calls.
85 *
86 * @param pVM Handle to the virtual machine.
87 */
88VMMDECL(PCCPUMCTXCORE) CPUMGetHyperCtxCore(PVMCPU pVCpu)
89{
90 return pVCpu->cpum.s.CTX_SUFF(pHyperCore);
91}
92
93
94/**
95 * Queries the pointer to the internal CPUMCTX structure for the hypervisor.
96 *
97 * @returns VBox status code.
98 * @param pVM Handle to the virtual machine.
99 * @param ppCtx Receives the hyper CPUMCTX pointer when successful.
100 *
101 * @deprecated This will *not* (and has never) given the right picture of the
102 * hypervisor register state. With CPUMHyperSetCtxCore() this is
103 * getting much worse. So, use the individual functions for getting
104 * and esp. setting the hypervisor registers.
105 */
106VMMDECL(int) CPUMQueryHyperCtxPtr(PVMCPU pVCpu, PCPUMCTX *ppCtx)
107{
108 *ppCtx = &pVCpu->cpum.s.Hyper;
109 return VINF_SUCCESS;
110}
111
112
113VMMDECL(void) CPUMSetHyperGDTR(PVMCPU pVCpu, uint32_t addr, uint16_t limit)
114{
115 pVCpu->cpum.s.Hyper.gdtr.cbGdt = limit;
116 pVCpu->cpum.s.Hyper.gdtr.pGdt = addr;
117 pVCpu->cpum.s.Hyper.gdtrPadding = 0;
118}
119
120
121VMMDECL(void) CPUMSetHyperIDTR(PVMCPU pVCpu, uint32_t addr, uint16_t limit)
122{
123 pVCpu->cpum.s.Hyper.idtr.cbIdt = limit;
124 pVCpu->cpum.s.Hyper.idtr.pIdt = addr;
125 pVCpu->cpum.s.Hyper.idtrPadding = 0;
126}
127
128
129VMMDECL(void) CPUMSetHyperCR3(PVMCPU pVCpu, uint32_t cr3)
130{
131 pVCpu->cpum.s.Hyper.cr3 = cr3;
132
133#ifdef IN_RC
134 /* Update the current CR3. */
135 ASMSetCR3(cr3);
136#endif
137}
138
139VMMDECL(uint32_t) CPUMGetHyperCR3(PVMCPU pVCpu)
140{
141 return pVCpu->cpum.s.Hyper.cr3;
142}
143
144
145VMMDECL(void) CPUMSetHyperCS(PVMCPU pVCpu, RTSEL SelCS)
146{
147 pVCpu->cpum.s.CTX_SUFF(pHyperCore)->cs = SelCS;
148}
149
150
151VMMDECL(void) CPUMSetHyperDS(PVMCPU pVCpu, RTSEL SelDS)
152{
153 pVCpu->cpum.s.CTX_SUFF(pHyperCore)->ds = SelDS;
154}
155
156
157VMMDECL(void) CPUMSetHyperES(PVMCPU pVCpu, RTSEL SelES)
158{
159 pVCpu->cpum.s.CTX_SUFF(pHyperCore)->es = SelES;
160}
161
162
163VMMDECL(void) CPUMSetHyperFS(PVMCPU pVCpu, RTSEL SelFS)
164{
165 pVCpu->cpum.s.CTX_SUFF(pHyperCore)->fs = SelFS;
166}
167
168
169VMMDECL(void) CPUMSetHyperGS(PVMCPU pVCpu, RTSEL SelGS)
170{
171 pVCpu->cpum.s.CTX_SUFF(pHyperCore)->gs = SelGS;
172}
173
174
175VMMDECL(void) CPUMSetHyperSS(PVMCPU pVCpu, RTSEL SelSS)
176{
177 pVCpu->cpum.s.CTX_SUFF(pHyperCore)->ss = SelSS;
178}
179
180
181VMMDECL(void) CPUMSetHyperESP(PVMCPU pVCpu, uint32_t u32ESP)
182{
183 pVCpu->cpum.s.CTX_SUFF(pHyperCore)->esp = u32ESP;
184}
185
186
187VMMDECL(int) CPUMSetHyperEFlags(PVMCPU pVCpu, uint32_t Efl)
188{
189 pVCpu->cpum.s.CTX_SUFF(pHyperCore)->eflags.u32 = Efl;
190 return VINF_SUCCESS;
191}
192
193
194VMMDECL(void) CPUMSetHyperEIP(PVMCPU pVCpu, uint32_t u32EIP)
195{
196 pVCpu->cpum.s.CTX_SUFF(pHyperCore)->eip = u32EIP;
197}
198
199
200VMMDECL(void) CPUMSetHyperTR(PVMCPU pVCpu, RTSEL SelTR)
201{
202 pVCpu->cpum.s.Hyper.tr = SelTR;
203}
204
205
206VMMDECL(void) CPUMSetHyperLDTR(PVMCPU pVCpu, RTSEL SelLDTR)
207{
208 pVCpu->cpum.s.Hyper.ldtr = SelLDTR;
209}
210
211
212VMMDECL(void) CPUMSetHyperDR0(PVMCPU pVCpu, RTGCUINTREG uDr0)
213{
214 pVCpu->cpum.s.Hyper.dr[0] = uDr0;
215 /** @todo in GC we must load it! */
216}
217
218
219VMMDECL(void) CPUMSetHyperDR1(PVMCPU pVCpu, RTGCUINTREG uDr1)
220{
221 pVCpu->cpum.s.Hyper.dr[1] = uDr1;
222 /** @todo in GC we must load it! */
223}
224
225
226VMMDECL(void) CPUMSetHyperDR2(PVMCPU pVCpu, RTGCUINTREG uDr2)
227{
228 pVCpu->cpum.s.Hyper.dr[2] = uDr2;
229 /** @todo in GC we must load it! */
230}
231
232
233VMMDECL(void) CPUMSetHyperDR3(PVMCPU pVCpu, RTGCUINTREG uDr3)
234{
235 pVCpu->cpum.s.Hyper.dr[3] = uDr3;
236 /** @todo in GC we must load it! */
237}
238
239
240VMMDECL(void) CPUMSetHyperDR6(PVMCPU pVCpu, RTGCUINTREG uDr6)
241{
242 pVCpu->cpum.s.Hyper.dr[6] = uDr6;
243 /** @todo in GC we must load it! */
244}
245
246
247VMMDECL(void) CPUMSetHyperDR7(PVMCPU pVCpu, RTGCUINTREG uDr7)
248{
249 pVCpu->cpum.s.Hyper.dr[7] = uDr7;
250 /** @todo in GC we must load it! */
251}
252
253
254VMMDECL(RTSEL) CPUMGetHyperCS(PVMCPU pVCpu)
255{
256 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->cs;
257}
258
259
260VMMDECL(RTSEL) CPUMGetHyperDS(PVMCPU pVCpu)
261{
262 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->ds;
263}
264
265
266VMMDECL(RTSEL) CPUMGetHyperES(PVMCPU pVCpu)
267{
268 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->es;
269}
270
271
272VMMDECL(RTSEL) CPUMGetHyperFS(PVMCPU pVCpu)
273{
274 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->fs;
275}
276
277
278VMMDECL(RTSEL) CPUMGetHyperGS(PVMCPU pVCpu)
279{
280 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->gs;
281}
282
283
284VMMDECL(RTSEL) CPUMGetHyperSS(PVMCPU pVCpu)
285{
286 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->ss;
287}
288
289
290VMMDECL(uint32_t) CPUMGetHyperEAX(PVMCPU pVCpu)
291{
292 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->eax;
293}
294
295
296VMMDECL(uint32_t) CPUMGetHyperEBX(PVMCPU pVCpu)
297{
298 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->ebx;
299}
300
301
302VMMDECL(uint32_t) CPUMGetHyperECX(PVMCPU pVCpu)
303{
304 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->ecx;
305}
306
307
308VMMDECL(uint32_t) CPUMGetHyperEDX(PVMCPU pVCpu)
309{
310 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->edx;
311}
312
313
314VMMDECL(uint32_t) CPUMGetHyperESI(PVMCPU pVCpu)
315{
316 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->esi;
317}
318
319
320VMMDECL(uint32_t) CPUMGetHyperEDI(PVMCPU pVCpu)
321{
322 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->edi;
323}
324
325
326VMMDECL(uint32_t) CPUMGetHyperEBP(PVMCPU pVCpu)
327{
328 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->ebp;
329}
330
331
332VMMDECL(uint32_t) CPUMGetHyperESP(PVMCPU pVCpu)
333{
334 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->esp;
335}
336
337
338VMMDECL(uint32_t) CPUMGetHyperEFlags(PVMCPU pVCpu)
339{
340 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->eflags.u32;
341}
342
343
344VMMDECL(uint32_t) CPUMGetHyperEIP(PVMCPU pVCpu)
345{
346 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->eip;
347}
348
349
350VMMDECL(uint64_t) CPUMGetHyperRIP(PVMCPU pVCpu)
351{
352 return pVCpu->cpum.s.CTX_SUFF(pHyperCore)->rip;
353}
354
355
356VMMDECL(uint32_t) CPUMGetHyperIDTR(PVMCPU pVCpu, uint16_t *pcbLimit)
357{
358 if (pcbLimit)
359 *pcbLimit = pVCpu->cpum.s.Hyper.idtr.cbIdt;
360 return pVCpu->cpum.s.Hyper.idtr.pIdt;
361}
362
363
364VMMDECL(uint32_t) CPUMGetHyperGDTR(PVMCPU pVCpu, uint16_t *pcbLimit)
365{
366 if (pcbLimit)
367 *pcbLimit = pVCpu->cpum.s.Hyper.gdtr.cbGdt;
368 return pVCpu->cpum.s.Hyper.gdtr.pGdt;
369}
370
371
372VMMDECL(RTSEL) CPUMGetHyperLDTR(PVMCPU pVCpu)
373{
374 return pVCpu->cpum.s.Hyper.ldtr;
375}
376
377
378VMMDECL(RTGCUINTREG) CPUMGetHyperDR0(PVMCPU pVCpu)
379{
380 return pVCpu->cpum.s.Hyper.dr[0];
381}
382
383
384VMMDECL(RTGCUINTREG) CPUMGetHyperDR1(PVMCPU pVCpu)
385{
386 return pVCpu->cpum.s.Hyper.dr[1];
387}
388
389
390VMMDECL(RTGCUINTREG) CPUMGetHyperDR2(PVMCPU pVCpu)
391{
392 return pVCpu->cpum.s.Hyper.dr[2];
393}
394
395
396VMMDECL(RTGCUINTREG) CPUMGetHyperDR3(PVMCPU pVCpu)
397{
398 return pVCpu->cpum.s.Hyper.dr[3];
399}
400
401
402VMMDECL(RTGCUINTREG) CPUMGetHyperDR6(PVMCPU pVCpu)
403{
404 return pVCpu->cpum.s.Hyper.dr[6];
405}
406
407
408VMMDECL(RTGCUINTREG) CPUMGetHyperDR7(PVMCPU pVCpu)
409{
410 return pVCpu->cpum.s.Hyper.dr[7];
411}
412
413
414/**
415 * Gets the pointer to the internal CPUMCTXCORE structure.
416 * This is only for reading in order to save a few calls.
417 *
418 * @param pVCpu Handle to the virtual cpu.
419 */
420VMMDECL(PCCPUMCTXCORE) CPUMGetGuestCtxCore(PVMCPU pVCpu)
421{
422 return CPUMCTX2CORE(&pVCpu->cpum.s.Guest);
423}
424
425
426/**
427 * Sets the guest context core registers.
428 *
429 * @param pVCpu Handle to the virtual cpu.
430 * @param pCtxCore The new context core values.
431 */
432VMMDECL(void) CPUMSetGuestCtxCore(PVMCPU pVCpu, PCCPUMCTXCORE pCtxCore)
433{
434 /** @todo #1410 requires selectors to be checked. (huh? 1410?) */
435
436 PCPUMCTXCORE pCtxCoreDst = CPUMCTX2CORE(&pVCpu->cpum.s.Guest);
437 *pCtxCoreDst = *pCtxCore;
438
439 /* Mask away invalid parts of the cpu context. */
440 if (!CPUMIsGuestInLongMode(pVCpu))
441 {
442 uint64_t u64Mask = UINT64_C(0xffffffff);
443
444 pCtxCoreDst->rip &= u64Mask;
445 pCtxCoreDst->rax &= u64Mask;
446 pCtxCoreDst->rbx &= u64Mask;
447 pCtxCoreDst->rcx &= u64Mask;
448 pCtxCoreDst->rdx &= u64Mask;
449 pCtxCoreDst->rsi &= u64Mask;
450 pCtxCoreDst->rdi &= u64Mask;
451 pCtxCoreDst->rbp &= u64Mask;
452 pCtxCoreDst->rsp &= u64Mask;
453 pCtxCoreDst->rflags.u &= u64Mask;
454
455 pCtxCoreDst->r8 = 0;
456 pCtxCoreDst->r9 = 0;
457 pCtxCoreDst->r10 = 0;
458 pCtxCoreDst->r11 = 0;
459 pCtxCoreDst->r12 = 0;
460 pCtxCoreDst->r13 = 0;
461 pCtxCoreDst->r14 = 0;
462 pCtxCoreDst->r15 = 0;
463 }
464}
465
466
467/**
468 * Queries the pointer to the internal CPUMCTX structure
469 *
470 * @returns The CPUMCTX pointer.
471 * @param pVCpu Handle to the virtual cpu.
472 */
473VMMDECL(PCPUMCTX) CPUMQueryGuestCtxPtr(PVMCPU pVCpu)
474{
475 return &pVCpu->cpum.s.Guest;
476}
477
478VMMDECL(int) CPUMSetGuestGDTR(PVMCPU pVCpu, uint32_t addr, uint16_t limit)
479{
480 pVCpu->cpum.s.Guest.gdtr.cbGdt = limit;
481 pVCpu->cpum.s.Guest.gdtr.pGdt = addr;
482 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_GDTR;
483 return VINF_SUCCESS;
484}
485
486VMMDECL(int) CPUMSetGuestIDTR(PVMCPU pVCpu, uint32_t addr, uint16_t limit)
487{
488 pVCpu->cpum.s.Guest.idtr.cbIdt = limit;
489 pVCpu->cpum.s.Guest.idtr.pIdt = addr;
490 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_IDTR;
491 return VINF_SUCCESS;
492}
493
494VMMDECL(int) CPUMSetGuestTR(PVMCPU pVCpu, uint16_t tr)
495{
496 AssertMsgFailed(("Need to load the hidden bits too!\n"));
497
498 pVCpu->cpum.s.Guest.tr = tr;
499 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_TR;
500 return VINF_SUCCESS;
501}
502
503VMMDECL(int) CPUMSetGuestLDTR(PVMCPU pVCpu, uint16_t ldtr)
504{
505 pVCpu->cpum.s.Guest.ldtr = ldtr;
506 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_LDTR;
507 return VINF_SUCCESS;
508}
509
510
511/**
512 * Set the guest CR0.
513 *
514 * When called in GC, the hyper CR0 may be updated if that is
515 * required. The caller only has to take special action if AM,
516 * WP, PG or PE changes.
517 *
518 * @returns VINF_SUCCESS (consider it void).
519 * @param pVCpu Handle to the virtual cpu.
520 * @param cr0 The new CR0 value.
521 */
522VMMDECL(int) CPUMSetGuestCR0(PVMCPU pVCpu, uint64_t cr0)
523{
524#ifdef IN_RC
525 /*
526 * Check if we need to change hypervisor CR0 because
527 * of math stuff.
528 */
529 if ( (cr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP))
530 != (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)))
531 {
532 if (!(pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU))
533 {
534 /*
535 * We haven't saved the host FPU state yet, so TS and MT are both set
536 * and EM should be reflecting the guest EM (it always does this).
537 */
538 if ((cr0 & X86_CR0_EM) != (pVCpu->cpum.s.Guest.cr0 & X86_CR0_EM))
539 {
540 uint32_t HyperCR0 = ASMGetCR0();
541 AssertMsg((HyperCR0 & (X86_CR0_TS | X86_CR0_MP)) == (X86_CR0_TS | X86_CR0_MP), ("%#x\n", HyperCR0));
542 AssertMsg((HyperCR0 & X86_CR0_EM) == (pVCpu->cpum.s.Guest.cr0 & X86_CR0_EM), ("%#x\n", HyperCR0));
543 HyperCR0 &= ~X86_CR0_EM;
544 HyperCR0 |= cr0 & X86_CR0_EM;
545 Log(("CPUM New HyperCR0=%#x\n", HyperCR0));
546 ASMSetCR0(HyperCR0);
547 }
548# ifdef VBOX_STRICT
549 else
550 {
551 uint32_t HyperCR0 = ASMGetCR0();
552 AssertMsg((HyperCR0 & (X86_CR0_TS | X86_CR0_MP)) == (X86_CR0_TS | X86_CR0_MP), ("%#x\n", HyperCR0));
553 AssertMsg((HyperCR0 & X86_CR0_EM) == (pVCpu->cpum.s.Guest.cr0 & X86_CR0_EM), ("%#x\n", HyperCR0));
554 }
555# endif
556 }
557 else
558 {
559 /*
560 * Already saved the state, so we're just mirroring
561 * the guest flags.
562 */
563 uint32_t HyperCR0 = ASMGetCR0();
564 AssertMsg( (HyperCR0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP))
565 == (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)),
566 ("%#x %#x\n", HyperCR0, pVCpu->cpum.s.Guest.cr0));
567 HyperCR0 &= ~(X86_CR0_TS | X86_CR0_EM | X86_CR0_MP);
568 HyperCR0 |= cr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP);
569 Log(("CPUM New HyperCR0=%#x\n", HyperCR0));
570 ASMSetCR0(HyperCR0);
571 }
572 }
573#endif /* IN_RC */
574
575 /*
576 * Check for changes causing TLB flushes (for REM).
577 * The caller is responsible for calling PGM when appropriate.
578 */
579 if ( (cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
580 != (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)))
581 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_GLOBAL_TLB_FLUSH;
582 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CR0;
583
584 pVCpu->cpum.s.Guest.cr0 = cr0 | X86_CR0_ET;
585 return VINF_SUCCESS;
586}
587
588
589VMMDECL(int) CPUMSetGuestCR2(PVMCPU pVCpu, uint64_t cr2)
590{
591 pVCpu->cpum.s.Guest.cr2 = cr2;
592 return VINF_SUCCESS;
593}
594
595
596VMMDECL(int) CPUMSetGuestCR3(PVMCPU pVCpu, uint64_t cr3)
597{
598 pVCpu->cpum.s.Guest.cr3 = cr3;
599 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CR3;
600 return VINF_SUCCESS;
601}
602
603
604VMMDECL(int) CPUMSetGuestCR4(PVMCPU pVCpu, uint64_t cr4)
605{
606 if ( (cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE))
607 != (pVCpu->cpum.s.Guest.cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE)))
608 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_GLOBAL_TLB_FLUSH;
609 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CR4;
610 if (!CPUMSupportsFXSR(pVCpu->CTX_SUFF(pVM)))
611 cr4 &= ~X86_CR4_OSFSXR;
612 pVCpu->cpum.s.Guest.cr4 = cr4;
613 return VINF_SUCCESS;
614}
615
616
617VMMDECL(int) CPUMSetGuestEFlags(PVMCPU pVCpu, uint32_t eflags)
618{
619 pVCpu->cpum.s.Guest.eflags.u32 = eflags;
620 return VINF_SUCCESS;
621}
622
623
624VMMDECL(int) CPUMSetGuestEIP(PVMCPU pVCpu, uint32_t eip)
625{
626 pVCpu->cpum.s.Guest.eip = eip;
627 return VINF_SUCCESS;
628}
629
630
631VMMDECL(int) CPUMSetGuestEAX(PVMCPU pVCpu, uint32_t eax)
632{
633 pVCpu->cpum.s.Guest.eax = eax;
634 return VINF_SUCCESS;
635}
636
637
638VMMDECL(int) CPUMSetGuestEBX(PVMCPU pVCpu, uint32_t ebx)
639{
640 pVCpu->cpum.s.Guest.ebx = ebx;
641 return VINF_SUCCESS;
642}
643
644
645VMMDECL(int) CPUMSetGuestECX(PVMCPU pVCpu, uint32_t ecx)
646{
647 pVCpu->cpum.s.Guest.ecx = ecx;
648 return VINF_SUCCESS;
649}
650
651
652VMMDECL(int) CPUMSetGuestEDX(PVMCPU pVCpu, uint32_t edx)
653{
654 pVCpu->cpum.s.Guest.edx = edx;
655 return VINF_SUCCESS;
656}
657
658
659VMMDECL(int) CPUMSetGuestESP(PVMCPU pVCpu, uint32_t esp)
660{
661 pVCpu->cpum.s.Guest.esp = esp;
662 return VINF_SUCCESS;
663}
664
665
666VMMDECL(int) CPUMSetGuestEBP(PVMCPU pVCpu, uint32_t ebp)
667{
668 pVCpu->cpum.s.Guest.ebp = ebp;
669 return VINF_SUCCESS;
670}
671
672
673VMMDECL(int) CPUMSetGuestESI(PVMCPU pVCpu, uint32_t esi)
674{
675 pVCpu->cpum.s.Guest.esi = esi;
676 return VINF_SUCCESS;
677}
678
679
680VMMDECL(int) CPUMSetGuestEDI(PVMCPU pVCpu, uint32_t edi)
681{
682 pVCpu->cpum.s.Guest.edi = edi;
683 return VINF_SUCCESS;
684}
685
686
687VMMDECL(int) CPUMSetGuestSS(PVMCPU pVCpu, uint16_t ss)
688{
689 pVCpu->cpum.s.Guest.ss = ss;
690 return VINF_SUCCESS;
691}
692
693
694VMMDECL(int) CPUMSetGuestCS(PVMCPU pVCpu, uint16_t cs)
695{
696 pVCpu->cpum.s.Guest.cs = cs;
697 return VINF_SUCCESS;
698}
699
700
701VMMDECL(int) CPUMSetGuestDS(PVMCPU pVCpu, uint16_t ds)
702{
703 pVCpu->cpum.s.Guest.ds = ds;
704 return VINF_SUCCESS;
705}
706
707
708VMMDECL(int) CPUMSetGuestES(PVMCPU pVCpu, uint16_t es)
709{
710 pVCpu->cpum.s.Guest.es = es;
711 return VINF_SUCCESS;
712}
713
714
715VMMDECL(int) CPUMSetGuestFS(PVMCPU pVCpu, uint16_t fs)
716{
717 pVCpu->cpum.s.Guest.fs = fs;
718 return VINF_SUCCESS;
719}
720
721
722VMMDECL(int) CPUMSetGuestGS(PVMCPU pVCpu, uint16_t gs)
723{
724 pVCpu->cpum.s.Guest.gs = gs;
725 return VINF_SUCCESS;
726}
727
728
729VMMDECL(void) CPUMSetGuestEFER(PVMCPU pVCpu, uint64_t val)
730{
731 pVCpu->cpum.s.Guest.msrEFER = val;
732}
733
734
735VMMDECL(uint64_t) CPUMGetGuestMsr(PVMCPU pVCpu, unsigned idMsr)
736{
737 uint64_t u64 = 0;
738
739 switch (idMsr)
740 {
741 case MSR_IA32_TSC:
742 u64 = TMCpuTickGet(pVCpu);
743 break;
744
745 case MSR_IA32_CR_PAT:
746 u64 = pVCpu->cpum.s.Guest.msrPAT;
747 break;
748
749 case MSR_IA32_SYSENTER_CS:
750 u64 = pVCpu->cpum.s.Guest.SysEnter.cs;
751 break;
752
753 case MSR_IA32_SYSENTER_EIP:
754 u64 = pVCpu->cpum.s.Guest.SysEnter.eip;
755 break;
756
757 case MSR_IA32_SYSENTER_ESP:
758 u64 = pVCpu->cpum.s.Guest.SysEnter.esp;
759 break;
760
761 case MSR_K6_EFER:
762 u64 = pVCpu->cpum.s.Guest.msrEFER;
763 break;
764
765 case MSR_K8_SF_MASK:
766 u64 = pVCpu->cpum.s.Guest.msrSFMASK;
767 break;
768
769 case MSR_K6_STAR:
770 u64 = pVCpu->cpum.s.Guest.msrSTAR;
771 break;
772
773 case MSR_K8_LSTAR:
774 u64 = pVCpu->cpum.s.Guest.msrLSTAR;
775 break;
776
777 case MSR_K8_CSTAR:
778 u64 = pVCpu->cpum.s.Guest.msrCSTAR;
779 break;
780
781 case MSR_K8_KERNEL_GS_BASE:
782 u64 = pVCpu->cpum.s.Guest.msrKERNELGSBASE;
783 break;
784
785 case MSR_K8_TSC_AUX:
786 u64 = pVCpu->cpum.s.GuestMsr.msr.tscAux;
787 break;
788
789 /* fs & gs base skipped on purpose as the current context might not be up-to-date. */
790 default:
791 AssertFailed();
792 break;
793 }
794 return u64;
795}
796
797VMMDECL(void) CPUMSetGuestMsr(PVMCPU pVCpu, unsigned idMsr, uint64_t valMsr)
798{
799 /* On purpose only a limited number of MSRs; use the emulation function to update the others. */
800 switch (idMsr)
801 {
802 case MSR_K8_TSC_AUX:
803 pVCpu->cpum.s.GuestMsr.msr.tscAux = valMsr;
804 break;
805
806 default:
807 AssertFailed();
808 break;
809 }
810}
811
812VMMDECL(RTGCPTR) CPUMGetGuestIDTR(PVMCPU pVCpu, uint16_t *pcbLimit)
813{
814 if (pcbLimit)
815 *pcbLimit = pVCpu->cpum.s.Guest.idtr.cbIdt;
816 return pVCpu->cpum.s.Guest.idtr.pIdt;
817}
818
819
820VMMDECL(RTSEL) CPUMGetGuestTR(PVMCPU pVCpu, PCPUMSELREGHID pHidden)
821{
822 if (pHidden)
823 *pHidden = pVCpu->cpum.s.Guest.trHid;
824 return pVCpu->cpum.s.Guest.tr;
825}
826
827
828VMMDECL(RTSEL) CPUMGetGuestCS(PVMCPU pVCpu)
829{
830 return pVCpu->cpum.s.Guest.cs;
831}
832
833
834VMMDECL(RTSEL) CPUMGetGuestDS(PVMCPU pVCpu)
835{
836 return pVCpu->cpum.s.Guest.ds;
837}
838
839
840VMMDECL(RTSEL) CPUMGetGuestES(PVMCPU pVCpu)
841{
842 return pVCpu->cpum.s.Guest.es;
843}
844
845
846VMMDECL(RTSEL) CPUMGetGuestFS(PVMCPU pVCpu)
847{
848 return pVCpu->cpum.s.Guest.fs;
849}
850
851
852VMMDECL(RTSEL) CPUMGetGuestGS(PVMCPU pVCpu)
853{
854 return pVCpu->cpum.s.Guest.gs;
855}
856
857
858VMMDECL(RTSEL) CPUMGetGuestSS(PVMCPU pVCpu)
859{
860 return pVCpu->cpum.s.Guest.ss;
861}
862
863
864VMMDECL(RTSEL) CPUMGetGuestLDTR(PVMCPU pVCpu)
865{
866 return pVCpu->cpum.s.Guest.ldtr;
867}
868
869
870VMMDECL(uint64_t) CPUMGetGuestCR0(PVMCPU pVCpu)
871{
872 return pVCpu->cpum.s.Guest.cr0;
873}
874
875
876VMMDECL(uint64_t) CPUMGetGuestCR2(PVMCPU pVCpu)
877{
878 return pVCpu->cpum.s.Guest.cr2;
879}
880
881
882VMMDECL(uint64_t) CPUMGetGuestCR3(PVMCPU pVCpu)
883{
884 return pVCpu->cpum.s.Guest.cr3;
885}
886
887
888VMMDECL(uint64_t) CPUMGetGuestCR4(PVMCPU pVCpu)
889{
890 return pVCpu->cpum.s.Guest.cr4;
891}
892
893
894VMMDECL(void) CPUMGetGuestGDTR(PVMCPU pVCpu, PVBOXGDTR pGDTR)
895{
896 *pGDTR = pVCpu->cpum.s.Guest.gdtr;
897}
898
899
900VMMDECL(uint32_t) CPUMGetGuestEIP(PVMCPU pVCpu)
901{
902 return pVCpu->cpum.s.Guest.eip;
903}
904
905
906VMMDECL(uint64_t) CPUMGetGuestRIP(PVMCPU pVCpu)
907{
908 return pVCpu->cpum.s.Guest.rip;
909}
910
911
912VMMDECL(uint32_t) CPUMGetGuestEAX(PVMCPU pVCpu)
913{
914 return pVCpu->cpum.s.Guest.eax;
915}
916
917
918VMMDECL(uint32_t) CPUMGetGuestEBX(PVMCPU pVCpu)
919{
920 return pVCpu->cpum.s.Guest.ebx;
921}
922
923
924VMMDECL(uint32_t) CPUMGetGuestECX(PVMCPU pVCpu)
925{
926 return pVCpu->cpum.s.Guest.ecx;
927}
928
929
930VMMDECL(uint32_t) CPUMGetGuestEDX(PVMCPU pVCpu)
931{
932 return pVCpu->cpum.s.Guest.edx;
933}
934
935
936VMMDECL(uint32_t) CPUMGetGuestESI(PVMCPU pVCpu)
937{
938 return pVCpu->cpum.s.Guest.esi;
939}
940
941
942VMMDECL(uint32_t) CPUMGetGuestEDI(PVMCPU pVCpu)
943{
944 return pVCpu->cpum.s.Guest.edi;
945}
946
947
948VMMDECL(uint32_t) CPUMGetGuestESP(PVMCPU pVCpu)
949{
950 return pVCpu->cpum.s.Guest.esp;
951}
952
953
954VMMDECL(uint32_t) CPUMGetGuestEBP(PVMCPU pVCpu)
955{
956 return pVCpu->cpum.s.Guest.ebp;
957}
958
959
960VMMDECL(uint32_t) CPUMGetGuestEFlags(PVMCPU pVCpu)
961{
962 return pVCpu->cpum.s.Guest.eflags.u32;
963}
964
965
966///@todo: crx should be an array
967VMMDECL(int) CPUMGetGuestCRx(PVMCPU pVCpu, unsigned iReg, uint64_t *pValue)
968{
969 switch (iReg)
970 {
971 case USE_REG_CR0:
972 *pValue = pVCpu->cpum.s.Guest.cr0;
973 break;
974 case USE_REG_CR2:
975 *pValue = pVCpu->cpum.s.Guest.cr2;
976 break;
977 case USE_REG_CR3:
978 *pValue = pVCpu->cpum.s.Guest.cr3;
979 break;
980 case USE_REG_CR4:
981 *pValue = pVCpu->cpum.s.Guest.cr4;
982 break;
983 default:
984 return VERR_INVALID_PARAMETER;
985 }
986 return VINF_SUCCESS;
987}
988
989
990VMMDECL(uint64_t) CPUMGetGuestDR0(PVMCPU pVCpu)
991{
992 return pVCpu->cpum.s.Guest.dr[0];
993}
994
995
996VMMDECL(uint64_t) CPUMGetGuestDR1(PVMCPU pVCpu)
997{
998 return pVCpu->cpum.s.Guest.dr[1];
999}
1000
1001
1002VMMDECL(uint64_t) CPUMGetGuestDR2(PVMCPU pVCpu)
1003{
1004 return pVCpu->cpum.s.Guest.dr[2];
1005}
1006
1007
1008VMMDECL(uint64_t) CPUMGetGuestDR3(PVMCPU pVCpu)
1009{
1010 return pVCpu->cpum.s.Guest.dr[3];
1011}
1012
1013
1014VMMDECL(uint64_t) CPUMGetGuestDR6(PVMCPU pVCpu)
1015{
1016 return pVCpu->cpum.s.Guest.dr[6];
1017}
1018
1019
1020VMMDECL(uint64_t) CPUMGetGuestDR7(PVMCPU pVCpu)
1021{
1022 return pVCpu->cpum.s.Guest.dr[7];
1023}
1024
1025
1026VMMDECL(int) CPUMGetGuestDRx(PVMCPU pVCpu, uint32_t iReg, uint64_t *pValue)
1027{
1028 AssertReturn(iReg <= USE_REG_DR7, VERR_INVALID_PARAMETER);
1029 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
1030 if (iReg == 4 || iReg == 5)
1031 iReg += 2;
1032 *pValue = pVCpu->cpum.s.Guest.dr[iReg];
1033 return VINF_SUCCESS;
1034}
1035
1036
1037VMMDECL(uint64_t) CPUMGetGuestEFER(PVMCPU pVCpu)
1038{
1039 return pVCpu->cpum.s.Guest.msrEFER;
1040}
1041
1042
1043/**
1044 * Gets a CpuId leaf.
1045 *
1046 * @param pVCpu The VMCPU handle.
1047 * @param iLeaf The CPUID leaf to get.
1048 * @param pEax Where to store the EAX value.
1049 * @param pEbx Where to store the EBX value.
1050 * @param pEcx Where to store the ECX value.
1051 * @param pEdx Where to store the EDX value.
1052 */
1053VMMDECL(void) CPUMGetGuestCpuId(PVMCPU pVCpu, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)
1054{
1055 PVM pVM = pVCpu->CTX_SUFF(pVM);
1056
1057 PCCPUMCPUID pCpuId;
1058 if (iLeaf < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd))
1059 pCpuId = &pVM->cpum.s.aGuestCpuIdStd[iLeaf];
1060 else if (iLeaf - UINT32_C(0x80000000) < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdExt))
1061 pCpuId = &pVM->cpum.s.aGuestCpuIdExt[iLeaf - UINT32_C(0x80000000)];
1062 else if (iLeaf - UINT32_C(0xc0000000) < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdCentaur))
1063 pCpuId = &pVM->cpum.s.aGuestCpuIdCentaur[iLeaf - UINT32_C(0xc0000000)];
1064 else
1065 pCpuId = &pVM->cpum.s.GuestCpuIdDef;
1066
1067 bool fHasMoreCaches = (*pEcx == 0);
1068
1069 *pEax = pCpuId->eax;
1070 *pEbx = pCpuId->ebx;
1071 *pEcx = pCpuId->ecx;
1072 *pEdx = pCpuId->edx;
1073
1074 if ( iLeaf == 1
1075 && pVM->cCPUs > 1)
1076 {
1077 /* Bits 31-24: Initial APIC ID */
1078 Assert(pVCpu->idCpu <= 255);
1079 *pEbx |= (pVCpu->idCpu << 24);
1080 }
1081
1082 if ( iLeaf == 4 && fHasMoreCaches &&
1083 pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_INTEL)
1084 {
1085 /* Report unified L0 cache, Linux'es num_cpu_cores() requires
1086 * that to be non-0 to detect core count correctly. */
1087 *pEax |= (1 << 5) | 3;
1088 }
1089
1090 Log2(("CPUMGetGuestCpuId: iLeaf=%#010x %RX32 %RX32 %RX32 %RX32\n", iLeaf, *pEax, *pEbx, *pEcx, *pEdx));
1091}
1092
1093/**
1094 * Gets a number of standard CPUID leafs.
1095 *
1096 * @returns Number of leafs.
1097 * @param pVM The VM handle.
1098 * @remark Intended for PATM.
1099 */
1100VMMDECL(uint32_t) CPUMGetGuestCpuIdStdMax(PVM pVM)
1101{
1102 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd);
1103}
1104
1105
1106/**
1107 * Gets a number of extended CPUID leafs.
1108 *
1109 * @returns Number of leafs.
1110 * @param pVM The VM handle.
1111 * @remark Intended for PATM.
1112 */
1113VMMDECL(uint32_t) CPUMGetGuestCpuIdExtMax(PVM pVM)
1114{
1115 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdExt);
1116}
1117
1118
1119/**
1120 * Gets a number of centaur CPUID leafs.
1121 *
1122 * @returns Number of leafs.
1123 * @param pVM The VM handle.
1124 * @remark Intended for PATM.
1125 */
1126VMMDECL(uint32_t) CPUMGetGuestCpuIdCentaurMax(PVM pVM)
1127{
1128 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdCentaur);
1129}
1130
1131
1132/**
1133 * Sets a CPUID feature bit.
1134 *
1135 * @param pVM The VM Handle.
1136 * @param enmFeature The feature to set.
1137 */
1138VMMDECL(void) CPUMSetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
1139{
1140 switch (enmFeature)
1141 {
1142 /*
1143 * Set the APIC bit in both feature masks.
1144 */
1145 case CPUMCPUIDFEATURE_APIC:
1146 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1147 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_APIC;
1148 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1149 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1150 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_APIC;
1151 LogRel(("CPUMSetGuestCpuIdFeature: Enabled APIC\n"));
1152 break;
1153
1154 /*
1155 * Set the x2APIC bit in the standard feature mask.
1156 */
1157 case CPUMCPUIDFEATURE_X2APIC:
1158 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1159 pVM->cpum.s.aGuestCpuIdStd[1].ecx |= X86_CPUID_FEATURE_ECX_X2APIC;
1160 LogRel(("CPUMSetGuestCpuIdFeature: Enabled x2APIC\n"));
1161 break;
1162
1163 /*
1164 * Set the sysenter/sysexit bit in the standard feature mask.
1165 * Assumes the caller knows what it's doing! (host must support these)
1166 */
1167 case CPUMCPUIDFEATURE_SEP:
1168 {
1169 if (!(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SEP))
1170 {
1171 AssertMsgFailed(("ERROR: Can't turn on SEP when the host doesn't support it!!\n"));
1172 return;
1173 }
1174
1175 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1176 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_SEP;
1177 LogRel(("CPUMSetGuestCpuIdFeature: Enabled sysenter/exit\n"));
1178 break;
1179 }
1180
1181 /*
1182 * Set the syscall/sysret bit in the extended feature mask.
1183 * Assumes the caller knows what it's doing! (host must support these)
1184 */
1185 case CPUMCPUIDFEATURE_SYSCALL:
1186 {
1187 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1188 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_SEP))
1189 {
1190#if HC_ARCH_BITS == 32
1191 /* X86_CPUID_AMD_FEATURE_EDX_SEP not set it seems in 32 bits mode.
1192 * Even when the cpu is capable of doing so in 64 bits mode.
1193 */
1194 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1195 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE)
1196 || !(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SEP))
1197#endif
1198 {
1199 LogRel(("WARNING: Can't turn on SYSCALL/SYSRET when the host doesn't support it!!\n"));
1200 return;
1201 }
1202 }
1203 /* Valid for both Intel and AMD CPUs, although only in 64 bits mode for Intel. */
1204 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_SEP;
1205 LogRel(("CPUMSetGuestCpuIdFeature: Enabled syscall/ret\n"));
1206 break;
1207 }
1208
1209 /*
1210 * Set the PAE bit in both feature masks.
1211 * Assumes the caller knows what it's doing! (host must support these)
1212 */
1213 case CPUMCPUIDFEATURE_PAE:
1214 {
1215 if (!(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_PAE))
1216 {
1217 LogRel(("WARNING: Can't turn on PAE when the host doesn't support it!!\n"));
1218 return;
1219 }
1220
1221 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1222 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_PAE;
1223 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1224 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1225 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_PAE;
1226 LogRel(("CPUMSetGuestCpuIdFeature: Enabled PAE\n"));
1227 break;
1228 }
1229
1230 /*
1231 * Set the LONG MODE bit in the extended feature mask.
1232 * Assumes the caller knows what it's doing! (host must support these)
1233 */
1234 case CPUMCPUIDFEATURE_LONG_MODE:
1235 {
1236 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1237 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE))
1238 {
1239 LogRel(("WARNING: Can't turn on LONG MODE when the host doesn't support it!!\n"));
1240 return;
1241 }
1242
1243 /* Valid for both Intel and AMD. */
1244 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_LONG_MODE;
1245 LogRel(("CPUMSetGuestCpuIdFeature: Enabled LONG MODE\n"));
1246 break;
1247 }
1248
1249 /*
1250 * Set the NXE bit in the extended feature mask.
1251 * Assumes the caller knows what it's doing! (host must support these)
1252 */
1253 case CPUMCPUIDFEATURE_NXE:
1254 {
1255 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1256 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_NX))
1257 {
1258 LogRel(("WARNING: Can't turn on NXE when the host doesn't support it!!\n"));
1259 return;
1260 }
1261
1262 /* Valid for both Intel and AMD. */
1263 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_NX;
1264 LogRel(("CPUMSetGuestCpuIdFeature: Enabled NXE\n"));
1265 break;
1266 }
1267
1268 case CPUMCPUIDFEATURE_LAHF:
1269 {
1270 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1271 || !(ASMCpuId_ECX(0x80000001) & X86_CPUID_AMD_FEATURE_ECX_LAHF_SAHF))
1272 {
1273 LogRel(("WARNING: Can't turn on LAHF/SAHF when the host doesn't support it!!\n"));
1274 return;
1275 }
1276
1277 pVM->cpum.s.aGuestCpuIdExt[1].ecx |= X86_CPUID_AMD_FEATURE_ECX_LAHF_SAHF;
1278 LogRel(("CPUMSetGuestCpuIdFeature: Enabled LAHF/SAHF\n"));
1279 break;
1280 }
1281
1282 case CPUMCPUIDFEATURE_PAT:
1283 {
1284 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1285 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_PAT;
1286 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1287 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1288 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_PAT;
1289 LogRel(("CPUMClearGuestCpuIdFeature: Enabled PAT\n"));
1290 break;
1291 }
1292
1293 case CPUMCPUIDFEATURE_RDTSCP:
1294 {
1295 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1296 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_RDTSCP))
1297 {
1298 LogRel(("WARNING: Can't turn on RDTSCP when the host doesn't support it!!\n"));
1299 return;
1300 }
1301
1302 /* Valid for AMD only (for now). */
1303 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_RDTSCP;
1304 LogRel(("CPUMSetGuestCpuIdFeature: Enabled RDTSCP.\n"));
1305 break;
1306 }
1307
1308 default:
1309 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
1310 break;
1311 }
1312 for (unsigned i=0;i<pVM->cCPUs;i++)
1313 {
1314 PVMCPU pVCpu = &pVM->aCpus[i];
1315
1316 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CPUID;
1317 }
1318}
1319
1320
1321/**
1322 * Queries a CPUID feature bit.
1323 *
1324 * @returns boolean for feature presence
1325 * @param pVM The VM Handle.
1326 * @param enmFeature The feature to query.
1327 */
1328VMMDECL(bool) CPUMGetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
1329{
1330 switch (enmFeature)
1331 {
1332 case CPUMCPUIDFEATURE_PAE:
1333 {
1334 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1335 return !!(pVM->cpum.s.aGuestCpuIdStd[1].edx & X86_CPUID_FEATURE_EDX_PAE);
1336 break;
1337 }
1338
1339 case CPUMCPUIDFEATURE_RDTSCP:
1340 {
1341 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1342 return !!(pVM->cpum.s.aGuestCpuIdExt[1].edx & X86_CPUID_AMD_FEATURE_EDX_RDTSCP);
1343 break;
1344 }
1345
1346 case CPUMCPUIDFEATURE_LONG_MODE:
1347 {
1348 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1349 return !!(pVM->cpum.s.aGuestCpuIdExt[1].edx & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE);
1350 break;
1351 }
1352
1353 default:
1354 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
1355 break;
1356 }
1357 return false;
1358}
1359
1360
1361/**
1362 * Clears a CPUID feature bit.
1363 *
1364 * @param pVM The VM Handle.
1365 * @param enmFeature The feature to clear.
1366 */
1367VMMDECL(void) CPUMClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
1368{
1369 switch (enmFeature)
1370 {
1371 /*
1372 * Set the APIC bit in both feature masks.
1373 */
1374 case CPUMCPUIDFEATURE_APIC:
1375 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1376 pVM->cpum.s.aGuestCpuIdStd[1].edx &= ~X86_CPUID_FEATURE_EDX_APIC;
1377 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1378 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1379 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_APIC;
1380 Log(("CPUMSetGuestCpuIdFeature: Disabled APIC\n"));
1381 break;
1382
1383 /*
1384 * Clear the x2APIC bit in the standard feature mask.
1385 */
1386 case CPUMCPUIDFEATURE_X2APIC:
1387 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1388 pVM->cpum.s.aGuestCpuIdStd[1].ecx &= ~X86_CPUID_FEATURE_ECX_X2APIC;
1389 LogRel(("CPUMSetGuestCpuIdFeature: Disabled x2APIC\n"));
1390 break;
1391
1392 case CPUMCPUIDFEATURE_PAE:
1393 {
1394 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1395 pVM->cpum.s.aGuestCpuIdStd[1].edx &= ~X86_CPUID_FEATURE_EDX_PAE;
1396 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1397 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1398 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_PAE;
1399 LogRel(("CPUMClearGuestCpuIdFeature: Disabled PAE!\n"));
1400 break;
1401 }
1402
1403 case CPUMCPUIDFEATURE_PAT:
1404 {
1405 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1406 pVM->cpum.s.aGuestCpuIdStd[1].edx &= ~X86_CPUID_FEATURE_EDX_PAT;
1407 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1408 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1409 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_PAT;
1410 LogRel(("CPUMClearGuestCpuIdFeature: Disabled PAT!\n"));
1411 break;
1412 }
1413
1414 case CPUMCPUIDFEATURE_LONG_MODE:
1415 {
1416 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1417 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_LONG_MODE;
1418 break;
1419 }
1420
1421 case CPUMCPUIDFEATURE_LAHF:
1422 {
1423 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1424 pVM->cpum.s.aGuestCpuIdExt[1].ecx &= ~X86_CPUID_AMD_FEATURE_ECX_LAHF_SAHF;
1425 break;
1426 }
1427
1428 default:
1429 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
1430 break;
1431 }
1432 for (unsigned i=0;i<pVM->cCPUs;i++)
1433 {
1434 PVMCPU pVCpu = &pVM->aCpus[i];
1435
1436 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CPUID;
1437 }
1438}
1439
1440
1441/**
1442 * Gets the CPU vendor
1443 *
1444 * @returns CPU vendor
1445 * @param pVM The VM handle.
1446 */
1447VMMDECL(CPUMCPUVENDOR) CPUMGetCPUVendor(PVM pVM)
1448{
1449 return pVM->cpum.s.enmCPUVendor;
1450}
1451
1452
1453VMMDECL(int) CPUMSetGuestDR0(PVMCPU pVCpu, uint64_t uDr0)
1454{
1455 pVCpu->cpum.s.Guest.dr[0] = uDr0;
1456 return CPUMRecalcHyperDRx(pVCpu);
1457}
1458
1459
1460VMMDECL(int) CPUMSetGuestDR1(PVMCPU pVCpu, uint64_t uDr1)
1461{
1462 pVCpu->cpum.s.Guest.dr[1] = uDr1;
1463 return CPUMRecalcHyperDRx(pVCpu);
1464}
1465
1466
1467VMMDECL(int) CPUMSetGuestDR2(PVMCPU pVCpu, uint64_t uDr2)
1468{
1469 pVCpu->cpum.s.Guest.dr[2] = uDr2;
1470 return CPUMRecalcHyperDRx(pVCpu);
1471}
1472
1473
1474VMMDECL(int) CPUMSetGuestDR3(PVMCPU pVCpu, uint64_t uDr3)
1475{
1476 pVCpu->cpum.s.Guest.dr[3] = uDr3;
1477 return CPUMRecalcHyperDRx(pVCpu);
1478}
1479
1480
1481VMMDECL(int) CPUMSetGuestDR6(PVMCPU pVCpu, uint64_t uDr6)
1482{
1483 pVCpu->cpum.s.Guest.dr[6] = uDr6;
1484 return CPUMRecalcHyperDRx(pVCpu);
1485}
1486
1487
1488VMMDECL(int) CPUMSetGuestDR7(PVMCPU pVCpu, uint64_t uDr7)
1489{
1490 pVCpu->cpum.s.Guest.dr[7] = uDr7;
1491 return CPUMRecalcHyperDRx(pVCpu);
1492}
1493
1494
1495VMMDECL(int) CPUMSetGuestDRx(PVMCPU pVCpu, uint32_t iReg, uint64_t Value)
1496{
1497 AssertReturn(iReg <= USE_REG_DR7, VERR_INVALID_PARAMETER);
1498 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
1499 if (iReg == 4 || iReg == 5)
1500 iReg += 2;
1501 pVCpu->cpum.s.Guest.dr[iReg] = Value;
1502 return CPUMRecalcHyperDRx(pVCpu);
1503}
1504
1505
1506/**
1507 * Recalculates the hypvervisor DRx register values based on
1508 * current guest registers and DBGF breakpoints.
1509 *
1510 * This is called whenever a guest DRx register is modified and when DBGF
1511 * sets a hardware breakpoint. In guest context this function will reload
1512 * any (hyper) DRx registers which comes out with a different value.
1513 *
1514 * @returns VINF_SUCCESS.
1515 * @param pVCpu The VMCPU handle.
1516 */
1517VMMDECL(int) CPUMRecalcHyperDRx(PVMCPU pVCpu)
1518{
1519 PVM pVM = pVCpu->CTX_SUFF(pVM);
1520
1521 /*
1522 * Compare the DR7s first.
1523 *
1524 * We only care about the enabled flags. The GE and LE flags are always
1525 * set and we don't care if the guest doesn't set them. GD is virtualized
1526 * when we dispatch #DB, we never enable it.
1527 */
1528 const RTGCUINTREG uDbgfDr7 = DBGFBpGetDR7(pVM);
1529#ifdef CPUM_VIRTUALIZE_DRX
1530 const RTGCUINTREG uGstDr7 = CPUMGetGuestDR7(pVCpu);
1531#else
1532 const RTGCUINTREG uGstDr7 = 0;
1533#endif
1534 if ((uGstDr7 | uDbgfDr7) & X86_DR7_ENABLED_MASK)
1535 {
1536 /*
1537 * Ok, something is enabled. Recalc each of the breakpoints.
1538 * Straight forward code, not optimized/minimized in any way.
1539 */
1540 RTGCUINTREG uNewDr7 = X86_DR7_GE | X86_DR7_LE | X86_DR7_MB1_MASK;
1541
1542 /* bp 0 */
1543 RTGCUINTREG uNewDr0;
1544 if (uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0))
1545 {
1546 uNewDr7 |= uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
1547 uNewDr0 = DBGFBpGetDR0(pVM);
1548 }
1549 else if (uGstDr7 & (X86_DR7_L0 | X86_DR7_G0))
1550 {
1551 uNewDr7 |= uGstDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
1552 uNewDr0 = CPUMGetGuestDR0(pVCpu);
1553 }
1554 else
1555 uNewDr0 = pVCpu->cpum.s.Hyper.dr[0];
1556
1557 /* bp 1 */
1558 RTGCUINTREG uNewDr1;
1559 if (uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1))
1560 {
1561 uNewDr7 |= uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
1562 uNewDr1 = DBGFBpGetDR1(pVM);
1563 }
1564 else if (uGstDr7 & (X86_DR7_L1 | X86_DR7_G1))
1565 {
1566 uNewDr7 |= uGstDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
1567 uNewDr1 = CPUMGetGuestDR1(pVCpu);
1568 }
1569 else
1570 uNewDr1 = pVCpu->cpum.s.Hyper.dr[1];
1571
1572 /* bp 2 */
1573 RTGCUINTREG uNewDr2;
1574 if (uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2))
1575 {
1576 uNewDr7 |= uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
1577 uNewDr2 = DBGFBpGetDR2(pVM);
1578 }
1579 else if (uGstDr7 & (X86_DR7_L2 | X86_DR7_G2))
1580 {
1581 uNewDr7 |= uGstDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
1582 uNewDr2 = CPUMGetGuestDR2(pVCpu);
1583 }
1584 else
1585 uNewDr2 = pVCpu->cpum.s.Hyper.dr[2];
1586
1587 /* bp 3 */
1588 RTGCUINTREG uNewDr3;
1589 if (uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3))
1590 {
1591 uNewDr7 |= uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
1592 uNewDr3 = DBGFBpGetDR3(pVM);
1593 }
1594 else if (uGstDr7 & (X86_DR7_L3 | X86_DR7_G3))
1595 {
1596 uNewDr7 |= uGstDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
1597 uNewDr3 = CPUMGetGuestDR3(pVCpu);
1598 }
1599 else
1600 uNewDr3 = pVCpu->cpum.s.Hyper.dr[3];
1601
1602 /*
1603 * Apply the updates.
1604 */
1605#ifdef IN_RC
1606 if (!(pVCpu->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS))
1607 {
1608 /** @todo save host DBx registers. */
1609 }
1610#endif
1611 pVCpu->cpum.s.fUseFlags |= CPUM_USE_DEBUG_REGS;
1612 if (uNewDr3 != pVCpu->cpum.s.Hyper.dr[3])
1613 CPUMSetHyperDR3(pVCpu, uNewDr3);
1614 if (uNewDr2 != pVCpu->cpum.s.Hyper.dr[2])
1615 CPUMSetHyperDR2(pVCpu, uNewDr2);
1616 if (uNewDr1 != pVCpu->cpum.s.Hyper.dr[1])
1617 CPUMSetHyperDR1(pVCpu, uNewDr1);
1618 if (uNewDr0 != pVCpu->cpum.s.Hyper.dr[0])
1619 CPUMSetHyperDR0(pVCpu, uNewDr0);
1620 if (uNewDr7 != pVCpu->cpum.s.Hyper.dr[7])
1621 CPUMSetHyperDR7(pVCpu, uNewDr7);
1622 }
1623 else
1624 {
1625#ifdef IN_RC
1626 if (pVCpu->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS)
1627 {
1628 /** @todo restore host DBx registers. */
1629 }
1630#endif
1631 pVCpu->cpum.s.fUseFlags &= ~CPUM_USE_DEBUG_REGS;
1632 }
1633 Log2(("CPUMRecalcHyperDRx: fUseFlags=%#x %RGr %RGr %RGr %RGr %RGr %RGr\n",
1634 pVCpu->cpum.s.fUseFlags, pVCpu->cpum.s.Hyper.dr[0], pVCpu->cpum.s.Hyper.dr[1],
1635 pVCpu->cpum.s.Hyper.dr[2], pVCpu->cpum.s.Hyper.dr[3], pVCpu->cpum.s.Hyper.dr[6],
1636 pVCpu->cpum.s.Hyper.dr[7]));
1637
1638 return VINF_SUCCESS;
1639}
1640
1641#ifndef IN_RING0 /** @todo I don't think we need this in R0, so move it to CPUMAll.cpp? */
1642
1643/**
1644 * Transforms the guest CPU state to raw-ring mode.
1645 *
1646 * This function will change the any of the cs and ss register with DPL=0 to DPL=1.
1647 *
1648 * @returns VBox status. (recompiler failure)
1649 * @param pVCpu The VMCPU handle.
1650 * @param pCtxCore The context core (for trap usage).
1651 * @see @ref pg_raw
1652 */
1653VMMDECL(int) CPUMRawEnter(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
1654{
1655 PVM pVM = pVCpu->CTX_SUFF(pVM);
1656
1657 Assert(!pVM->cpum.s.fRawEntered);
1658 if (!pCtxCore)
1659 pCtxCore = CPUMCTX2CORE(&pVCpu->cpum.s.Guest);
1660
1661 /*
1662 * Are we in Ring-0?
1663 */
1664 if ( pCtxCore->ss && (pCtxCore->ss & X86_SEL_RPL) == 0
1665 && !pCtxCore->eflags.Bits.u1VM)
1666 {
1667 /*
1668 * Enter execution mode.
1669 */
1670 PATMRawEnter(pVM, pCtxCore);
1671
1672 /*
1673 * Set CPL to Ring-1.
1674 */
1675 pCtxCore->ss |= 1;
1676 if (pCtxCore->cs && (pCtxCore->cs & X86_SEL_RPL) == 0)
1677 pCtxCore->cs |= 1;
1678 }
1679 else
1680 {
1681 AssertMsg((pCtxCore->ss & X86_SEL_RPL) >= 2 || pCtxCore->eflags.Bits.u1VM,
1682 ("ring-1 code not supported\n"));
1683 /*
1684 * PATM takes care of IOPL and IF flags for Ring-3 and Ring-2 code as well.
1685 */
1686 PATMRawEnter(pVM, pCtxCore);
1687 }
1688
1689 /*
1690 * Assert sanity.
1691 */
1692 AssertMsg((pCtxCore->eflags.u32 & X86_EFL_IF), ("X86_EFL_IF is clear\n"));
1693 AssertReleaseMsg( pCtxCore->eflags.Bits.u2IOPL < (unsigned)(pCtxCore->ss & X86_SEL_RPL)
1694 || pCtxCore->eflags.Bits.u1VM,
1695 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss & X86_SEL_RPL));
1696 Assert((pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) == (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP));
1697 pCtxCore->eflags.u32 |= X86_EFL_IF; /* paranoia */
1698
1699 pVM->cpum.s.fRawEntered = true;
1700 return VINF_SUCCESS;
1701}
1702
1703
1704/**
1705 * Transforms the guest CPU state from raw-ring mode to correct values.
1706 *
1707 * This function will change any selector registers with DPL=1 to DPL=0.
1708 *
1709 * @returns Adjusted rc.
1710 * @param pVCpu The VMCPU handle.
1711 * @param rc Raw mode return code
1712 * @param pCtxCore The context core (for trap usage).
1713 * @see @ref pg_raw
1714 */
1715VMMDECL(int) CPUMRawLeave(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, int rc)
1716{
1717 PVM pVM = pVCpu->CTX_SUFF(pVM);
1718
1719 /*
1720 * Don't leave if we've already left (in GC).
1721 */
1722 Assert(pVM->cpum.s.fRawEntered);
1723 if (!pVM->cpum.s.fRawEntered)
1724 return rc;
1725 pVM->cpum.s.fRawEntered = false;
1726
1727 PCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
1728 if (!pCtxCore)
1729 pCtxCore = CPUMCTX2CORE(pCtx);
1730 Assert(pCtxCore->eflags.Bits.u1VM || (pCtxCore->ss & X86_SEL_RPL));
1731 AssertMsg(pCtxCore->eflags.Bits.u1VM || pCtxCore->eflags.Bits.u2IOPL < (unsigned)(pCtxCore->ss & X86_SEL_RPL),
1732 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss & X86_SEL_RPL));
1733
1734 /*
1735 * Are we executing in raw ring-1?
1736 */
1737 if ( (pCtxCore->ss & X86_SEL_RPL) == 1
1738 && !pCtxCore->eflags.Bits.u1VM)
1739 {
1740 /*
1741 * Leave execution mode.
1742 */
1743 PATMRawLeave(pVM, pCtxCore, rc);
1744 /* Not quite sure if this is really required, but shouldn't harm (too much anyways). */
1745 /** @todo See what happens if we remove this. */
1746 if ((pCtxCore->ds & X86_SEL_RPL) == 1)
1747 pCtxCore->ds &= ~X86_SEL_RPL;
1748 if ((pCtxCore->es & X86_SEL_RPL) == 1)
1749 pCtxCore->es &= ~X86_SEL_RPL;
1750 if ((pCtxCore->fs & X86_SEL_RPL) == 1)
1751 pCtxCore->fs &= ~X86_SEL_RPL;
1752 if ((pCtxCore->gs & X86_SEL_RPL) == 1)
1753 pCtxCore->gs &= ~X86_SEL_RPL;
1754
1755 /*
1756 * Ring-1 selector => Ring-0.
1757 */
1758 pCtxCore->ss &= ~X86_SEL_RPL;
1759 if ((pCtxCore->cs & X86_SEL_RPL) == 1)
1760 pCtxCore->cs &= ~X86_SEL_RPL;
1761 }
1762 else
1763 {
1764 /*
1765 * PATM is taking care of the IOPL and IF flags for us.
1766 */
1767 PATMRawLeave(pVM, pCtxCore, rc);
1768 if (!pCtxCore->eflags.Bits.u1VM)
1769 {
1770 /** @todo See what happens if we remove this. */
1771 if ((pCtxCore->ds & X86_SEL_RPL) == 1)
1772 pCtxCore->ds &= ~X86_SEL_RPL;
1773 if ((pCtxCore->es & X86_SEL_RPL) == 1)
1774 pCtxCore->es &= ~X86_SEL_RPL;
1775 if ((pCtxCore->fs & X86_SEL_RPL) == 1)
1776 pCtxCore->fs &= ~X86_SEL_RPL;
1777 if ((pCtxCore->gs & X86_SEL_RPL) == 1)
1778 pCtxCore->gs &= ~X86_SEL_RPL;
1779 }
1780 }
1781
1782 return rc;
1783}
1784
1785/**
1786 * Updates the EFLAGS while we're in raw-mode.
1787 *
1788 * @param pVCpu The VMCPU handle.
1789 * @param pCtxCore The context core.
1790 * @param eflags The new EFLAGS value.
1791 */
1792VMMDECL(void) CPUMRawSetEFlags(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, uint32_t eflags)
1793{
1794 PVM pVM = pVCpu->CTX_SUFF(pVM);
1795
1796 if (!pVM->cpum.s.fRawEntered)
1797 {
1798 pCtxCore->eflags.u32 = eflags;
1799 return;
1800 }
1801 PATMRawSetEFlags(pVM, pCtxCore, eflags);
1802}
1803
1804#endif /* !IN_RING0 */
1805
1806/**
1807 * Gets the EFLAGS while we're in raw-mode.
1808 *
1809 * @returns The eflags.
1810 * @param pVCpu The VMCPU handle.
1811 * @param pCtxCore The context core.
1812 */
1813VMMDECL(uint32_t) CPUMRawGetEFlags(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
1814{
1815#ifdef IN_RING0
1816 return pCtxCore->eflags.u32;
1817#else
1818 PVM pVM = pVCpu->CTX_SUFF(pVM);
1819
1820 if (!pVM->cpum.s.fRawEntered)
1821 return pCtxCore->eflags.u32;
1822 return PATMRawGetEFlags(pVM, pCtxCore);
1823#endif
1824}
1825
1826
1827/**
1828 * Gets and resets the changed flags (CPUM_CHANGED_*).
1829 * Only REM should call this function.
1830 *
1831 * @returns The changed flags.
1832 * @param pVCpu The VMCPU handle.
1833 */
1834VMMDECL(unsigned) CPUMGetAndClearChangedFlagsREM(PVMCPU pVCpu)
1835{
1836 unsigned fFlags = pVCpu->cpum.s.fChanged;
1837 pVCpu->cpum.s.fChanged = 0;
1838 /** @todo change the switcher to use the fChanged flags. */
1839 if (pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU_SINCE_REM)
1840 {
1841 fFlags |= CPUM_CHANGED_FPU_REM;
1842 pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_FPU_SINCE_REM;
1843 }
1844 return fFlags;
1845}
1846
1847
1848/**
1849 * Sets the specified changed flags (CPUM_CHANGED_*).
1850 *
1851 * @param pVCpu The VMCPU handle.
1852 */
1853VMMDECL(void) CPUMSetChangedFlags(PVMCPU pVCpu, uint32_t fChangedFlags)
1854{
1855 pVCpu->cpum.s.fChanged |= fChangedFlags;
1856}
1857
1858
1859/**
1860 * Checks if the CPU supports the FXSAVE and FXRSTOR instruction.
1861 * @returns true if supported.
1862 * @returns false if not supported.
1863 * @param pVM The VM handle.
1864 */
1865VMMDECL(bool) CPUMSupportsFXSR(PVM pVM)
1866{
1867 return pVM->cpum.s.CPUFeatures.edx.u1FXSR != 0;
1868}
1869
1870
1871/**
1872 * Checks if the host OS uses the SYSENTER / SYSEXIT instructions.
1873 * @returns true if used.
1874 * @returns false if not used.
1875 * @param pVM The VM handle.
1876 */
1877VMMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM)
1878{
1879 return (pVM->cpum.s.fHostUseFlags & CPUM_USE_SYSENTER) != 0;
1880}
1881
1882
1883/**
1884 * Checks if the host OS uses the SYSCALL / SYSRET instructions.
1885 * @returns true if used.
1886 * @returns false if not used.
1887 * @param pVM The VM handle.
1888 */
1889VMMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM)
1890{
1891 return (pVM->cpum.s.fHostUseFlags & CPUM_USE_SYSCALL) != 0;
1892}
1893
1894#ifndef IN_RING3
1895
1896/**
1897 * Lazily sync in the FPU/XMM state
1898 *
1899 * @returns VBox status code.
1900 * @param pVCpu VMCPU handle
1901 */
1902VMMDECL(int) CPUMHandleLazyFPU(PVMCPU pVCpu)
1903{
1904 return cpumHandleLazyFPUAsm(&pVCpu->cpum.s);
1905}
1906
1907#endif /* !IN_RING3 */
1908
1909/**
1910 * Checks if we activated the FPU/XMM state of the guest OS
1911 * @returns true if we did.
1912 * @returns false if not.
1913 * @param pVCpu The VMCPU handle.
1914 */
1915VMMDECL(bool) CPUMIsGuestFPUStateActive(PVMCPU pVCpu)
1916{
1917 return (pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU) != 0;
1918}
1919
1920
1921/**
1922 * Deactivate the FPU/XMM state of the guest OS
1923 * @param pVCpu The VMCPU handle.
1924 */
1925VMMDECL(void) CPUMDeactivateGuestFPUState(PVMCPU pVCpu)
1926{
1927 pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_FPU;
1928}
1929
1930
1931/**
1932 * Checks if the guest debug state is active
1933 *
1934 * @returns boolean
1935 * @param pVM VM handle.
1936 */
1937VMMDECL(bool) CPUMIsGuestDebugStateActive(PVMCPU pVCpu)
1938{
1939 return (pVCpu->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS) != 0;
1940}
1941
1942/**
1943 * Checks if the hyper debug state is active
1944 *
1945 * @returns boolean
1946 * @param pVM VM handle.
1947 */
1948VMMDECL(bool) CPUMIsHyperDebugStateActive(PVMCPU pVCpu)
1949{
1950 return (pVCpu->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS_HYPER) != 0;
1951}
1952
1953
1954/**
1955 * Mark the guest's debug state as inactive
1956 *
1957 * @returns boolean
1958 * @param pVM VM handle.
1959 */
1960VMMDECL(void) CPUMDeactivateGuestDebugState(PVMCPU pVCpu)
1961{
1962 pVCpu->cpum.s.fUseFlags &= ~CPUM_USE_DEBUG_REGS;
1963}
1964
1965
1966/**
1967 * Mark the hypervisor's debug state as inactive
1968 *
1969 * @returns boolean
1970 * @param pVM VM handle.
1971 */
1972VMMDECL(void) CPUMDeactivateHyperDebugState(PVMCPU pVCpu)
1973{
1974 pVCpu->cpum.s.fUseFlags &= ~CPUM_USE_DEBUG_REGS_HYPER;
1975}
1976
1977/**
1978 * Checks if the hidden selector registers are valid
1979 * @returns true if they are.
1980 * @returns false if not.
1981 * @param pVM The VM handle.
1982 */
1983VMMDECL(bool) CPUMAreHiddenSelRegsValid(PVM pVM)
1984{
1985 return HWACCMIsEnabled(pVM);
1986}
1987
1988
1989
1990/**
1991 * Get the current privilege level of the guest.
1992 *
1993 * @returns cpl
1994 * @param pVM VM Handle.
1995 * @param pRegFrame Trap register frame.
1996 */
1997VMMDECL(uint32_t) CPUMGetGuestCPL(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
1998{
1999 uint32_t cpl;
2000
2001 if (CPUMAreHiddenSelRegsValid(pVCpu->CTX_SUFF(pVM)))
2002 {
2003 /*
2004 * The hidden CS.DPL register is always equal to the CPL, it is
2005 * not affected by loading a conforming coding segment.
2006 *
2007 * This only seems to apply to AMD-V; in the VT-x case we *do* need to look
2008 * at SS. (ACP2 regression during install after a far call to ring 2)
2009 */
2010 if (RT_LIKELY(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
2011 cpl = pCtxCore->ssHid.Attr.n.u2Dpl;
2012 else
2013 cpl = 0; /* CPL set to 3 for VT-x real-mode emulation. */
2014 }
2015 else if (RT_LIKELY(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
2016 {
2017 if (RT_LIKELY(!pCtxCore->eflags.Bits.u1VM))
2018 {
2019 /*
2020 * The SS RPL is always equal to the CPL, while the CS RPL
2021 * isn't necessarily equal if the segment is conforming.
2022 * See section 4.11.1 in the AMD manual.
2023 */
2024 cpl = (pCtxCore->ss & X86_SEL_RPL);
2025#ifndef IN_RING0
2026 if (cpl == 1)
2027 cpl = 0;
2028#endif
2029 }
2030 else
2031 cpl = 3;
2032 }
2033 else
2034 cpl = 0; /* real mode; cpl is zero */
2035
2036 return cpl;
2037}
2038
2039
2040/**
2041 * Gets the current guest CPU mode.
2042 *
2043 * If paging mode is what you need, check out PGMGetGuestMode().
2044 *
2045 * @returns The CPU mode.
2046 * @param pVCpu The VMCPU handle.
2047 */
2048VMMDECL(CPUMMODE) CPUMGetGuestMode(PVMCPU pVCpu)
2049{
2050 CPUMMODE enmMode;
2051 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
2052 enmMode = CPUMMODE_REAL;
2053 else if (!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
2054 enmMode = CPUMMODE_PROTECTED;
2055 else
2056 enmMode = CPUMMODE_LONG;
2057
2058 return enmMode;
2059}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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