VirtualBox

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

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

Even more debugger fixes.

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