VirtualBox

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

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

X86_CPUID_AMD_FEATURE_EDX_SEP not set it seems in 32 bits mode. (Intel)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 56.8 KB
Line 
1/* $Id: CPUMAllRegs.cpp 15390 2008-12-12 17:33:23Z 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#if HC_ARCH_BITS == 32
1361 /* X86_CPUID_AMD_FEATURE_EDX_SEP not set it seems in 32 bits mode.
1362 * Even when the cpu is capable of doing so in 64 bits mode.
1363 */
1364 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1365 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE)
1366 || !(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SEP))
1367#endif
1368 {
1369 LogRel(("WARNING: Can't turn on SYSCALL/SYSRET when the host doesn't support it!!\n"));
1370 return;
1371 }
1372 }
1373 /* Valid for both Intel and AMD CPUs, although only in 64 bits mode for Intel. */
1374 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_SEP;
1375 LogRel(("CPUMSetGuestCpuIdFeature: Enabled syscall/ret\n"));
1376 break;
1377 }
1378
1379 /*
1380 * Set the PAE bit in both feature masks.
1381 * Assumes the caller knows what it's doing! (host must support these)
1382 */
1383 case CPUMCPUIDFEATURE_PAE:
1384 {
1385 if (!(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_PAE))
1386 {
1387 LogRel(("WARNING: Can't turn on PAE when the host doesn't support it!!\n"));
1388 return;
1389 }
1390
1391 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1392 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_PAE;
1393 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1394 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1395 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_PAE;
1396 LogRel(("CPUMSetGuestCpuIdFeature: Enabled PAE\n"));
1397 break;
1398 }
1399
1400 /*
1401 * Set the LONG MODE bit in the extended feature mask.
1402 * Assumes the caller knows what it's doing! (host must support these)
1403 */
1404 case CPUMCPUIDFEATURE_LONG_MODE:
1405 {
1406 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1407 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE))
1408 {
1409 LogRel(("WARNING: Can't turn on LONG MODE when the host doesn't support it!!\n"));
1410 return;
1411 }
1412
1413 /* Valid for both Intel and AMD. */
1414 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_LONG_MODE;
1415 LogRel(("CPUMSetGuestCpuIdFeature: Enabled LONG MODE\n"));
1416 break;
1417 }
1418
1419 /*
1420 * Set the NXE bit in the extended feature mask.
1421 * Assumes the caller knows what it's doing! (host must support these)
1422 */
1423 case CPUMCPUIDFEATURE_NXE:
1424 {
1425 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1426 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_NX))
1427 {
1428 LogRel(("WARNING: Can't turn on NXE when the host doesn't support it!!\n"));
1429 return;
1430 }
1431
1432 /* Valid for both Intel and AMD. */
1433 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_NX;
1434 LogRel(("CPUMSetGuestCpuIdFeature: Enabled NXE\n"));
1435 break;
1436 }
1437
1438 case CPUMCPUIDFEATURE_LAHF:
1439 {
1440 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1441 || !(ASMCpuId_ECX(0x80000001) & X86_CPUID_AMD_FEATURE_ECX_LAHF_SAHF))
1442 {
1443 LogRel(("WARNING: Can't turn on LAHF/SAHF when the host doesn't support it!!\n"));
1444 return;
1445 }
1446
1447 pVM->cpum.s.aGuestCpuIdExt[1].ecx |= X86_CPUID_AMD_FEATURE_ECX_LAHF_SAHF;
1448 LogRel(("CPUMSetGuestCpuIdFeature: Enabled LAHF/SAHF\n"));
1449 break;
1450 }
1451
1452 case CPUMCPUIDFEATURE_PAT:
1453 {
1454 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1455 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_PAT;
1456 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1457 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1458 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_PAT;
1459 LogRel(("CPUMClearGuestCpuIdFeature: Enabled PAT\n"));
1460 break;
1461 }
1462
1463 case CPUMCPUIDFEATURE_RDTSCP:
1464 {
1465 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax < 0x80000001
1466 || !(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_RDTSCP))
1467 {
1468 LogRel(("WARNING: Can't turn on RDTSCP when the host doesn't support it!!\n"));
1469 return;
1470 }
1471
1472 /* Valid for AMD only (for now). */
1473 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_RDTSCP;
1474 LogRel(("CPUMSetGuestCpuIdFeature: Enabled RDTSCP.\n"));
1475 break;
1476 }
1477
1478 default:
1479 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
1480 break;
1481 }
1482 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1483
1484 pCpumCpu->fChanged |= CPUM_CHANGED_CPUID;
1485}
1486
1487
1488/**
1489 * Queries a CPUID feature bit.
1490 *
1491 * @returns boolean for feature presence
1492 * @param pVM The VM Handle.
1493 * @param enmFeature The feature to query.
1494 */
1495VMMDECL(bool) CPUMGetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
1496{
1497 switch (enmFeature)
1498 {
1499 case CPUMCPUIDFEATURE_PAE:
1500 {
1501 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1502 return !!(pVM->cpum.s.aGuestCpuIdStd[1].edx & X86_CPUID_FEATURE_EDX_PAE);
1503 break;
1504 }
1505
1506 case CPUMCPUIDFEATURE_RDTSCP:
1507 {
1508 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1509 return !!(pVM->cpum.s.aGuestCpuIdExt[1].edx & X86_CPUID_AMD_FEATURE_EDX_RDTSCP);
1510 break;
1511 }
1512
1513 case CPUMCPUIDFEATURE_LONG_MODE:
1514 {
1515 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1516 return !!(pVM->cpum.s.aGuestCpuIdExt[1].edx & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE);
1517 break;
1518 }
1519
1520 default:
1521 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
1522 break;
1523 }
1524 return false;
1525}
1526
1527
1528/**
1529 * Clears a CPUID feature bit.
1530 *
1531 * @param pVM The VM Handle.
1532 * @param enmFeature The feature to clear.
1533 */
1534VMMDECL(void) CPUMClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
1535{
1536 switch (enmFeature)
1537 {
1538 /*
1539 * Set the APIC bit in both feature masks.
1540 */
1541 case CPUMCPUIDFEATURE_APIC:
1542 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1543 pVM->cpum.s.aGuestCpuIdStd[1].edx &= ~X86_CPUID_FEATURE_EDX_APIC;
1544 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1545 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1546 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_APIC;
1547 Log(("CPUMSetGuestCpuIdFeature: Disabled APIC\n"));
1548 break;
1549
1550 /*
1551 * Clear the x2APIC bit in the standard feature mask.
1552 */
1553 case CPUMCPUIDFEATURE_X2APIC:
1554 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1555 pVM->cpum.s.aGuestCpuIdStd[1].ecx &= ~X86_CPUID_FEATURE_ECX_X2APIC;
1556 LogRel(("CPUMSetGuestCpuIdFeature: Disabled x2APIC\n"));
1557 break;
1558
1559 case CPUMCPUIDFEATURE_PAE:
1560 {
1561 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1562 pVM->cpum.s.aGuestCpuIdStd[1].edx &= ~X86_CPUID_FEATURE_EDX_PAE;
1563 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1564 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1565 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_PAE;
1566 LogRel(("CPUMClearGuestCpuIdFeature: Disabled PAE!\n"));
1567 break;
1568 }
1569
1570 case CPUMCPUIDFEATURE_PAT:
1571 {
1572 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
1573 pVM->cpum.s.aGuestCpuIdStd[1].edx &= ~X86_CPUID_FEATURE_EDX_PAT;
1574 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1575 && pVM->cpum.s.enmCPUVendor == CPUMCPUVENDOR_AMD)
1576 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_PAT;
1577 LogRel(("CPUMClearGuestCpuIdFeature: Disabled PAT!\n"));
1578 break;
1579 }
1580
1581 case CPUMCPUIDFEATURE_LONG_MODE:
1582 {
1583 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1584 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_LONG_MODE;
1585 break;
1586 }
1587
1588 case CPUMCPUIDFEATURE_LAHF:
1589 {
1590 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
1591 pVM->cpum.s.aGuestCpuIdExt[1].ecx &= ~X86_CPUID_AMD_FEATURE_ECX_LAHF_SAHF;
1592 break;
1593 }
1594
1595 default:
1596 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
1597 break;
1598 }
1599 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1600 pCpumCpu->fChanged |= CPUM_CHANGED_CPUID;
1601}
1602
1603
1604/**
1605 * Gets the CPU vendor
1606 *
1607 * @returns CPU vendor
1608 * @param pVM The VM handle.
1609 */
1610VMMDECL(CPUMCPUVENDOR) CPUMGetCPUVendor(PVM pVM)
1611{
1612 return pVM->cpum.s.enmCPUVendor;
1613}
1614
1615
1616VMMDECL(int) CPUMSetGuestDR0(PVM pVM, uint64_t uDr0)
1617{
1618 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1619
1620 pCpumCpu->Guest.dr[0] = uDr0;
1621 return CPUMRecalcHyperDRx(pVM);
1622}
1623
1624
1625VMMDECL(int) CPUMSetGuestDR1(PVM pVM, uint64_t uDr1)
1626{
1627 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1628
1629 pCpumCpu->Guest.dr[1] = uDr1;
1630 return CPUMRecalcHyperDRx(pVM);
1631}
1632
1633
1634VMMDECL(int) CPUMSetGuestDR2(PVM pVM, uint64_t uDr2)
1635{
1636 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1637
1638 pCpumCpu->Guest.dr[2] = uDr2;
1639 return CPUMRecalcHyperDRx(pVM);
1640}
1641
1642
1643VMMDECL(int) CPUMSetGuestDR3(PVM pVM, uint64_t uDr3)
1644{
1645 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1646
1647 pCpumCpu->Guest.dr[3] = uDr3;
1648 return CPUMRecalcHyperDRx(pVM);
1649}
1650
1651
1652VMMDECL(int) CPUMSetGuestDR6(PVM pVM, uint64_t uDr6)
1653{
1654 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1655
1656 pCpumCpu->Guest.dr[6] = uDr6;
1657 return CPUMRecalcHyperDRx(pVM);
1658}
1659
1660
1661VMMDECL(int) CPUMSetGuestDR7(PVM pVM, uint64_t uDr7)
1662{
1663 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1664
1665 pCpumCpu->Guest.dr[7] = uDr7;
1666 return CPUMRecalcHyperDRx(pVM);
1667}
1668
1669
1670VMMDECL(int) CPUMSetGuestDRx(PVM pVM, uint32_t iReg, uint64_t Value)
1671{
1672 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1673
1674 AssertReturn(iReg <= USE_REG_DR7, VERR_INVALID_PARAMETER);
1675 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
1676 if (iReg == 4 || iReg == 5)
1677 iReg += 2;
1678 pCpumCpu->Guest.dr[iReg] = Value;
1679 return CPUMRecalcHyperDRx(pVM);
1680}
1681
1682
1683/**
1684 * Recalculates the hypvervisor DRx register values based on
1685 * current guest registers and DBGF breakpoints.
1686 *
1687 * This is called whenever a guest DRx register is modified and when DBGF
1688 * sets a hardware breakpoint. In guest context this function will reload
1689 * any (hyper) DRx registers which comes out with a different value.
1690 *
1691 * @returns VINF_SUCCESS.
1692 * @param pVM The VM handle.
1693 */
1694VMMDECL(int) CPUMRecalcHyperDRx(PVM pVM)
1695{
1696 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1697 /*
1698 * Compare the DR7s first.
1699 *
1700 * We only care about the enabled flags. The GE and LE flags are always
1701 * set and we don't care if the guest doesn't set them. GD is virtualized
1702 * when we dispatch #DB, we never enable it.
1703 */
1704 const RTGCUINTREG uDbgfDr7 = DBGFBpGetDR7(pVM);
1705#ifdef CPUM_VIRTUALIZE_DRX
1706 const RTGCUINTREG uGstDr7 = CPUMGetGuestDR7(pVM);
1707#else
1708 const RTGCUINTREG uGstDr7 = 0;
1709#endif
1710 if ((uGstDr7 | uDbgfDr7) & X86_DR7_ENABLED_MASK)
1711 {
1712 /*
1713 * Ok, something is enabled. Recalc each of the breakpoints.
1714 * Straight forward code, not optimized/minimized in any way.
1715 */
1716 RTGCUINTREG uNewDr7 = X86_DR7_GE | X86_DR7_LE | X86_DR7_MB1_MASK;
1717
1718 /* bp 0 */
1719 RTGCUINTREG uNewDr0;
1720 if (uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0))
1721 {
1722 uNewDr7 |= uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
1723 uNewDr0 = DBGFBpGetDR0(pVM);
1724 }
1725 else if (uGstDr7 & (X86_DR7_L0 | X86_DR7_G0))
1726 {
1727 uNewDr7 |= uGstDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
1728 uNewDr0 = CPUMGetGuestDR0(pVM);
1729 }
1730 else
1731 uNewDr0 = pVM->cpum.s.Hyper.dr[0];
1732
1733 /* bp 1 */
1734 RTGCUINTREG uNewDr1;
1735 if (uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1))
1736 {
1737 uNewDr7 |= uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
1738 uNewDr1 = DBGFBpGetDR1(pVM);
1739 }
1740 else if (uGstDr7 & (X86_DR7_L1 | X86_DR7_G1))
1741 {
1742 uNewDr7 |= uGstDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
1743 uNewDr1 = CPUMGetGuestDR1(pVM);
1744 }
1745 else
1746 uNewDr1 = pVM->cpum.s.Hyper.dr[1];
1747
1748 /* bp 2 */
1749 RTGCUINTREG uNewDr2;
1750 if (uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2))
1751 {
1752 uNewDr7 |= uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
1753 uNewDr2 = DBGFBpGetDR2(pVM);
1754 }
1755 else if (uGstDr7 & (X86_DR7_L2 | X86_DR7_G2))
1756 {
1757 uNewDr7 |= uGstDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
1758 uNewDr2 = CPUMGetGuestDR2(pVM);
1759 }
1760 else
1761 uNewDr2 = pVM->cpum.s.Hyper.dr[2];
1762
1763 /* bp 3 */
1764 RTGCUINTREG uNewDr3;
1765 if (uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3))
1766 {
1767 uNewDr7 |= uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
1768 uNewDr3 = DBGFBpGetDR3(pVM);
1769 }
1770 else if (uGstDr7 & (X86_DR7_L3 | X86_DR7_G3))
1771 {
1772 uNewDr7 |= uGstDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
1773 uNewDr3 = CPUMGetGuestDR3(pVM);
1774 }
1775 else
1776 uNewDr3 = pVM->cpum.s.Hyper.dr[3];
1777
1778 /*
1779 * Apply the updates.
1780 */
1781#ifdef IN_RC
1782 if (!(pCpumCpu->fUseFlags & CPUM_USE_DEBUG_REGS))
1783 {
1784 /** @todo save host DBx registers. */
1785 }
1786#endif
1787 pCpumCpu->fUseFlags |= CPUM_USE_DEBUG_REGS;
1788 if (uNewDr3 != pVM->cpum.s.Hyper.dr[3])
1789 CPUMSetHyperDR3(pVM, uNewDr3);
1790 if (uNewDr2 != pVM->cpum.s.Hyper.dr[2])
1791 CPUMSetHyperDR2(pVM, uNewDr2);
1792 if (uNewDr1 != pVM->cpum.s.Hyper.dr[1])
1793 CPUMSetHyperDR1(pVM, uNewDr1);
1794 if (uNewDr0 != pVM->cpum.s.Hyper.dr[0])
1795 CPUMSetHyperDR0(pVM, uNewDr0);
1796 if (uNewDr7 != pVM->cpum.s.Hyper.dr[7])
1797 CPUMSetHyperDR7(pVM, uNewDr7);
1798 }
1799 else
1800 {
1801#ifdef IN_RC
1802 if (pCpumCpu->fUseFlags & CPUM_USE_DEBUG_REGS)
1803 {
1804 /** @todo restore host DBx registers. */
1805 }
1806#endif
1807 pCpumCpu->fUseFlags &= ~CPUM_USE_DEBUG_REGS;
1808 }
1809 Log2(("CPUMRecalcHyperDRx: fUseFlags=%#x %RGr %RGr %RGr %RGr %RGr %RGr\n",
1810 pCpumCpu->fUseFlags, pVM->cpum.s.Hyper.dr[0], pVM->cpum.s.Hyper.dr[1],
1811 pVM->cpum.s.Hyper.dr[2], pVM->cpum.s.Hyper.dr[3], pVM->cpum.s.Hyper.dr[6],
1812 pVM->cpum.s.Hyper.dr[7]));
1813
1814 return VINF_SUCCESS;
1815}
1816
1817#ifndef IN_RING0 /** @todo I don't think we need this in R0, so move it to CPUMAll.cpp? */
1818
1819/**
1820 * Transforms the guest CPU state to raw-ring mode.
1821 *
1822 * This function will change the any of the cs and ss register with DPL=0 to DPL=1.
1823 *
1824 * @returns VBox status. (recompiler failure)
1825 * @param pVM VM handle.
1826 * @param pCtxCore The context core (for trap usage).
1827 * @see @ref pg_raw
1828 */
1829VMMDECL(int) CPUMRawEnter(PVM pVM, PCPUMCTXCORE pCtxCore)
1830{
1831 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1832
1833 Assert(!pVM->cpum.s.fRawEntered);
1834 if (!pCtxCore)
1835 pCtxCore = CPUMCTX2CORE(&pCpumCpu->Guest);
1836
1837 /*
1838 * Are we in Ring-0?
1839 */
1840 if ( pCtxCore->ss && (pCtxCore->ss & X86_SEL_RPL) == 0
1841 && !pCtxCore->eflags.Bits.u1VM)
1842 {
1843 /*
1844 * Enter execution mode.
1845 */
1846 PATMRawEnter(pVM, pCtxCore);
1847
1848 /*
1849 * Set CPL to Ring-1.
1850 */
1851 pCtxCore->ss |= 1;
1852 if (pCtxCore->cs && (pCtxCore->cs & X86_SEL_RPL) == 0)
1853 pCtxCore->cs |= 1;
1854 }
1855 else
1856 {
1857 AssertMsg((pCtxCore->ss & X86_SEL_RPL) >= 2 || pCtxCore->eflags.Bits.u1VM,
1858 ("ring-1 code not supported\n"));
1859 /*
1860 * PATM takes care of IOPL and IF flags for Ring-3 and Ring-2 code as well.
1861 */
1862 PATMRawEnter(pVM, pCtxCore);
1863 }
1864
1865 /*
1866 * Assert sanity.
1867 */
1868 AssertMsg((pCtxCore->eflags.u32 & X86_EFL_IF), ("X86_EFL_IF is clear\n"));
1869 AssertReleaseMsg( pCtxCore->eflags.Bits.u2IOPL < (unsigned)(pCtxCore->ss & X86_SEL_RPL)
1870 || pCtxCore->eflags.Bits.u1VM,
1871 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss & X86_SEL_RPL));
1872 Assert((pCpumCpu->Guest.cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) == (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP));
1873 pCtxCore->eflags.u32 |= X86_EFL_IF; /* paranoia */
1874
1875 pVM->cpum.s.fRawEntered = true;
1876 return VINF_SUCCESS;
1877}
1878
1879
1880/**
1881 * Transforms the guest CPU state from raw-ring mode to correct values.
1882 *
1883 * This function will change any selector registers with DPL=1 to DPL=0.
1884 *
1885 * @returns Adjusted rc.
1886 * @param pVM VM handle.
1887 * @param rc Raw mode return code
1888 * @param pCtxCore The context core (for trap usage).
1889 * @see @ref pg_raw
1890 */
1891VMMDECL(int) CPUMRawLeave(PVM pVM, PCPUMCTXCORE pCtxCore, int rc)
1892{
1893 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
1894
1895 /*
1896 * Don't leave if we've already left (in GC).
1897 */
1898 Assert(pVM->cpum.s.fRawEntered);
1899 if (!pVM->cpum.s.fRawEntered)
1900 return rc;
1901 pVM->cpum.s.fRawEntered = false;
1902
1903 PCPUMCTX pCtx = &pCpumCpu->Guest;
1904 if (!pCtxCore)
1905 pCtxCore = CPUMCTX2CORE(pCtx);
1906 Assert(pCtxCore->eflags.Bits.u1VM || (pCtxCore->ss & X86_SEL_RPL));
1907 AssertMsg(pCtxCore->eflags.Bits.u1VM || pCtxCore->eflags.Bits.u2IOPL < (unsigned)(pCtxCore->ss & X86_SEL_RPL),
1908 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss & X86_SEL_RPL));
1909
1910 /*
1911 * Are we executing in raw ring-1?
1912 */
1913 if ( (pCtxCore->ss & X86_SEL_RPL) == 1
1914 && !pCtxCore->eflags.Bits.u1VM)
1915 {
1916 /*
1917 * Leave execution mode.
1918 */
1919 PATMRawLeave(pVM, pCtxCore, rc);
1920 /* Not quite sure if this is really required, but shouldn't harm (too much anyways). */
1921 /** @todo See what happens if we remove this. */
1922 if ((pCtxCore->ds & X86_SEL_RPL) == 1)
1923 pCtxCore->ds &= ~X86_SEL_RPL;
1924 if ((pCtxCore->es & X86_SEL_RPL) == 1)
1925 pCtxCore->es &= ~X86_SEL_RPL;
1926 if ((pCtxCore->fs & X86_SEL_RPL) == 1)
1927 pCtxCore->fs &= ~X86_SEL_RPL;
1928 if ((pCtxCore->gs & X86_SEL_RPL) == 1)
1929 pCtxCore->gs &= ~X86_SEL_RPL;
1930
1931 /*
1932 * Ring-1 selector => Ring-0.
1933 */
1934 pCtxCore->ss &= ~X86_SEL_RPL;
1935 if ((pCtxCore->cs & X86_SEL_RPL) == 1)
1936 pCtxCore->cs &= ~X86_SEL_RPL;
1937 }
1938 else
1939 {
1940 /*
1941 * PATM is taking care of the IOPL and IF flags for us.
1942 */
1943 PATMRawLeave(pVM, pCtxCore, rc);
1944 if (!pCtxCore->eflags.Bits.u1VM)
1945 {
1946 /** @todo See what happens if we remove this. */
1947 if ((pCtxCore->ds & X86_SEL_RPL) == 1)
1948 pCtxCore->ds &= ~X86_SEL_RPL;
1949 if ((pCtxCore->es & X86_SEL_RPL) == 1)
1950 pCtxCore->es &= ~X86_SEL_RPL;
1951 if ((pCtxCore->fs & X86_SEL_RPL) == 1)
1952 pCtxCore->fs &= ~X86_SEL_RPL;
1953 if ((pCtxCore->gs & X86_SEL_RPL) == 1)
1954 pCtxCore->gs &= ~X86_SEL_RPL;
1955 }
1956 }
1957
1958 return rc;
1959}
1960
1961/**
1962 * Updates the EFLAGS while we're in raw-mode.
1963 *
1964 * @param pVM The VM handle.
1965 * @param pCtxCore The context core.
1966 * @param eflags The new EFLAGS value.
1967 */
1968VMMDECL(void) CPUMRawSetEFlags(PVM pVM, PCPUMCTXCORE pCtxCore, uint32_t eflags)
1969{
1970 if (!pVM->cpum.s.fRawEntered)
1971 {
1972 pCtxCore->eflags.u32 = eflags;
1973 return;
1974 }
1975 PATMRawSetEFlags(pVM, pCtxCore, eflags);
1976}
1977
1978#endif /* !IN_RING0 */
1979
1980/**
1981 * Gets the EFLAGS while we're in raw-mode.
1982 *
1983 * @returns The eflags.
1984 * @param pVM The VM handle.
1985 * @param pCtxCore The context core.
1986 */
1987VMMDECL(uint32_t) CPUMRawGetEFlags(PVM pVM, PCPUMCTXCORE pCtxCore)
1988{
1989#ifdef IN_RING0
1990 return pCtxCore->eflags.u32;
1991#else
1992 if (!pVM->cpum.s.fRawEntered)
1993 return pCtxCore->eflags.u32;
1994 return PATMRawGetEFlags(pVM, pCtxCore);
1995#endif
1996}
1997
1998
1999/**
2000 * Gets and resets the changed flags (CPUM_CHANGED_*).
2001 * Only REM should call this function.
2002 *
2003 * @returns The changed flags.
2004 * @param pVM The VM handle.
2005 */
2006VMMDECL(unsigned) CPUMGetAndClearChangedFlagsREM(PVM pVM)
2007{
2008 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
2009
2010 unsigned fFlags = pCpumCpu->fChanged;
2011 pCpumCpu->fChanged = 0;
2012 /** @todo change the switcher to use the fChanged flags. */
2013 if (pCpumCpu->fUseFlags & CPUM_USED_FPU_SINCE_REM)
2014 {
2015 fFlags |= CPUM_CHANGED_FPU_REM;
2016 pCpumCpu->fUseFlags &= ~CPUM_USED_FPU_SINCE_REM;
2017 }
2018 return fFlags;
2019}
2020
2021
2022/**
2023 * Sets the specified changed flags (CPUM_CHANGED_*).
2024 *
2025 * @param pVM The VM handle.
2026 */
2027VMMDECL(void) CPUMSetChangedFlags(PVM pVM, uint32_t fChangedFlags)
2028{
2029 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
2030
2031 pCpumCpu->fChanged |= fChangedFlags;
2032}
2033
2034
2035/**
2036 * Checks if the CPU supports the FXSAVE and FXRSTOR instruction.
2037 * @returns true if supported.
2038 * @returns false if not supported.
2039 * @param pVM The VM handle.
2040 */
2041VMMDECL(bool) CPUMSupportsFXSR(PVM pVM)
2042{
2043 return pVM->cpum.s.CPUFeatures.edx.u1FXSR != 0;
2044}
2045
2046
2047/**
2048 * Checks if the host OS uses the SYSENTER / SYSEXIT instructions.
2049 * @returns true if used.
2050 * @returns false if not used.
2051 * @param pVM The VM handle.
2052 */
2053VMMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM)
2054{
2055 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
2056
2057 return (pCpumCpu->fUseFlags & CPUM_USE_SYSENTER) != 0;
2058}
2059
2060
2061/**
2062 * Checks if the host OS uses the SYSCALL / SYSRET instructions.
2063 * @returns true if used.
2064 * @returns false if not used.
2065 * @param pVM The VM handle.
2066 */
2067VMMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM)
2068{
2069 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
2070
2071 return (pCpumCpu->fUseFlags & CPUM_USE_SYSCALL) != 0;
2072}
2073
2074#ifndef IN_RING3
2075
2076/**
2077 * Lazily sync in the FPU/XMM state
2078 *
2079 * @returns VBox status code.
2080 * @param pVM VM handle.
2081 * @param pVCpu VMCPU handle
2082 */
2083VMMDECL(int) CPUMHandleLazyFPU(PVM pVM, PVMCPU pVCpu)
2084{
2085 return CPUMHandleLazyFPUAsm(&pVCpu->cpum.s);
2086}
2087
2088#endif /* !IN_RING3 */
2089
2090/**
2091 * Checks if we activated the FPU/XMM state of the guest OS
2092 * @returns true if we did.
2093 * @returns false if not.
2094 * @param pVCpu The VMCPU handle.
2095 */
2096VMMDECL(bool) CPUMIsGuestFPUStateActive(PVMCPU pVCpu)
2097{
2098 return (pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU) != 0;
2099}
2100
2101
2102/**
2103 * Deactivate the FPU/XMM state of the guest OS
2104 * @param pVM The VM handle.
2105 */
2106VMMDECL(void) CPUMDeactivateGuestFPUState(PVM pVM)
2107{
2108 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
2109
2110 pCpumCpu->fUseFlags &= ~CPUM_USED_FPU;
2111}
2112
2113
2114/**
2115 * Checks if the guest debug state is active
2116 *
2117 * @returns boolean
2118 * @param pVM VM handle.
2119 */
2120VMMDECL(bool) CPUMIsGuestDebugStateActive(PVM pVM)
2121{
2122 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
2123
2124 return (pCpumCpu->fUseFlags & CPUM_USE_DEBUG_REGS) != 0;
2125}
2126
2127
2128/**
2129 * Mark the guest's debug state as inactive
2130 *
2131 * @returns boolean
2132 * @param pVM VM handle.
2133 */
2134VMMDECL(void) CPUMDeactivateGuestDebugState(PVM pVM)
2135{
2136 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
2137
2138 pCpumCpu->fUseFlags &= ~CPUM_USE_DEBUG_REGS;
2139}
2140
2141
2142/**
2143 * Checks if the hidden selector registers are valid
2144 * @returns true if they are.
2145 * @returns false if not.
2146 * @param pVM The VM handle.
2147 */
2148VMMDECL(bool) CPUMAreHiddenSelRegsValid(PVM pVM)
2149{
2150 return !!pVM->cpum.s.fValidHiddenSelRegs; /** @todo change fValidHiddenSelRegs to bool! */
2151}
2152
2153
2154/**
2155 * Checks if the hidden selector registers are valid
2156 * @param pVM The VM handle.
2157 * @param fValid Valid or not
2158 */
2159VMMDECL(void) CPUMSetHiddenSelRegsValid(PVM pVM, bool fValid)
2160{
2161 pVM->cpum.s.fValidHiddenSelRegs = fValid;
2162}
2163
2164
2165/**
2166 * Get the current privilege level of the guest.
2167 *
2168 * @returns cpl
2169 * @param pVM VM Handle.
2170 * @param pRegFrame Trap register frame.
2171 */
2172VMMDECL(uint32_t) CPUMGetGuestCPL(PVM pVM, PCPUMCTXCORE pCtxCore)
2173{
2174 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
2175 uint32_t cpl;
2176
2177 if (CPUMAreHiddenSelRegsValid(pVM))
2178 {
2179 /*
2180 * The hidden CS.DPL register is always equal to the CPL, it is
2181 * not affected by loading a conforming coding segment.
2182 *
2183 * This only seems to apply to AMD-V; in the VT-x case we *do* need to look
2184 * at SS. (ACP2 regression during install after a far call to ring 2)
2185 */
2186 if (RT_LIKELY(pCpumCpu->Guest.cr0 & X86_CR0_PE))
2187 cpl = pCtxCore->ssHid.Attr.n.u2Dpl;
2188 else
2189 cpl = 0; /* CPL set to 3 for VT-x real-mode emulation. */
2190 }
2191 else if (RT_LIKELY(pCpumCpu->Guest.cr0 & X86_CR0_PE))
2192 {
2193 if (RT_LIKELY(!pCtxCore->eflags.Bits.u1VM))
2194 {
2195 /*
2196 * The SS RPL is always equal to the CPL, while the CS RPL
2197 * isn't necessarily equal if the segment is conforming.
2198 * See section 4.11.1 in the AMD manual.
2199 */
2200 cpl = (pCtxCore->ss & X86_SEL_RPL);
2201#ifndef IN_RING0
2202 if (cpl == 1)
2203 cpl = 0;
2204#endif
2205 }
2206 else
2207 cpl = 3;
2208 }
2209 else
2210 cpl = 0; /* real mode; cpl is zero */
2211
2212 return cpl;
2213}
2214
2215
2216/**
2217 * Gets the current guest CPU mode.
2218 *
2219 * If paging mode is what you need, check out PGMGetGuestMode().
2220 *
2221 * @returns The CPU mode.
2222 * @param pVM The VM handle.
2223 */
2224VMMDECL(CPUMMODE) CPUMGetGuestMode(PVM pVM)
2225{
2226 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
2227
2228 CPUMMODE enmMode;
2229 if (!(pCpumCpu->Guest.cr0 & X86_CR0_PE))
2230 enmMode = CPUMMODE_REAL;
2231 else if (!(pCpumCpu->Guest.msrEFER & MSR_K6_EFER_LMA))
2232 enmMode = CPUMMODE_PROTECTED;
2233 else
2234 enmMode = CPUMMODE_LONG;
2235
2236 return enmMode;
2237}
2238
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