VirtualBox

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

Last change on this file since 26685 was 26673, checked in by vboxsync, 15 years ago

faster

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 58.5 KB
Line 
1/* $Id: CPUMAllRegs.cpp 26673 2010-02-22 09:26:43Z 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.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * 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 case MSR_IA32_PERF_STATUS:
790 /** @todo: could really be not exactly correct, maybe use host's values */
791 /* Keep consistent with helper_rdmsr() in REM */
792 u64 = (1000ULL /* TSC increment by tick */)
793 | (((uint64_t)4ULL) << 40 /* CPU multiplier */ );
794 break;
795
796 /* fs & gs base skipped on purpose as the current context might not be up-to-date. */
797 default:
798 AssertFailed();
799 break;
800 }
801 return u64;
802}
803
804VMMDECL(void) CPUMSetGuestMsr(PVMCPU pVCpu, unsigned idMsr, uint64_t valMsr)
805{
806 /* On purpose only a limited number of MSRs; use the emulation function to update the others. */
807 switch (idMsr)
808 {
809 case MSR_K8_TSC_AUX:
810 pVCpu->cpum.s.GuestMsr.msr.tscAux = valMsr;
811 break;
812
813 default:
814 AssertFailed();
815 break;
816 }
817}
818
819VMMDECL(RTGCPTR) CPUMGetGuestIDTR(PVMCPU pVCpu, uint16_t *pcbLimit)
820{
821 if (pcbLimit)
822 *pcbLimit = pVCpu->cpum.s.Guest.idtr.cbIdt;
823 return pVCpu->cpum.s.Guest.idtr.pIdt;
824}
825
826
827VMMDECL(RTSEL) CPUMGetGuestTR(PVMCPU pVCpu, PCPUMSELREGHID pHidden)
828{
829 if (pHidden)
830 *pHidden = pVCpu->cpum.s.Guest.trHid;
831 return pVCpu->cpum.s.Guest.tr;
832}
833
834
835VMMDECL(RTSEL) CPUMGetGuestCS(PVMCPU pVCpu)
836{
837 return pVCpu->cpum.s.Guest.cs;
838}
839
840
841VMMDECL(RTSEL) CPUMGetGuestDS(PVMCPU pVCpu)
842{
843 return pVCpu->cpum.s.Guest.ds;
844}
845
846
847VMMDECL(RTSEL) CPUMGetGuestES(PVMCPU pVCpu)
848{
849 return pVCpu->cpum.s.Guest.es;
850}
851
852
853VMMDECL(RTSEL) CPUMGetGuestFS(PVMCPU pVCpu)
854{
855 return pVCpu->cpum.s.Guest.fs;
856}
857
858
859VMMDECL(RTSEL) CPUMGetGuestGS(PVMCPU pVCpu)
860{
861 return pVCpu->cpum.s.Guest.gs;
862}
863
864
865VMMDECL(RTSEL) CPUMGetGuestSS(PVMCPU pVCpu)
866{
867 return pVCpu->cpum.s.Guest.ss;
868}
869
870
871VMMDECL(RTSEL) CPUMGetGuestLDTR(PVMCPU pVCpu)
872{
873 return pVCpu->cpum.s.Guest.ldtr;
874}
875
876
877VMMDECL(uint64_t) CPUMGetGuestCR0(PVMCPU pVCpu)
878{
879 return pVCpu->cpum.s.Guest.cr0;
880}
881
882
883VMMDECL(uint64_t) CPUMGetGuestCR2(PVMCPU pVCpu)
884{
885 return pVCpu->cpum.s.Guest.cr2;
886}
887
888
889VMMDECL(uint64_t) CPUMGetGuestCR3(PVMCPU pVCpu)
890{
891 return pVCpu->cpum.s.Guest.cr3;
892}
893
894
895VMMDECL(uint64_t) CPUMGetGuestCR4(PVMCPU pVCpu)
896{
897 return pVCpu->cpum.s.Guest.cr4;
898}
899
900
901VMMDECL(void) CPUMGetGuestGDTR(PVMCPU pVCpu, PVBOXGDTR pGDTR)
902{
903 *pGDTR = pVCpu->cpum.s.Guest.gdtr;
904}
905
906
907VMMDECL(uint32_t) CPUMGetGuestEIP(PVMCPU pVCpu)
908{
909 return pVCpu->cpum.s.Guest.eip;
910}
911
912
913VMMDECL(uint64_t) CPUMGetGuestRIP(PVMCPU pVCpu)
914{
915 return pVCpu->cpum.s.Guest.rip;
916}
917
918
919VMMDECL(uint32_t) CPUMGetGuestEAX(PVMCPU pVCpu)
920{
921 return pVCpu->cpum.s.Guest.eax;
922}
923
924
925VMMDECL(uint32_t) CPUMGetGuestEBX(PVMCPU pVCpu)
926{
927 return pVCpu->cpum.s.Guest.ebx;
928}
929
930
931VMMDECL(uint32_t) CPUMGetGuestECX(PVMCPU pVCpu)
932{
933 return pVCpu->cpum.s.Guest.ecx;
934}
935
936
937VMMDECL(uint32_t) CPUMGetGuestEDX(PVMCPU pVCpu)
938{
939 return pVCpu->cpum.s.Guest.edx;
940}
941
942
943VMMDECL(uint32_t) CPUMGetGuestESI(PVMCPU pVCpu)
944{
945 return pVCpu->cpum.s.Guest.esi;
946}
947
948
949VMMDECL(uint32_t) CPUMGetGuestEDI(PVMCPU pVCpu)
950{
951 return pVCpu->cpum.s.Guest.edi;
952}
953
954
955VMMDECL(uint32_t) CPUMGetGuestESP(PVMCPU pVCpu)
956{
957 return pVCpu->cpum.s.Guest.esp;
958}
959
960
961VMMDECL(uint32_t) CPUMGetGuestEBP(PVMCPU pVCpu)
962{
963 return pVCpu->cpum.s.Guest.ebp;
964}
965
966
967VMMDECL(uint32_t) CPUMGetGuestEFlags(PVMCPU pVCpu)
968{
969 return pVCpu->cpum.s.Guest.eflags.u32;
970}
971
972
973///@todo: crx should be an array
974VMMDECL(int) CPUMGetGuestCRx(PVMCPU pVCpu, unsigned iReg, uint64_t *pValue)
975{
976 switch (iReg)
977 {
978 case USE_REG_CR0:
979 *pValue = pVCpu->cpum.s.Guest.cr0;
980 break;
981 case USE_REG_CR2:
982 *pValue = pVCpu->cpum.s.Guest.cr2;
983 break;
984 case USE_REG_CR3:
985 *pValue = pVCpu->cpum.s.Guest.cr3;
986 break;
987 case USE_REG_CR4:
988 *pValue = pVCpu->cpum.s.Guest.cr4;
989 break;
990 default:
991 return VERR_INVALID_PARAMETER;
992 }
993 return VINF_SUCCESS;
994}
995
996
997VMMDECL(uint64_t) CPUMGetGuestDR0(PVMCPU pVCpu)
998{
999 return pVCpu->cpum.s.Guest.dr[0];
1000}
1001
1002
1003VMMDECL(uint64_t) CPUMGetGuestDR1(PVMCPU pVCpu)
1004{
1005 return pVCpu->cpum.s.Guest.dr[1];
1006}
1007
1008
1009VMMDECL(uint64_t) CPUMGetGuestDR2(PVMCPU pVCpu)
1010{
1011 return pVCpu->cpum.s.Guest.dr[2];
1012}
1013
1014
1015VMMDECL(uint64_t) CPUMGetGuestDR3(PVMCPU pVCpu)
1016{
1017 return pVCpu->cpum.s.Guest.dr[3];
1018}
1019
1020
1021VMMDECL(uint64_t) CPUMGetGuestDR6(PVMCPU pVCpu)
1022{
1023 return pVCpu->cpum.s.Guest.dr[6];
1024}
1025
1026
1027VMMDECL(uint64_t) CPUMGetGuestDR7(PVMCPU pVCpu)
1028{
1029 return pVCpu->cpum.s.Guest.dr[7];
1030}
1031
1032
1033VMMDECL(int) CPUMGetGuestDRx(PVMCPU pVCpu, uint32_t iReg, uint64_t *pValue)
1034{
1035 AssertReturn(iReg <= USE_REG_DR7, VERR_INVALID_PARAMETER);
1036 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
1037 if (iReg == 4 || iReg == 5)
1038 iReg += 2;
1039 *pValue = pVCpu->cpum.s.Guest.dr[iReg];
1040 return VINF_SUCCESS;
1041}
1042
1043
1044VMMDECL(uint64_t) CPUMGetGuestEFER(PVMCPU pVCpu)
1045{
1046 return pVCpu->cpum.s.Guest.msrEFER;
1047}
1048
1049
1050/**
1051 * Gets a CpuId leaf.
1052 *
1053 * @param pVCpu The VMCPU handle.
1054 * @param iLeaf The CPUID leaf to get.
1055 * @param pEax Where to store the EAX value.
1056 * @param pEbx Where to store the EBX value.
1057 * @param pEcx Where to store the ECX value.
1058 * @param pEdx Where to store the EDX value.
1059 */
1060VMMDECL(void) CPUMGetGuestCpuId(PVMCPU pVCpu, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)
1061{
1062 PVM pVM = pVCpu->CTX_SUFF(pVM);
1063
1064 PCCPUMCPUID pCpuId;
1065 if (iLeaf < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd))
1066 pCpuId = &pVM->cpum.s.aGuestCpuIdStd[iLeaf];
1067 else if (iLeaf - UINT32_C(0x80000000) < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdExt))
1068 pCpuId = &pVM->cpum.s.aGuestCpuIdExt[iLeaf - UINT32_C(0x80000000)];
1069 else if (iLeaf - UINT32_C(0xc0000000) < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdCentaur))
1070 pCpuId = &pVM->cpum.s.aGuestCpuIdCentaur[iLeaf - UINT32_C(0xc0000000)];
1071 else
1072 pCpuId = &pVM->cpum.s.GuestCpuIdDef;
1073
1074 uint32_t cCurrentCacheIndex = *pEcx;
1075
1076 *pEax = pCpuId->eax;
1077 *pEbx = pCpuId->ebx;
1078 *pEcx = pCpuId->ecx;
1079 *pEdx = pCpuId->edx;
1080
1081 if ( iLeaf == 1)
1082 {
1083 /* Bits 31-24: Initial APIC ID */
1084 Assert(pVCpu->idCpu <= 255);
1085 *pEbx |= (pVCpu->idCpu << 24);
1086 }
1087
1088 if ( iLeaf == 4
1089 && cCurrentCacheIndex < 3
1090 && pVM->cpum.s.enmGuestCpuVendor == CPUMCPUVENDOR_INTEL)
1091 {
1092 uint32_t type, level, sharing, linesize,
1093 partitions, associativity, sets, cores;
1094
1095 /* For type: 1 - data cache, 2 - i-cache, 3 - unified */
1096 partitions = 1;
1097 /* Those are only to shut up compiler, as they will always
1098 get overwritten, and compiler should be able to figure that out */
1099 sets = associativity = sharing = level = 1;
1100 cores = pVM->cCpus > 32 ? 32 : pVM->cCpus;
1101 switch (cCurrentCacheIndex)
1102 {
1103 case 0:
1104 type = 1;
1105 level = 1;
1106 sharing = 1;
1107 linesize = 64;
1108 associativity = 8;
1109 sets = 64;
1110 break;
1111 case 1:
1112 level = 1;
1113 type = 2;
1114 sharing = 1;
1115 linesize = 64;
1116 associativity = 8;
1117 sets = 64;
1118 break;
1119 default: /* shut up gcc.*/
1120 AssertFailed();
1121 case 2:
1122 level = 2;
1123 type = 3;
1124 sharing = cores; /* our L2 cache is modelled as shared between all cores */
1125 linesize = 64;
1126 associativity = 24;
1127 sets = 4096;
1128 break;
1129 }
1130
1131 *pEax |= ((cores - 1) << 26) |
1132 ((sharing - 1) << 14) |
1133 (level << 5) |
1134 1;
1135 *pEbx = (linesize - 1) |
1136 ((partitions - 1) << 12) |
1137 ((associativity - 1) << 22); /* -1 encoding */
1138 *pEcx = sets - 1;
1139 }
1140
1141 Log2(("CPUMGetGuestCpuId: iLeaf=%#010x %RX32 %RX32 %RX32 %RX32\n", iLeaf, *pEax, *pEbx, *pEcx, *pEdx));
1142}
1143
1144/**
1145 * Gets a number of standard CPUID leafs.
1146 *
1147 * @returns Number of leafs.
1148 * @param pVM The VM handle.
1149 * @remark Intended for PATM.
1150 */
1151VMMDECL(uint32_t) CPUMGetGuestCpuIdStdMax(PVM pVM)
1152{
1153 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd);
1154}
1155
1156
1157/**
1158 * Gets a number of extended CPUID leafs.
1159 *
1160 * @returns Number of leafs.
1161 * @param pVM The VM handle.
1162 * @remark Intended for PATM.
1163 */
1164VMMDECL(uint32_t) CPUMGetGuestCpuIdExtMax(PVM pVM)
1165{
1166 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdExt);
1167}
1168
1169
1170/**
1171 * Gets a number of centaur CPUID leafs.
1172 *
1173 * @returns Number of leafs.
1174 * @param pVM The VM handle.
1175 * @remark Intended for PATM.
1176 */
1177VMMDECL(uint32_t) CPUMGetGuestCpuIdCentaurMax(PVM pVM)
1178{
1179 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdCentaur);
1180}
1181
1182
1183/**
1184 * Sets a CPUID feature bit.
1185 *
1186 * @param pVM The VM Handle.
1187 * @param enmFeature The feature to set.
1188 */
1189VMMDECL(void) CPUMSetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
1190{
1191 switch (enmFeature)
1192 {
1193 /*
1194 * Set the APIC bit in both feature masks.
1195 */
1196 case CPUMCPUIDFEATURE_APIC:
1197 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1198 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_APIC;
1199 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1200 && pVM->cpum.s.enmGuestCpuVendor == CPUMCPUVENDOR_AMD)
1201 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_APIC;
1202 LogRel(("CPUMSetGuestCpuIdFeature: Enabled APIC\n"));
1203 break;
1204
1205 /*
1206 * Set the x2APIC bit in the standard feature mask.
1207 */
1208 case CPUMCPUIDFEATURE_X2APIC:
1209 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1210 pVM->cpum.s.aGuestCpuIdStd[1].ecx |= X86_CPUID_FEATURE_ECX_X2APIC;
1211 LogRel(("CPUMSetGuestCpuIdFeature: Enabled x2APIC\n"));
1212 break;
1213
1214 /*
1215 * Set the sysenter/sysexit bit in the standard feature mask.
1216 * Assumes the caller knows what it's doing! (host must support these)
1217 */
1218 case CPUMCPUIDFEATURE_SEP:
1219 {
1220 if (!(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SEP))
1221 {
1222 AssertMsgFailed(("ERROR: Can't turn on SEP when the host doesn't support it!!\n"));
1223 return;
1224 }
1225
1226 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1227 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_SEP;
1228 LogRel(("CPUMSetGuestCpuIdFeature: Enabled sysenter/exit\n"));
1229 break;
1230 }
1231
1232 /*
1233 * Set the syscall/sysret bit in the extended feature mask.
1234 * Assumes the caller knows what it's doing! (host must support these)
1235 */
1236 case CPUMCPUIDFEATURE_SYSCALL:
1237 {
1238 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1239 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_SEP))
1240 {
1241#if HC_ARCH_BITS == 32
1242 /* X86_CPUID_AMD_FEATURE_EDX_SEP not set it seems in 32 bits mode.
1243 * Even when the cpu is capable of doing so in 64 bits mode.
1244 */
1245 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1246 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE)
1247 || !(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SEP))
1248#endif
1249 {
1250 LogRel(("WARNING: Can't turn on SYSCALL/SYSRET when the host doesn't support it!!\n"));
1251 return;
1252 }
1253 }
1254 /* Valid for both Intel and AMD CPUs, although only in 64 bits mode for Intel. */
1255 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_SEP;
1256 LogRel(("CPUMSetGuestCpuIdFeature: Enabled syscall/ret\n"));
1257 break;
1258 }
1259
1260 /*
1261 * Set the PAE bit in both feature masks.
1262 * Assumes the caller knows what it's doing! (host must support these)
1263 */
1264 case CPUMCPUIDFEATURE_PAE:
1265 {
1266 if (!(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_PAE))
1267 {
1268 LogRel(("WARNING: Can't turn on PAE when the host doesn't support it!!\n"));
1269 return;
1270 }
1271
1272 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1273 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_PAE;
1274 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1275 && pVM->cpum.s.enmGuestCpuVendor == CPUMCPUVENDOR_AMD)
1276 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_PAE;
1277 LogRel(("CPUMSetGuestCpuIdFeature: Enabled PAE\n"));
1278 break;
1279 }
1280
1281 /*
1282 * Set the LONG MODE bit in the extended feature mask.
1283 * Assumes the caller knows what it's doing! (host must support these)
1284 */
1285 case CPUMCPUIDFEATURE_LONG_MODE:
1286 {
1287 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1288 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE))
1289 {
1290 LogRel(("WARNING: Can't turn on LONG MODE when the host doesn't support it!!\n"));
1291 return;
1292 }
1293
1294 /* Valid for both Intel and AMD. */
1295 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_LONG_MODE;
1296 LogRel(("CPUMSetGuestCpuIdFeature: Enabled LONG MODE\n"));
1297 break;
1298 }
1299
1300 /*
1301 * Set the NXE bit in the extended feature mask.
1302 * Assumes the caller knows what it's doing! (host must support these)
1303 */
1304 case CPUMCPUIDFEATURE_NXE:
1305 {
1306 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1307 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_NX))
1308 {
1309 LogRel(("WARNING: Can't turn on NXE when the host doesn't support it!!\n"));
1310 return;
1311 }
1312
1313 /* Valid for both Intel and AMD. */
1314 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_NX;
1315 LogRel(("CPUMSetGuestCpuIdFeature: Enabled NXE\n"));
1316 break;
1317 }
1318
1319 case CPUMCPUIDFEATURE_LAHF:
1320 {
1321 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1322 || !(ASMCpuId_ECX(0x80000001) & X86_CPUID_AMD_FEATURE_ECX_LAHF_SAHF))
1323 {
1324 LogRel(("WARNING: Can't turn on LAHF/SAHF when the host doesn't support it!!\n"));
1325 return;
1326 }
1327
1328 pVM->cpum.s.aGuestCpuIdExt[1].ecx |= X86_CPUID_AMD_FEATURE_ECX_LAHF_SAHF;
1329 LogRel(("CPUMSetGuestCpuIdFeature: Enabled LAHF/SAHF\n"));
1330 break;
1331 }
1332
1333 case CPUMCPUIDFEATURE_PAT:
1334 {
1335 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1336 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_PAT;
1337 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1338 && pVM->cpum.s.enmGuestCpuVendor == CPUMCPUVENDOR_AMD)
1339 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_PAT;
1340 LogRel(("CPUMClearGuestCpuIdFeature: Enabled PAT\n"));
1341 break;
1342 }
1343
1344 case CPUMCPUIDFEATURE_RDTSCP:
1345 {
1346 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1347 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_RDTSCP))
1348 {
1349 LogRel(("WARNING: Can't turn on RDTSCP when the host doesn't support it!!\n"));
1350 return;
1351 }
1352
1353 /* Valid for AMD only (for now). */
1354 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_RDTSCP;
1355 LogRel(("CPUMSetGuestCpuIdFeature: Enabled RDTSCP.\n"));
1356 break;
1357 }
1358
1359 default:
1360 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
1361 break;
1362 }
1363 for (VMCPUID i = 0; i < pVM->cCpus; i++)
1364 {
1365 PVMCPU pVCpu = &pVM->aCpus[i];
1366 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CPUID;
1367 }
1368}
1369
1370
1371/**
1372 * Queries a CPUID feature bit.
1373 *
1374 * @returns boolean for feature presence
1375 * @param pVM The VM Handle.
1376 * @param enmFeature The feature to query.
1377 */
1378VMMDECL(bool) CPUMGetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
1379{
1380 switch (enmFeature)
1381 {
1382 case CPUMCPUIDFEATURE_PAE:
1383 {
1384 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1385 return !!(pVM->cpum.s.aGuestCpuIdStd[1].edx & X86_CPUID_FEATURE_EDX_PAE);
1386 break;
1387 }
1388
1389 case CPUMCPUIDFEATURE_RDTSCP:
1390 {
1391 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1392 return !!(pVM->cpum.s.aGuestCpuIdExt[1].edx & X86_CPUID_AMD_FEATURE_EDX_RDTSCP);
1393 break;
1394 }
1395
1396 case CPUMCPUIDFEATURE_LONG_MODE:
1397 {
1398 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1399 return !!(pVM->cpum.s.aGuestCpuIdExt[1].edx & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE);
1400 break;
1401 }
1402
1403 default:
1404 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
1405 break;
1406 }
1407 return false;
1408}
1409
1410
1411/**
1412 * Clears a CPUID feature bit.
1413 *
1414 * @param pVM The VM Handle.
1415 * @param enmFeature The feature to clear.
1416 */
1417VMMDECL(void) CPUMClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
1418{
1419 switch (enmFeature)
1420 {
1421 /*
1422 * Set the APIC bit in both feature masks.
1423 */
1424 case CPUMCPUIDFEATURE_APIC:
1425 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1426 pVM->cpum.s.aGuestCpuIdStd[1].edx &= ~X86_CPUID_FEATURE_EDX_APIC;
1427 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1428 && pVM->cpum.s.enmGuestCpuVendor == CPUMCPUVENDOR_AMD)
1429 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_APIC;
1430 Log(("CPUMSetGuestCpuIdFeature: Disabled APIC\n"));
1431 break;
1432
1433 /*
1434 * Clear the x2APIC bit in the standard feature mask.
1435 */
1436 case CPUMCPUIDFEATURE_X2APIC:
1437 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1438 pVM->cpum.s.aGuestCpuIdStd[1].ecx &= ~X86_CPUID_FEATURE_ECX_X2APIC;
1439 LogRel(("CPUMSetGuestCpuIdFeature: Disabled x2APIC\n"));
1440 break;
1441
1442 case CPUMCPUIDFEATURE_PAE:
1443 {
1444 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1445 pVM->cpum.s.aGuestCpuIdStd[1].edx &= ~X86_CPUID_FEATURE_EDX_PAE;
1446 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1447 && pVM->cpum.s.enmGuestCpuVendor == CPUMCPUVENDOR_AMD)
1448 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_PAE;
1449 LogRel(("CPUMClearGuestCpuIdFeature: Disabled PAE!\n"));
1450 break;
1451 }
1452
1453 case CPUMCPUIDFEATURE_PAT:
1454 {
1455 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1456 pVM->cpum.s.aGuestCpuIdStd[1].edx &= ~X86_CPUID_FEATURE_EDX_PAT;
1457 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1458 && pVM->cpum.s.enmGuestCpuVendor == CPUMCPUVENDOR_AMD)
1459 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_PAT;
1460 LogRel(("CPUMClearGuestCpuIdFeature: Disabled PAT!\n"));
1461 break;
1462 }
1463
1464 case CPUMCPUIDFEATURE_LONG_MODE:
1465 {
1466 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1467 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_LONG_MODE;
1468 break;
1469 }
1470
1471 case CPUMCPUIDFEATURE_LAHF:
1472 {
1473 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1474 pVM->cpum.s.aGuestCpuIdExt[1].ecx &= ~X86_CPUID_AMD_FEATURE_ECX_LAHF_SAHF;
1475 break;
1476 }
1477
1478 default:
1479 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
1480 break;
1481 }
1482 for (VMCPUID i = 0; i < pVM->cCpus; i++)
1483 {
1484 PVMCPU pVCpu = &pVM->aCpus[i];
1485 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CPUID;
1486 }
1487}
1488
1489
1490/**
1491 * Gets the host CPU vendor
1492 *
1493 * @returns CPU vendor
1494 * @param pVM The VM handle.
1495 */
1496VMMDECL(CPUMCPUVENDOR) CPUMGetHostCpuVendor(PVM pVM)
1497{
1498 return pVM->cpum.s.enmHostCpuVendor;
1499}
1500
1501/**
1502 * Gets the CPU vendor
1503 *
1504 * @returns CPU vendor
1505 * @param pVM The VM handle.
1506 */
1507VMMDECL(CPUMCPUVENDOR) CPUMGetGuestCpuVendor(PVM pVM)
1508{
1509 return pVM->cpum.s.enmGuestCpuVendor;
1510}
1511
1512
1513VMMDECL(int) CPUMSetGuestDR0(PVMCPU pVCpu, uint64_t uDr0)
1514{
1515 pVCpu->cpum.s.Guest.dr[0] = uDr0;
1516 return CPUMRecalcHyperDRx(pVCpu);
1517}
1518
1519
1520VMMDECL(int) CPUMSetGuestDR1(PVMCPU pVCpu, uint64_t uDr1)
1521{
1522 pVCpu->cpum.s.Guest.dr[1] = uDr1;
1523 return CPUMRecalcHyperDRx(pVCpu);
1524}
1525
1526
1527VMMDECL(int) CPUMSetGuestDR2(PVMCPU pVCpu, uint64_t uDr2)
1528{
1529 pVCpu->cpum.s.Guest.dr[2] = uDr2;
1530 return CPUMRecalcHyperDRx(pVCpu);
1531}
1532
1533
1534VMMDECL(int) CPUMSetGuestDR3(PVMCPU pVCpu, uint64_t uDr3)
1535{
1536 pVCpu->cpum.s.Guest.dr[3] = uDr3;
1537 return CPUMRecalcHyperDRx(pVCpu);
1538}
1539
1540
1541VMMDECL(int) CPUMSetGuestDR6(PVMCPU pVCpu, uint64_t uDr6)
1542{
1543 pVCpu->cpum.s.Guest.dr[6] = uDr6;
1544 return CPUMRecalcHyperDRx(pVCpu);
1545}
1546
1547
1548VMMDECL(int) CPUMSetGuestDR7(PVMCPU pVCpu, uint64_t uDr7)
1549{
1550 pVCpu->cpum.s.Guest.dr[7] = uDr7;
1551 return CPUMRecalcHyperDRx(pVCpu);
1552}
1553
1554
1555VMMDECL(int) CPUMSetGuestDRx(PVMCPU pVCpu, uint32_t iReg, uint64_t Value)
1556{
1557 AssertReturn(iReg <= USE_REG_DR7, VERR_INVALID_PARAMETER);
1558 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
1559 if (iReg == 4 || iReg == 5)
1560 iReg += 2;
1561 pVCpu->cpum.s.Guest.dr[iReg] = Value;
1562 return CPUMRecalcHyperDRx(pVCpu);
1563}
1564
1565
1566/**
1567 * Recalculates the hypvervisor DRx register values based on
1568 * current guest registers and DBGF breakpoints.
1569 *
1570 * This is called whenever a guest DRx register is modified and when DBGF
1571 * sets a hardware breakpoint. In guest context this function will reload
1572 * any (hyper) DRx registers which comes out with a different value.
1573 *
1574 * @returns VINF_SUCCESS.
1575 * @param pVCpu The VMCPU handle.
1576 */
1577VMMDECL(int) CPUMRecalcHyperDRx(PVMCPU pVCpu)
1578{
1579 PVM pVM = pVCpu->CTX_SUFF(pVM);
1580
1581 /*
1582 * Compare the DR7s first.
1583 *
1584 * We only care about the enabled flags. The GE and LE flags are always
1585 * set and we don't care if the guest doesn't set them. GD is virtualized
1586 * when we dispatch #DB, we never enable it.
1587 */
1588 const RTGCUINTREG uDbgfDr7 = DBGFBpGetDR7(pVM);
1589#ifdef CPUM_VIRTUALIZE_DRX
1590 const RTGCUINTREG uGstDr7 = CPUMGetGuestDR7(pVCpu);
1591#else
1592 const RTGCUINTREG uGstDr7 = 0;
1593#endif
1594 if ((uGstDr7 | uDbgfDr7) & X86_DR7_ENABLED_MASK)
1595 {
1596 /*
1597 * Ok, something is enabled. Recalc each of the breakpoints.
1598 * Straight forward code, not optimized/minimized in any way.
1599 */
1600 RTGCUINTREG uNewDr7 = X86_DR7_GE | X86_DR7_LE | X86_DR7_MB1_MASK;
1601
1602 /* bp 0 */
1603 RTGCUINTREG uNewDr0;
1604 if (uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0))
1605 {
1606 uNewDr7 |= uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
1607 uNewDr0 = DBGFBpGetDR0(pVM);
1608 }
1609 else if (uGstDr7 & (X86_DR7_L0 | X86_DR7_G0))
1610 {
1611 uNewDr7 |= uGstDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
1612 uNewDr0 = CPUMGetGuestDR0(pVCpu);
1613 }
1614 else
1615 uNewDr0 = pVCpu->cpum.s.Hyper.dr[0];
1616
1617 /* bp 1 */
1618 RTGCUINTREG uNewDr1;
1619 if (uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1))
1620 {
1621 uNewDr7 |= uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
1622 uNewDr1 = DBGFBpGetDR1(pVM);
1623 }
1624 else if (uGstDr7 & (X86_DR7_L1 | X86_DR7_G1))
1625 {
1626 uNewDr7 |= uGstDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
1627 uNewDr1 = CPUMGetGuestDR1(pVCpu);
1628 }
1629 else
1630 uNewDr1 = pVCpu->cpum.s.Hyper.dr[1];
1631
1632 /* bp 2 */
1633 RTGCUINTREG uNewDr2;
1634 if (uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2))
1635 {
1636 uNewDr7 |= uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
1637 uNewDr2 = DBGFBpGetDR2(pVM);
1638 }
1639 else if (uGstDr7 & (X86_DR7_L2 | X86_DR7_G2))
1640 {
1641 uNewDr7 |= uGstDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
1642 uNewDr2 = CPUMGetGuestDR2(pVCpu);
1643 }
1644 else
1645 uNewDr2 = pVCpu->cpum.s.Hyper.dr[2];
1646
1647 /* bp 3 */
1648 RTGCUINTREG uNewDr3;
1649 if (uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3))
1650 {
1651 uNewDr7 |= uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
1652 uNewDr3 = DBGFBpGetDR3(pVM);
1653 }
1654 else if (uGstDr7 & (X86_DR7_L3 | X86_DR7_G3))
1655 {
1656 uNewDr7 |= uGstDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
1657 uNewDr3 = CPUMGetGuestDR3(pVCpu);
1658 }
1659 else
1660 uNewDr3 = pVCpu->cpum.s.Hyper.dr[3];
1661
1662 /*
1663 * Apply the updates.
1664 */
1665#ifdef IN_RC
1666 if (!(pVCpu->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS))
1667 {
1668 /** @todo save host DBx registers. */
1669 }
1670#endif
1671 pVCpu->cpum.s.fUseFlags |= CPUM_USE_DEBUG_REGS;
1672 if (uNewDr3 != pVCpu->cpum.s.Hyper.dr[3])
1673 CPUMSetHyperDR3(pVCpu, uNewDr3);
1674 if (uNewDr2 != pVCpu->cpum.s.Hyper.dr[2])
1675 CPUMSetHyperDR2(pVCpu, uNewDr2);
1676 if (uNewDr1 != pVCpu->cpum.s.Hyper.dr[1])
1677 CPUMSetHyperDR1(pVCpu, uNewDr1);
1678 if (uNewDr0 != pVCpu->cpum.s.Hyper.dr[0])
1679 CPUMSetHyperDR0(pVCpu, uNewDr0);
1680 if (uNewDr7 != pVCpu->cpum.s.Hyper.dr[7])
1681 CPUMSetHyperDR7(pVCpu, uNewDr7);
1682 }
1683 else
1684 {
1685#ifdef IN_RC
1686 if (pVCpu->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS)
1687 {
1688 /** @todo restore host DBx registers. */
1689 }
1690#endif
1691 pVCpu->cpum.s.fUseFlags &= ~CPUM_USE_DEBUG_REGS;
1692 }
1693 Log2(("CPUMRecalcHyperDRx: fUseFlags=%#x %RGr %RGr %RGr %RGr %RGr %RGr\n",
1694 pVCpu->cpum.s.fUseFlags, pVCpu->cpum.s.Hyper.dr[0], pVCpu->cpum.s.Hyper.dr[1],
1695 pVCpu->cpum.s.Hyper.dr[2], pVCpu->cpum.s.Hyper.dr[3], pVCpu->cpum.s.Hyper.dr[6],
1696 pVCpu->cpum.s.Hyper.dr[7]));
1697
1698 return VINF_SUCCESS;
1699}
1700
1701
1702/**
1703 * Tests if the guest has No-Execute Page Protection Enabled (NXE).
1704 *
1705 * @returns true if in real mode, otherwise false.
1706 * @param pVCpu The virtual CPU handle.
1707 */
1708VMMDECL(bool) CPUMIsGuestNXEnabled(PVMCPU pVCpu)
1709{
1710 return !!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_NXE);
1711}
1712
1713
1714/**
1715 * Tests if the guest has the Page Size Extension enabled (PSE).
1716 *
1717 * @returns true if in real mode, otherwise false.
1718 * @param pVCpu The virtual CPU handle.
1719 */
1720VMMDECL(bool) CPUMIsGuestPageSizeExtEnabled(PVMCPU pVCpu)
1721{
1722 /* PAE or AMD64 implies support for big pages regardless of CR4.PSE */
1723 return !!(pVCpu->cpum.s.Guest.cr4 & (X86_CR4_PSE | X86_CR4_PAE));
1724}
1725
1726
1727/**
1728 * Tests if the guest has the paging enabled (PG).
1729 *
1730 * @returns true if in real mode, otherwise false.
1731 * @param pVCpu The virtual CPU handle.
1732 */
1733VMMDECL(bool) CPUMIsGuestPagingEnabled(PVMCPU pVCpu)
1734{
1735 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PG);
1736}
1737
1738
1739/**
1740 * Tests if the guest has the paging enabled (PG).
1741 *
1742 * @returns true if in real mode, otherwise false.
1743 * @param pVCpu The virtual CPU handle.
1744 */
1745VMMDECL(bool) CPUMIsGuestR0WriteProtEnabled(PVMCPU pVCpu)
1746{
1747 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_WP);
1748}
1749
1750
1751/**
1752 * Tests if the guest is running in real mode or not.
1753 *
1754 * @returns true if in real mode, otherwise false.
1755 * @param pVCpu The virtual CPU handle.
1756 */
1757VMMDECL(bool) CPUMIsGuestInRealMode(PVMCPU pVCpu)
1758{
1759 return !(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE);
1760}
1761
1762
1763/**
1764 * Tests if the guest is running in protected or not.
1765 *
1766 * @returns true if in protected mode, otherwise false.
1767 * @param pVCpu The virtual CPU handle.
1768 */
1769VMMDECL(bool) CPUMIsGuestInProtectedMode(PVMCPU pVCpu)
1770{
1771 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE);
1772}
1773
1774
1775/**
1776 * Tests if the guest is running in paged protected or not.
1777 *
1778 * @returns true if in paged protected mode, otherwise false.
1779 * @param pVCpu The virtual CPU handle.
1780 */
1781VMMDECL(bool) CPUMIsGuestInPagedProtectedMode(PVMCPU pVCpu)
1782{
1783 return (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG);
1784}
1785
1786
1787/**
1788 * Tests if the guest is running in long mode or not.
1789 *
1790 * @returns true if in long mode, otherwise false.
1791 * @param pVCpu The virtual CPU handle.
1792 */
1793VMMDECL(bool) CPUMIsGuestInLongMode(PVMCPU pVCpu)
1794{
1795 return (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA) == MSR_K6_EFER_LMA;
1796}
1797
1798
1799/**
1800 * Tests if the guest is running in PAE mode or not.
1801 *
1802 * @returns true if in PAE mode, otherwise false.
1803 * @param pVCpu The virtual CPU handle.
1804 */
1805VMMDECL(bool) CPUMIsGuestInPAEMode(PVMCPU pVCpu)
1806{
1807 return (pVCpu->cpum.s.Guest.cr4 & X86_CR4_PAE)
1808 && (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG)
1809 && !(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA);
1810}
1811
1812
1813
1814#ifndef IN_RING0 /** @todo I don't think we need this in R0, so move it to CPUMAll.cpp? */
1815
1816/**
1817 * Transforms the guest CPU state to raw-ring mode.
1818 *
1819 * This function will change the any of the cs and ss register with DPL=0 to DPL=1.
1820 *
1821 * @returns VBox status. (recompiler failure)
1822 * @param pVCpu The VMCPU handle.
1823 * @param pCtxCore The context core (for trap usage).
1824 * @see @ref pg_raw
1825 */
1826VMMDECL(int) CPUMRawEnter(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
1827{
1828 PVM pVM = pVCpu->CTX_SUFF(pVM);
1829
1830 Assert(!pVM->cpum.s.fRawEntered);
1831 if (!pCtxCore)
1832 pCtxCore = CPUMCTX2CORE(&pVCpu->cpum.s.Guest);
1833
1834 /*
1835 * Are we in Ring-0?
1836 */
1837 if ( pCtxCore->ss && (pCtxCore->ss & X86_SEL_RPL) == 0
1838 && !pCtxCore->eflags.Bits.u1VM)
1839 {
1840 /*
1841 * Enter execution mode.
1842 */
1843 PATMRawEnter(pVM, pCtxCore);
1844
1845 /*
1846 * Set CPL to Ring-1.
1847 */
1848 pCtxCore->ss |= 1;
1849 if (pCtxCore->cs && (pCtxCore->cs & X86_SEL_RPL) == 0)
1850 pCtxCore->cs |= 1;
1851 }
1852 else
1853 {
1854 AssertMsg((pCtxCore->ss & X86_SEL_RPL) >= 2 || pCtxCore->eflags.Bits.u1VM,
1855 ("ring-1 code not supported\n"));
1856 /*
1857 * PATM takes care of IOPL and IF flags for Ring-3 and Ring-2 code as well.
1858 */
1859 PATMRawEnter(pVM, pCtxCore);
1860 }
1861
1862 /*
1863 * Assert sanity.
1864 */
1865 AssertMsg((pCtxCore->eflags.u32 & X86_EFL_IF), ("X86_EFL_IF is clear\n"));
1866 AssertReleaseMsg( pCtxCore->eflags.Bits.u2IOPL < (unsigned)(pCtxCore->ss & X86_SEL_RPL)
1867 || pCtxCore->eflags.Bits.u1VM,
1868 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss & X86_SEL_RPL));
1869 Assert((pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) == (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP));
1870 pCtxCore->eflags.u32 |= X86_EFL_IF; /* paranoia */
1871
1872 pVM->cpum.s.fRawEntered = true;
1873 return VINF_SUCCESS;
1874}
1875
1876
1877/**
1878 * Transforms the guest CPU state from raw-ring mode to correct values.
1879 *
1880 * This function will change any selector registers with DPL=1 to DPL=0.
1881 *
1882 * @returns Adjusted rc.
1883 * @param pVCpu The VMCPU handle.
1884 * @param rc Raw mode return code
1885 * @param pCtxCore The context core (for trap usage).
1886 * @see @ref pg_raw
1887 */
1888VMMDECL(int) CPUMRawLeave(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, int rc)
1889{
1890 PVM pVM = pVCpu->CTX_SUFF(pVM);
1891
1892 /*
1893 * Don't leave if we've already left (in GC).
1894 */
1895 Assert(pVM->cpum.s.fRawEntered);
1896 if (!pVM->cpum.s.fRawEntered)
1897 return rc;
1898 pVM->cpum.s.fRawEntered = false;
1899
1900 PCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
1901 if (!pCtxCore)
1902 pCtxCore = CPUMCTX2CORE(pCtx);
1903 Assert(pCtxCore->eflags.Bits.u1VM || (pCtxCore->ss & X86_SEL_RPL));
1904 AssertMsg(pCtxCore->eflags.Bits.u1VM || pCtxCore->eflags.Bits.u2IOPL < (unsigned)(pCtxCore->ss & X86_SEL_RPL),
1905 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss & X86_SEL_RPL));
1906
1907 /*
1908 * Are we executing in raw ring-1?
1909 */
1910 if ( (pCtxCore->ss & X86_SEL_RPL) == 1
1911 && !pCtxCore->eflags.Bits.u1VM)
1912 {
1913 /*
1914 * Leave execution mode.
1915 */
1916 PATMRawLeave(pVM, pCtxCore, rc);
1917 /* Not quite sure if this is really required, but shouldn't harm (too much anyways). */
1918 /** @todo See what happens if we remove this. */
1919 if ((pCtxCore->ds & X86_SEL_RPL) == 1)
1920 pCtxCore->ds &= ~X86_SEL_RPL;
1921 if ((pCtxCore->es & X86_SEL_RPL) == 1)
1922 pCtxCore->es &= ~X86_SEL_RPL;
1923 if ((pCtxCore->fs & X86_SEL_RPL) == 1)
1924 pCtxCore->fs &= ~X86_SEL_RPL;
1925 if ((pCtxCore->gs & X86_SEL_RPL) == 1)
1926 pCtxCore->gs &= ~X86_SEL_RPL;
1927
1928 /*
1929 * Ring-1 selector => Ring-0.
1930 */
1931 pCtxCore->ss &= ~X86_SEL_RPL;
1932 if ((pCtxCore->cs & X86_SEL_RPL) == 1)
1933 pCtxCore->cs &= ~X86_SEL_RPL;
1934 }
1935 else
1936 {
1937 /*
1938 * PATM is taking care of the IOPL and IF flags for us.
1939 */
1940 PATMRawLeave(pVM, pCtxCore, rc);
1941 if (!pCtxCore->eflags.Bits.u1VM)
1942 {
1943 /** @todo See what happens if we remove this. */
1944 if ((pCtxCore->ds & X86_SEL_RPL) == 1)
1945 pCtxCore->ds &= ~X86_SEL_RPL;
1946 if ((pCtxCore->es & X86_SEL_RPL) == 1)
1947 pCtxCore->es &= ~X86_SEL_RPL;
1948 if ((pCtxCore->fs & X86_SEL_RPL) == 1)
1949 pCtxCore->fs &= ~X86_SEL_RPL;
1950 if ((pCtxCore->gs & X86_SEL_RPL) == 1)
1951 pCtxCore->gs &= ~X86_SEL_RPL;
1952 }
1953 }
1954
1955 return rc;
1956}
1957
1958/**
1959 * Updates the EFLAGS while we're in raw-mode.
1960 *
1961 * @param pVCpu The VMCPU handle.
1962 * @param pCtxCore The context core.
1963 * @param eflags The new EFLAGS value.
1964 */
1965VMMDECL(void) CPUMRawSetEFlags(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, uint32_t eflags)
1966{
1967 PVM pVM = pVCpu->CTX_SUFF(pVM);
1968
1969 if (!pVM->cpum.s.fRawEntered)
1970 {
1971 pCtxCore->eflags.u32 = eflags;
1972 return;
1973 }
1974 PATMRawSetEFlags(pVM, pCtxCore, eflags);
1975}
1976
1977#endif /* !IN_RING0 */
1978
1979/**
1980 * Gets the EFLAGS while we're in raw-mode.
1981 *
1982 * @returns The eflags.
1983 * @param pVCpu The VMCPU handle.
1984 * @param pCtxCore The context core.
1985 */
1986VMMDECL(uint32_t) CPUMRawGetEFlags(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
1987{
1988#ifdef IN_RING0
1989 return pCtxCore->eflags.u32;
1990#else
1991 PVM pVM = pVCpu->CTX_SUFF(pVM);
1992
1993 if (!pVM->cpum.s.fRawEntered)
1994 return pCtxCore->eflags.u32;
1995 return PATMRawGetEFlags(pVM, pCtxCore);
1996#endif
1997}
1998
1999
2000/**
2001 * Gets and resets the changed flags (CPUM_CHANGED_*).
2002 * Only REM should call this function.
2003 *
2004 * @returns The changed flags.
2005 * @param pVCpu The VMCPU handle.
2006 */
2007VMMDECL(unsigned) CPUMGetAndClearChangedFlagsREM(PVMCPU pVCpu)
2008{
2009 unsigned fFlags = pVCpu->cpum.s.fChanged;
2010 pVCpu->cpum.s.fChanged = 0;
2011 /** @todo change the switcher to use the fChanged flags. */
2012 if (pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU_SINCE_REM)
2013 {
2014 fFlags |= CPUM_CHANGED_FPU_REM;
2015 pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_FPU_SINCE_REM;
2016 }
2017 return fFlags;
2018}
2019
2020
2021/**
2022 * Sets the specified changed flags (CPUM_CHANGED_*).
2023 *
2024 * @param pVCpu The VMCPU handle.
2025 */
2026VMMDECL(void) CPUMSetChangedFlags(PVMCPU pVCpu, uint32_t fChangedFlags)
2027{
2028 pVCpu->cpum.s.fChanged |= fChangedFlags;
2029}
2030
2031
2032/**
2033 * Checks if the CPU supports the FXSAVE and FXRSTOR instruction.
2034 * @returns true if supported.
2035 * @returns false if not supported.
2036 * @param pVM The VM handle.
2037 */
2038VMMDECL(bool) CPUMSupportsFXSR(PVM pVM)
2039{
2040 return pVM->cpum.s.CPUFeatures.edx.u1FXSR != 0;
2041}
2042
2043
2044/**
2045 * Checks if the host OS uses the SYSENTER / SYSEXIT instructions.
2046 * @returns true if used.
2047 * @returns false if not used.
2048 * @param pVM The VM handle.
2049 */
2050VMMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM)
2051{
2052 return (pVM->cpum.s.fHostUseFlags & CPUM_USE_SYSENTER) != 0;
2053}
2054
2055
2056/**
2057 * Checks if the host OS uses the SYSCALL / SYSRET instructions.
2058 * @returns true if used.
2059 * @returns false if not used.
2060 * @param pVM The VM handle.
2061 */
2062VMMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM)
2063{
2064 return (pVM->cpum.s.fHostUseFlags & CPUM_USE_SYSCALL) != 0;
2065}
2066
2067#ifndef IN_RING3
2068
2069/**
2070 * Lazily sync in the FPU/XMM state
2071 *
2072 * @returns VBox status code.
2073 * @param pVCpu VMCPU handle
2074 */
2075VMMDECL(int) CPUMHandleLazyFPU(PVMCPU pVCpu)
2076{
2077 return cpumHandleLazyFPUAsm(&pVCpu->cpum.s);
2078}
2079
2080#endif /* !IN_RING3 */
2081
2082/**
2083 * Checks if we activated the FPU/XMM state of the guest OS
2084 * @returns true if we did.
2085 * @returns false if not.
2086 * @param pVCpu The VMCPU handle.
2087 */
2088VMMDECL(bool) CPUMIsGuestFPUStateActive(PVMCPU pVCpu)
2089{
2090 return (pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU) != 0;
2091}
2092
2093
2094/**
2095 * Deactivate the FPU/XMM state of the guest OS
2096 * @param pVCpu The VMCPU handle.
2097 */
2098VMMDECL(void) CPUMDeactivateGuestFPUState(PVMCPU pVCpu)
2099{
2100 pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_FPU;
2101}
2102
2103
2104/**
2105 * Checks if the guest debug state is active
2106 *
2107 * @returns boolean
2108 * @param pVM VM handle.
2109 */
2110VMMDECL(bool) CPUMIsGuestDebugStateActive(PVMCPU pVCpu)
2111{
2112 return (pVCpu->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS) != 0;
2113}
2114
2115/**
2116 * Checks if the hyper debug state is active
2117 *
2118 * @returns boolean
2119 * @param pVM VM handle.
2120 */
2121VMMDECL(bool) CPUMIsHyperDebugStateActive(PVMCPU pVCpu)
2122{
2123 return (pVCpu->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS_HYPER) != 0;
2124}
2125
2126
2127/**
2128 * Mark the guest's debug state as inactive
2129 *
2130 * @returns boolean
2131 * @param pVM VM handle.
2132 */
2133VMMDECL(void) CPUMDeactivateGuestDebugState(PVMCPU pVCpu)
2134{
2135 pVCpu->cpum.s.fUseFlags &= ~CPUM_USE_DEBUG_REGS;
2136}
2137
2138
2139/**
2140 * Mark the hypervisor's debug state as inactive
2141 *
2142 * @returns boolean
2143 * @param pVM VM handle.
2144 */
2145VMMDECL(void) CPUMDeactivateHyperDebugState(PVMCPU pVCpu)
2146{
2147 pVCpu->cpum.s.fUseFlags &= ~CPUM_USE_DEBUG_REGS_HYPER;
2148}
2149
2150/**
2151 * Checks if the hidden selector registers are valid
2152 * @returns true if they are.
2153 * @returns false if not.
2154 * @param pVM The VM handle.
2155 */
2156VMMDECL(bool) CPUMAreHiddenSelRegsValid(PVM pVM)
2157{
2158 return HWACCMIsEnabled(pVM);
2159}
2160
2161
2162
2163/**
2164 * Get the current privilege level of the guest.
2165 *
2166 * @returns cpl
2167 * @param pVM VM Handle.
2168 * @param pRegFrame Trap register frame.
2169 */
2170VMMDECL(uint32_t) CPUMGetGuestCPL(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
2171{
2172 uint32_t cpl;
2173
2174 if (CPUMAreHiddenSelRegsValid(pVCpu->CTX_SUFF(pVM)))
2175 {
2176 /*
2177 * The hidden CS.DPL register is always equal to the CPL, it is
2178 * not affected by loading a conforming coding segment.
2179 *
2180 * This only seems to apply to AMD-V; in the VT-x case we *do* need to look
2181 * at SS. (ACP2 regression during install after a far call to ring 2)
2182 */
2183 if (RT_LIKELY(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
2184 cpl = pCtxCore->ssHid.Attr.n.u2Dpl;
2185 else
2186 cpl = 0; /* CPL set to 3 for VT-x real-mode emulation. */
2187 }
2188 else if (RT_LIKELY(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
2189 {
2190 if (RT_LIKELY(!pCtxCore->eflags.Bits.u1VM))
2191 {
2192 /*
2193 * The SS RPL is always equal to the CPL, while the CS RPL
2194 * isn't necessarily equal if the segment is conforming.
2195 * See section 4.11.1 in the AMD manual.
2196 */
2197 cpl = (pCtxCore->ss & X86_SEL_RPL);
2198#ifndef IN_RING0
2199 if (cpl == 1)
2200 cpl = 0;
2201#endif
2202 }
2203 else
2204 cpl = 3;
2205 }
2206 else
2207 cpl = 0; /* real mode; cpl is zero */
2208
2209 return cpl;
2210}
2211
2212
2213/**
2214 * Gets the current guest CPU mode.
2215 *
2216 * If paging mode is what you need, check out PGMGetGuestMode().
2217 *
2218 * @returns The CPU mode.
2219 * @param pVCpu The VMCPU handle.
2220 */
2221VMMDECL(CPUMMODE) CPUMGetGuestMode(PVMCPU pVCpu)
2222{
2223 CPUMMODE enmMode;
2224 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
2225 enmMode = CPUMMODE_REAL;
2226 else if (!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
2227 enmMode = CPUMMODE_PROTECTED;
2228 else
2229 enmMode = CPUMMODE_LONG;
2230
2231 return enmMode;
2232}
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