VirtualBox

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

Last change on this file since 14446 was 14411, checked in by vboxsync, 16 years ago

RDTSCP support added. Enabled only for AMD-V guests.

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