VirtualBox

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

Last change on this file since 50653 was 49972, checked in by vboxsync, 10 years ago

CPUM: More msr hacking.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 105.7 KB
Line 
1/* $Id: CPUMAllRegs.cpp 49972 2013-12-18 13:10:58Z vboxsync $ */
2/** @file
3 * CPUM - CPU Monitor(/Manager) - Getters and Setters.
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
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
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_CPUM
23#include <VBox/vmm/cpum.h>
24#include <VBox/vmm/patm.h>
25#include <VBox/vmm/dbgf.h>
26#include <VBox/vmm/pdm.h>
27#include <VBox/vmm/pgm.h>
28#include <VBox/vmm/mm.h>
29#include <VBox/vmm/em.h>
30#if defined(VBOX_WITH_RAW_MODE) && !defined(IN_RING0)
31# include <VBox/vmm/selm.h>
32#endif
33#include "CPUMInternal.h"
34#include <VBox/vmm/vm.h>
35#include <VBox/err.h>
36#include <VBox/dis.h>
37#include <VBox/log.h>
38#include <VBox/vmm/hm.h>
39#include <VBox/vmm/tm.h>
40#include <iprt/assert.h>
41#include <iprt/asm.h>
42#include <iprt/asm-amd64-x86.h>
43#ifdef IN_RING3
44#include <iprt/thread.h>
45#endif
46
47/** Disable stack frame pointer generation here. */
48#if defined(_MSC_VER) && !defined(DEBUG)
49# pragma optimize("y", off)
50#endif
51
52
53/*******************************************************************************
54* Defined Constants And Macros *
55*******************************************************************************/
56/**
57 * Converts a CPUMCPU::Guest pointer into a VMCPU pointer.
58 *
59 * @returns Pointer to the Virtual CPU.
60 * @param a_pGuestCtx Pointer to the guest context.
61 */
62#define CPUM_GUEST_CTX_TO_VMCPU(a_pGuestCtx) RT_FROM_MEMBER(a_pGuestCtx, VMCPU, cpum.s.Guest)
63
64/**
65 * Lazily loads the hidden parts of a selector register when using raw-mode.
66 */
67#if defined(VBOX_WITH_RAW_MODE) && !defined(IN_RING0)
68# define CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(a_pVCpu, a_pSReg) \
69 do \
70 { \
71 if (!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(a_pVCpu, a_pSReg)) \
72 cpumGuestLazyLoadHiddenSelectorReg(a_pVCpu, a_pSReg); \
73 } while (0)
74#else
75# define CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(a_pVCpu, a_pSReg) \
76 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(a_pVCpu, a_pSReg));
77#endif
78
79
80
81#ifdef VBOX_WITH_RAW_MODE_NOT_R0
82
83/**
84 * Does the lazy hidden selector register loading.
85 *
86 * @param pVCpu The current Virtual CPU.
87 * @param pSReg The selector register to lazily load hidden parts of.
88 */
89static void cpumGuestLazyLoadHiddenSelectorReg(PVMCPU pVCpu, PCPUMSELREG pSReg)
90{
91 Assert(!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
92 Assert(!HMIsEnabled(pVCpu->CTX_SUFF(pVM)));
93 Assert((uintptr_t)(pSReg - &pVCpu->cpum.s.Guest.es) < X86_SREG_COUNT);
94
95 if (pVCpu->cpum.s.Guest.eflags.Bits.u1VM)
96 {
97 /* V8086 mode - Tightly controlled environment, no question about the limit or flags. */
98 pSReg->Attr.u = 0;
99 pSReg->Attr.n.u4Type = pSReg == &pVCpu->cpum.s.Guest.cs ? X86_SEL_TYPE_ER_ACC : X86_SEL_TYPE_RW_ACC;
100 pSReg->Attr.n.u1DescType = 1; /* code/data segment */
101 pSReg->Attr.n.u2Dpl = 3;
102 pSReg->Attr.n.u1Present = 1;
103 pSReg->u32Limit = 0x0000ffff;
104 pSReg->u64Base = (uint32_t)pSReg->Sel << 4;
105 pSReg->ValidSel = pSReg->Sel;
106 pSReg->fFlags = CPUMSELREG_FLAGS_VALID;
107 /** @todo Check what the accessed bit should be (VT-x and AMD-V). */
108 }
109 else if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
110 {
111 /* Real mode - leave the limit and flags alone here, at least for now. */
112 pSReg->u64Base = (uint32_t)pSReg->Sel << 4;
113 pSReg->ValidSel = pSReg->Sel;
114 pSReg->fFlags = CPUMSELREG_FLAGS_VALID;
115 }
116 else
117 {
118 /* Protected mode - get it from the selector descriptor tables. */
119 if (!(pSReg->Sel & X86_SEL_MASK_OFF_RPL))
120 {
121 Assert(!CPUMIsGuestInLongMode(pVCpu));
122 pSReg->Sel = 0;
123 pSReg->u64Base = 0;
124 pSReg->u32Limit = 0;
125 pSReg->Attr.u = 0;
126 pSReg->ValidSel = 0;
127 pSReg->fFlags = CPUMSELREG_FLAGS_VALID;
128 /** @todo see todo in iemHlpLoadNullDataSelectorProt. */
129 }
130 else
131 SELMLoadHiddenSelectorReg(pVCpu, &pVCpu->cpum.s.Guest, pSReg);
132 }
133}
134
135
136/**
137 * Makes sure the hidden CS and SS selector registers are valid, loading them if
138 * necessary.
139 *
140 * @param pVCpu The current virtual CPU.
141 */
142VMM_INT_DECL(void) CPUMGuestLazyLoadHiddenCsAndSs(PVMCPU pVCpu)
143{
144 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
145 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.ss);
146}
147
148
149/**
150 * Loads a the hidden parts of a selector register.
151 *
152 * @param pVCpu The current virtual CPU.
153 */
154VMM_INT_DECL(void) CPUMGuestLazyLoadHiddenSelectorReg(PVMCPU pVCpu, PCPUMSELREG pSReg)
155{
156 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, pSReg);
157}
158
159#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
160
161
162/**
163 * Obsolete.
164 *
165 * We don't support nested hypervisor context interrupts or traps. Life is much
166 * simpler when we don't. It's also slightly faster at times.
167 *
168 * @param pVM Handle to the virtual machine.
169 */
170VMMDECL(PCCPUMCTXCORE) CPUMGetHyperCtxCore(PVMCPU pVCpu)
171{
172 return CPUMCTX2CORE(&pVCpu->cpum.s.Hyper);
173}
174
175
176/**
177 * Gets the pointer to the hypervisor CPU context structure of a virtual CPU.
178 *
179 * @param pVCpu Pointer to the VMCPU.
180 */
181VMMDECL(PCPUMCTX) CPUMGetHyperCtxPtr(PVMCPU pVCpu)
182{
183 return &pVCpu->cpum.s.Hyper;
184}
185
186
187VMMDECL(void) CPUMSetHyperGDTR(PVMCPU pVCpu, uint32_t addr, uint16_t limit)
188{
189 pVCpu->cpum.s.Hyper.gdtr.cbGdt = limit;
190 pVCpu->cpum.s.Hyper.gdtr.pGdt = addr;
191}
192
193
194VMMDECL(void) CPUMSetHyperIDTR(PVMCPU pVCpu, uint32_t addr, uint16_t limit)
195{
196 pVCpu->cpum.s.Hyper.idtr.cbIdt = limit;
197 pVCpu->cpum.s.Hyper.idtr.pIdt = addr;
198}
199
200
201VMMDECL(void) CPUMSetHyperCR3(PVMCPU pVCpu, uint32_t cr3)
202{
203 pVCpu->cpum.s.Hyper.cr3 = cr3;
204
205#ifdef IN_RC
206 /* Update the current CR3. */
207 ASMSetCR3(cr3);
208#endif
209}
210
211VMMDECL(uint32_t) CPUMGetHyperCR3(PVMCPU pVCpu)
212{
213 return pVCpu->cpum.s.Hyper.cr3;
214}
215
216
217VMMDECL(void) CPUMSetHyperCS(PVMCPU pVCpu, RTSEL SelCS)
218{
219 pVCpu->cpum.s.Hyper.cs.Sel = SelCS;
220}
221
222
223VMMDECL(void) CPUMSetHyperDS(PVMCPU pVCpu, RTSEL SelDS)
224{
225 pVCpu->cpum.s.Hyper.ds.Sel = SelDS;
226}
227
228
229VMMDECL(void) CPUMSetHyperES(PVMCPU pVCpu, RTSEL SelES)
230{
231 pVCpu->cpum.s.Hyper.es.Sel = SelES;
232}
233
234
235VMMDECL(void) CPUMSetHyperFS(PVMCPU pVCpu, RTSEL SelFS)
236{
237 pVCpu->cpum.s.Hyper.fs.Sel = SelFS;
238}
239
240
241VMMDECL(void) CPUMSetHyperGS(PVMCPU pVCpu, RTSEL SelGS)
242{
243 pVCpu->cpum.s.Hyper.gs.Sel = SelGS;
244}
245
246
247VMMDECL(void) CPUMSetHyperSS(PVMCPU pVCpu, RTSEL SelSS)
248{
249 pVCpu->cpum.s.Hyper.ss.Sel = SelSS;
250}
251
252
253VMMDECL(void) CPUMSetHyperESP(PVMCPU pVCpu, uint32_t u32ESP)
254{
255 pVCpu->cpum.s.Hyper.esp = u32ESP;
256}
257
258
259VMMDECL(void) CPUMSetHyperEDX(PVMCPU pVCpu, uint32_t u32ESP)
260{
261 pVCpu->cpum.s.Hyper.esp = u32ESP;
262}
263
264
265VMMDECL(int) CPUMSetHyperEFlags(PVMCPU pVCpu, uint32_t Efl)
266{
267 pVCpu->cpum.s.Hyper.eflags.u32 = Efl;
268 return VINF_SUCCESS;
269}
270
271
272VMMDECL(void) CPUMSetHyperEIP(PVMCPU pVCpu, uint32_t u32EIP)
273{
274 pVCpu->cpum.s.Hyper.eip = u32EIP;
275}
276
277
278/**
279 * Used by VMMR3RawRunGC to reinitialize the general raw-mode context registers,
280 * EFLAGS and EIP prior to resuming guest execution.
281 *
282 * All general register not given as a parameter will be set to 0. The EFLAGS
283 * register will be set to sane values for C/C++ code execution with interrupts
284 * disabled and IOPL 0.
285 *
286 * @param pVCpu The current virtual CPU.
287 * @param u32EIP The EIP value.
288 * @param u32ESP The ESP value.
289 * @param u32EAX The EAX value.
290 * @param u32EDX The EDX value.
291 */
292VMM_INT_DECL(void) CPUMSetHyperState(PVMCPU pVCpu, uint32_t u32EIP, uint32_t u32ESP, uint32_t u32EAX, uint32_t u32EDX)
293{
294 pVCpu->cpum.s.Hyper.eip = u32EIP;
295 pVCpu->cpum.s.Hyper.esp = u32ESP;
296 pVCpu->cpum.s.Hyper.eax = u32EAX;
297 pVCpu->cpum.s.Hyper.edx = u32EDX;
298 pVCpu->cpum.s.Hyper.ecx = 0;
299 pVCpu->cpum.s.Hyper.ebx = 0;
300 pVCpu->cpum.s.Hyper.ebp = 0;
301 pVCpu->cpum.s.Hyper.esi = 0;
302 pVCpu->cpum.s.Hyper.edi = 0;
303 pVCpu->cpum.s.Hyper.eflags.u = X86_EFL_1;
304}
305
306
307VMMDECL(void) CPUMSetHyperTR(PVMCPU pVCpu, RTSEL SelTR)
308{
309 pVCpu->cpum.s.Hyper.tr.Sel = SelTR;
310}
311
312
313VMMDECL(void) CPUMSetHyperLDTR(PVMCPU pVCpu, RTSEL SelLDTR)
314{
315 pVCpu->cpum.s.Hyper.ldtr.Sel = SelLDTR;
316}
317
318
319/** @MAYBE_LOAD_DRx
320 * Macro for updating DRx values in raw-mode and ring-0 contexts.
321 */
322#ifdef IN_RING0
323# if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
324# ifndef VBOX_WITH_HYBRID_32BIT_KERNEL
325# define MAYBE_LOAD_DRx(a_pVCpu, a_fnLoad, a_uValue) \
326 do { \
327 if (!CPUMIsGuestInLongModeEx(&(a_pVCpu)->cpum.s.Guest)) \
328 a_fnLoad(a_uValue); \
329 else \
330 (a_pVCpu)->cpum.s.fUseFlags |= CPUM_SYNC_DEBUG_REGS_HYPER; \
331 } while (0)
332# else
333# define MAYBE_LOAD_DRx(a_pVCpu, a_fnLoad, a_uValue) \
334 do { \
335 /** @todo we're not loading the correct guest value here! */ \
336 a_fnLoad(a_uValue); \
337 } while (0)
338# endif
339# else
340# define MAYBE_LOAD_DRx(a_pVCpu, a_fnLoad, a_uValue) \
341 do { \
342 a_fnLoad(a_uValue); \
343 } while (0)
344# endif
345
346#elif defined(IN_RC)
347# define MAYBE_LOAD_DRx(a_pVCpu, a_fnLoad, a_uValue) \
348 do { \
349 if ((a_pVCpu)->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HYPER) \
350 { a_fnLoad(a_uValue); } \
351 } while (0)
352
353#else
354# define MAYBE_LOAD_DRx(a_pVCpu, a_fnLoad, a_uValue) do { } while (0)
355#endif
356
357VMMDECL(void) CPUMSetHyperDR0(PVMCPU pVCpu, RTGCUINTREG uDr0)
358{
359 pVCpu->cpum.s.Hyper.dr[0] = uDr0;
360 MAYBE_LOAD_DRx(pVCpu, ASMSetDR0, uDr0);
361}
362
363
364VMMDECL(void) CPUMSetHyperDR1(PVMCPU pVCpu, RTGCUINTREG uDr1)
365{
366 pVCpu->cpum.s.Hyper.dr[1] = uDr1;
367 MAYBE_LOAD_DRx(pVCpu, ASMSetDR1, uDr1);
368}
369
370
371VMMDECL(void) CPUMSetHyperDR2(PVMCPU pVCpu, RTGCUINTREG uDr2)
372{
373 pVCpu->cpum.s.Hyper.dr[2] = uDr2;
374 MAYBE_LOAD_DRx(pVCpu, ASMSetDR2, uDr2);
375}
376
377
378VMMDECL(void) CPUMSetHyperDR3(PVMCPU pVCpu, RTGCUINTREG uDr3)
379{
380 pVCpu->cpum.s.Hyper.dr[3] = uDr3;
381 MAYBE_LOAD_DRx(pVCpu, ASMSetDR3, uDr3);
382}
383
384
385VMMDECL(void) CPUMSetHyperDR6(PVMCPU pVCpu, RTGCUINTREG uDr6)
386{
387 pVCpu->cpum.s.Hyper.dr[6] = uDr6;
388}
389
390
391VMMDECL(void) CPUMSetHyperDR7(PVMCPU pVCpu, RTGCUINTREG uDr7)
392{
393 pVCpu->cpum.s.Hyper.dr[7] = uDr7;
394#ifdef IN_RC
395 MAYBE_LOAD_DRx(pVCpu, ASMSetDR7, uDr7);
396#endif
397}
398
399
400VMMDECL(RTSEL) CPUMGetHyperCS(PVMCPU pVCpu)
401{
402 return pVCpu->cpum.s.Hyper.cs.Sel;
403}
404
405
406VMMDECL(RTSEL) CPUMGetHyperDS(PVMCPU pVCpu)
407{
408 return pVCpu->cpum.s.Hyper.ds.Sel;
409}
410
411
412VMMDECL(RTSEL) CPUMGetHyperES(PVMCPU pVCpu)
413{
414 return pVCpu->cpum.s.Hyper.es.Sel;
415}
416
417
418VMMDECL(RTSEL) CPUMGetHyperFS(PVMCPU pVCpu)
419{
420 return pVCpu->cpum.s.Hyper.fs.Sel;
421}
422
423
424VMMDECL(RTSEL) CPUMGetHyperGS(PVMCPU pVCpu)
425{
426 return pVCpu->cpum.s.Hyper.gs.Sel;
427}
428
429
430VMMDECL(RTSEL) CPUMGetHyperSS(PVMCPU pVCpu)
431{
432 return pVCpu->cpum.s.Hyper.ss.Sel;
433}
434
435
436VMMDECL(uint32_t) CPUMGetHyperEAX(PVMCPU pVCpu)
437{
438 return pVCpu->cpum.s.Hyper.eax;
439}
440
441
442VMMDECL(uint32_t) CPUMGetHyperEBX(PVMCPU pVCpu)
443{
444 return pVCpu->cpum.s.Hyper.ebx;
445}
446
447
448VMMDECL(uint32_t) CPUMGetHyperECX(PVMCPU pVCpu)
449{
450 return pVCpu->cpum.s.Hyper.ecx;
451}
452
453
454VMMDECL(uint32_t) CPUMGetHyperEDX(PVMCPU pVCpu)
455{
456 return pVCpu->cpum.s.Hyper.edx;
457}
458
459
460VMMDECL(uint32_t) CPUMGetHyperESI(PVMCPU pVCpu)
461{
462 return pVCpu->cpum.s.Hyper.esi;
463}
464
465
466VMMDECL(uint32_t) CPUMGetHyperEDI(PVMCPU pVCpu)
467{
468 return pVCpu->cpum.s.Hyper.edi;
469}
470
471
472VMMDECL(uint32_t) CPUMGetHyperEBP(PVMCPU pVCpu)
473{
474 return pVCpu->cpum.s.Hyper.ebp;
475}
476
477
478VMMDECL(uint32_t) CPUMGetHyperESP(PVMCPU pVCpu)
479{
480 return pVCpu->cpum.s.Hyper.esp;
481}
482
483
484VMMDECL(uint32_t) CPUMGetHyperEFlags(PVMCPU pVCpu)
485{
486 return pVCpu->cpum.s.Hyper.eflags.u32;
487}
488
489
490VMMDECL(uint32_t) CPUMGetHyperEIP(PVMCPU pVCpu)
491{
492 return pVCpu->cpum.s.Hyper.eip;
493}
494
495
496VMMDECL(uint64_t) CPUMGetHyperRIP(PVMCPU pVCpu)
497{
498 return pVCpu->cpum.s.Hyper.rip;
499}
500
501
502VMMDECL(uint32_t) CPUMGetHyperIDTR(PVMCPU pVCpu, uint16_t *pcbLimit)
503{
504 if (pcbLimit)
505 *pcbLimit = pVCpu->cpum.s.Hyper.idtr.cbIdt;
506 return pVCpu->cpum.s.Hyper.idtr.pIdt;
507}
508
509
510VMMDECL(uint32_t) CPUMGetHyperGDTR(PVMCPU pVCpu, uint16_t *pcbLimit)
511{
512 if (pcbLimit)
513 *pcbLimit = pVCpu->cpum.s.Hyper.gdtr.cbGdt;
514 return pVCpu->cpum.s.Hyper.gdtr.pGdt;
515}
516
517
518VMMDECL(RTSEL) CPUMGetHyperLDTR(PVMCPU pVCpu)
519{
520 return pVCpu->cpum.s.Hyper.ldtr.Sel;
521}
522
523
524VMMDECL(RTGCUINTREG) CPUMGetHyperDR0(PVMCPU pVCpu)
525{
526 return pVCpu->cpum.s.Hyper.dr[0];
527}
528
529
530VMMDECL(RTGCUINTREG) CPUMGetHyperDR1(PVMCPU pVCpu)
531{
532 return pVCpu->cpum.s.Hyper.dr[1];
533}
534
535
536VMMDECL(RTGCUINTREG) CPUMGetHyperDR2(PVMCPU pVCpu)
537{
538 return pVCpu->cpum.s.Hyper.dr[2];
539}
540
541
542VMMDECL(RTGCUINTREG) CPUMGetHyperDR3(PVMCPU pVCpu)
543{
544 return pVCpu->cpum.s.Hyper.dr[3];
545}
546
547
548VMMDECL(RTGCUINTREG) CPUMGetHyperDR6(PVMCPU pVCpu)
549{
550 return pVCpu->cpum.s.Hyper.dr[6];
551}
552
553
554VMMDECL(RTGCUINTREG) CPUMGetHyperDR7(PVMCPU pVCpu)
555{
556 return pVCpu->cpum.s.Hyper.dr[7];
557}
558
559
560/**
561 * Gets the pointer to the internal CPUMCTXCORE structure.
562 * This is only for reading in order to save a few calls.
563 *
564 * @param pVCpu Handle to the virtual cpu.
565 */
566VMMDECL(PCCPUMCTXCORE) CPUMGetGuestCtxCore(PVMCPU pVCpu)
567{
568 return CPUMCTX2CORE(&pVCpu->cpum.s.Guest);
569}
570
571
572/**
573 * Queries the pointer to the internal CPUMCTX structure.
574 *
575 * @returns The CPUMCTX pointer.
576 * @param pVCpu Handle to the virtual cpu.
577 */
578VMMDECL(PCPUMCTX) CPUMQueryGuestCtxPtr(PVMCPU pVCpu)
579{
580 return &pVCpu->cpum.s.Guest;
581}
582
583VMMDECL(int) CPUMSetGuestGDTR(PVMCPU pVCpu, uint64_t GCPtrBase, uint16_t cbLimit)
584{
585#ifdef VBOX_WITH_IEM
586# ifdef VBOX_WITH_RAW_MODE_NOT_R0
587 if (!HMIsEnabled(pVCpu->CTX_SUFF(pVM)))
588 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_GDT);
589# endif
590#endif
591 pVCpu->cpum.s.Guest.gdtr.cbGdt = cbLimit;
592 pVCpu->cpum.s.Guest.gdtr.pGdt = GCPtrBase;
593 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_GDTR;
594 return VINF_SUCCESS; /* formality, consider it void. */
595}
596
597VMMDECL(int) CPUMSetGuestIDTR(PVMCPU pVCpu, uint64_t GCPtrBase, uint16_t cbLimit)
598{
599#ifdef VBOX_WITH_IEM
600# ifdef VBOX_WITH_RAW_MODE_NOT_R0
601 if (!HMIsEnabled(pVCpu->CTX_SUFF(pVM)))
602 VMCPU_FF_SET(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
603# endif
604#endif
605 pVCpu->cpum.s.Guest.idtr.cbIdt = cbLimit;
606 pVCpu->cpum.s.Guest.idtr.pIdt = GCPtrBase;
607 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_IDTR;
608 return VINF_SUCCESS; /* formality, consider it void. */
609}
610
611VMMDECL(int) CPUMSetGuestTR(PVMCPU pVCpu, uint16_t tr)
612{
613#ifdef VBOX_WITH_IEM
614# ifdef VBOX_WITH_RAW_MODE_NOT_R0
615 if (!HMIsEnabled(pVCpu->CTX_SUFF(pVM)))
616 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
617# endif
618#endif
619 pVCpu->cpum.s.Guest.tr.Sel = tr;
620 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_TR;
621 return VINF_SUCCESS; /* formality, consider it void. */
622}
623
624VMMDECL(int) CPUMSetGuestLDTR(PVMCPU pVCpu, uint16_t ldtr)
625{
626#ifdef VBOX_WITH_IEM
627# ifdef VBOX_WITH_RAW_MODE_NOT_R0
628 if ( ( ldtr != 0
629 || pVCpu->cpum.s.Guest.ldtr.Sel != 0)
630 && !HMIsEnabled(pVCpu->CTX_SUFF(pVM)))
631 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_LDT);
632# endif
633#endif
634 pVCpu->cpum.s.Guest.ldtr.Sel = ldtr;
635 /* The caller will set more hidden bits if it has them. */
636 pVCpu->cpum.s.Guest.ldtr.ValidSel = 0;
637 pVCpu->cpum.s.Guest.ldtr.fFlags = 0;
638 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_LDTR;
639 return VINF_SUCCESS; /* formality, consider it void. */
640}
641
642
643/**
644 * Set the guest CR0.
645 *
646 * When called in GC, the hyper CR0 may be updated if that is
647 * required. The caller only has to take special action if AM,
648 * WP, PG or PE changes.
649 *
650 * @returns VINF_SUCCESS (consider it void).
651 * @param pVCpu Handle to the virtual cpu.
652 * @param cr0 The new CR0 value.
653 */
654VMMDECL(int) CPUMSetGuestCR0(PVMCPU pVCpu, uint64_t cr0)
655{
656#ifdef IN_RC
657 /*
658 * Check if we need to change hypervisor CR0 because
659 * of math stuff.
660 */
661 if ( (cr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP))
662 != (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)))
663 {
664 if (!(pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU))
665 {
666 /*
667 * We haven't saved the host FPU state yet, so TS and MT are both set
668 * and EM should be reflecting the guest EM (it always does this).
669 */
670 if ((cr0 & X86_CR0_EM) != (pVCpu->cpum.s.Guest.cr0 & X86_CR0_EM))
671 {
672 uint32_t HyperCR0 = ASMGetCR0();
673 AssertMsg((HyperCR0 & (X86_CR0_TS | X86_CR0_MP)) == (X86_CR0_TS | X86_CR0_MP), ("%#x\n", HyperCR0));
674 AssertMsg((HyperCR0 & X86_CR0_EM) == (pVCpu->cpum.s.Guest.cr0 & X86_CR0_EM), ("%#x\n", HyperCR0));
675 HyperCR0 &= ~X86_CR0_EM;
676 HyperCR0 |= cr0 & X86_CR0_EM;
677 Log(("CPUM: New HyperCR0=%#x\n", HyperCR0));
678 ASMSetCR0(HyperCR0);
679 }
680# ifdef VBOX_STRICT
681 else
682 {
683 uint32_t HyperCR0 = ASMGetCR0();
684 AssertMsg((HyperCR0 & (X86_CR0_TS | X86_CR0_MP)) == (X86_CR0_TS | X86_CR0_MP), ("%#x\n", HyperCR0));
685 AssertMsg((HyperCR0 & X86_CR0_EM) == (pVCpu->cpum.s.Guest.cr0 & X86_CR0_EM), ("%#x\n", HyperCR0));
686 }
687# endif
688 }
689 else
690 {
691 /*
692 * Already saved the state, so we're just mirroring
693 * the guest flags.
694 */
695 uint32_t HyperCR0 = ASMGetCR0();
696 AssertMsg( (HyperCR0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP))
697 == (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)),
698 ("%#x %#x\n", HyperCR0, pVCpu->cpum.s.Guest.cr0));
699 HyperCR0 &= ~(X86_CR0_TS | X86_CR0_EM | X86_CR0_MP);
700 HyperCR0 |= cr0 & (X86_CR0_TS | X86_CR0_EM | X86_CR0_MP);
701 Log(("CPUM: New HyperCR0=%#x\n", HyperCR0));
702 ASMSetCR0(HyperCR0);
703 }
704 }
705#endif /* IN_RC */
706
707 /*
708 * Check for changes causing TLB flushes (for REM).
709 * The caller is responsible for calling PGM when appropriate.
710 */
711 if ( (cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
712 != (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)))
713 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_GLOBAL_TLB_FLUSH;
714 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CR0;
715
716 /*
717 * Let PGM know if the WP goes from 0 to 1 (netware WP0+RO+US hack)
718 */
719 if (((cr0 ^ pVCpu->cpum.s.Guest.cr0) & X86_CR0_WP) && (cr0 & X86_CR0_WP))
720 PGMCr0WpEnabled(pVCpu);
721
722 pVCpu->cpum.s.Guest.cr0 = cr0 | X86_CR0_ET;
723 return VINF_SUCCESS;
724}
725
726
727VMMDECL(int) CPUMSetGuestCR2(PVMCPU pVCpu, uint64_t cr2)
728{
729 pVCpu->cpum.s.Guest.cr2 = cr2;
730 return VINF_SUCCESS;
731}
732
733
734VMMDECL(int) CPUMSetGuestCR3(PVMCPU pVCpu, uint64_t cr3)
735{
736 pVCpu->cpum.s.Guest.cr3 = cr3;
737 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CR3;
738 return VINF_SUCCESS;
739}
740
741
742VMMDECL(int) CPUMSetGuestCR4(PVMCPU pVCpu, uint64_t cr4)
743{
744 if ( (cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE))
745 != (pVCpu->cpum.s.Guest.cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE)))
746 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_GLOBAL_TLB_FLUSH;
747 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CR4;
748 if (!CPUMSupportsFXSR(pVCpu->CTX_SUFF(pVM)))
749 cr4 &= ~X86_CR4_OSFSXR;
750 pVCpu->cpum.s.Guest.cr4 = cr4;
751 return VINF_SUCCESS;
752}
753
754
755VMMDECL(int) CPUMSetGuestEFlags(PVMCPU pVCpu, uint32_t eflags)
756{
757 pVCpu->cpum.s.Guest.eflags.u32 = eflags;
758 return VINF_SUCCESS;
759}
760
761
762VMMDECL(int) CPUMSetGuestEIP(PVMCPU pVCpu, uint32_t eip)
763{
764 pVCpu->cpum.s.Guest.eip = eip;
765 return VINF_SUCCESS;
766}
767
768
769VMMDECL(int) CPUMSetGuestEAX(PVMCPU pVCpu, uint32_t eax)
770{
771 pVCpu->cpum.s.Guest.eax = eax;
772 return VINF_SUCCESS;
773}
774
775
776VMMDECL(int) CPUMSetGuestEBX(PVMCPU pVCpu, uint32_t ebx)
777{
778 pVCpu->cpum.s.Guest.ebx = ebx;
779 return VINF_SUCCESS;
780}
781
782
783VMMDECL(int) CPUMSetGuestECX(PVMCPU pVCpu, uint32_t ecx)
784{
785 pVCpu->cpum.s.Guest.ecx = ecx;
786 return VINF_SUCCESS;
787}
788
789
790VMMDECL(int) CPUMSetGuestEDX(PVMCPU pVCpu, uint32_t edx)
791{
792 pVCpu->cpum.s.Guest.edx = edx;
793 return VINF_SUCCESS;
794}
795
796
797VMMDECL(int) CPUMSetGuestESP(PVMCPU pVCpu, uint32_t esp)
798{
799 pVCpu->cpum.s.Guest.esp = esp;
800 return VINF_SUCCESS;
801}
802
803
804VMMDECL(int) CPUMSetGuestEBP(PVMCPU pVCpu, uint32_t ebp)
805{
806 pVCpu->cpum.s.Guest.ebp = ebp;
807 return VINF_SUCCESS;
808}
809
810
811VMMDECL(int) CPUMSetGuestESI(PVMCPU pVCpu, uint32_t esi)
812{
813 pVCpu->cpum.s.Guest.esi = esi;
814 return VINF_SUCCESS;
815}
816
817
818VMMDECL(int) CPUMSetGuestEDI(PVMCPU pVCpu, uint32_t edi)
819{
820 pVCpu->cpum.s.Guest.edi = edi;
821 return VINF_SUCCESS;
822}
823
824
825VMMDECL(int) CPUMSetGuestSS(PVMCPU pVCpu, uint16_t ss)
826{
827 pVCpu->cpum.s.Guest.ss.Sel = ss;
828 return VINF_SUCCESS;
829}
830
831
832VMMDECL(int) CPUMSetGuestCS(PVMCPU pVCpu, uint16_t cs)
833{
834 pVCpu->cpum.s.Guest.cs.Sel = cs;
835 return VINF_SUCCESS;
836}
837
838
839VMMDECL(int) CPUMSetGuestDS(PVMCPU pVCpu, uint16_t ds)
840{
841 pVCpu->cpum.s.Guest.ds.Sel = ds;
842 return VINF_SUCCESS;
843}
844
845
846VMMDECL(int) CPUMSetGuestES(PVMCPU pVCpu, uint16_t es)
847{
848 pVCpu->cpum.s.Guest.es.Sel = es;
849 return VINF_SUCCESS;
850}
851
852
853VMMDECL(int) CPUMSetGuestFS(PVMCPU pVCpu, uint16_t fs)
854{
855 pVCpu->cpum.s.Guest.fs.Sel = fs;
856 return VINF_SUCCESS;
857}
858
859
860VMMDECL(int) CPUMSetGuestGS(PVMCPU pVCpu, uint16_t gs)
861{
862 pVCpu->cpum.s.Guest.gs.Sel = gs;
863 return VINF_SUCCESS;
864}
865
866
867VMMDECL(void) CPUMSetGuestEFER(PVMCPU pVCpu, uint64_t val)
868{
869 pVCpu->cpum.s.Guest.msrEFER = val;
870}
871
872#ifndef VBOX_WITH_NEW_MSR_CODE
873
874/**
875 * Worker for CPUMQueryGuestMsr().
876 *
877 * @retval VINF_SUCCESS
878 * @retval VERR_CPUM_RAISE_GP_0
879 * @param pVCpu The cross context CPU structure.
880 * @param idMsr The MSR to read.
881 * @param puValue Where to store the return value.
882 */
883static int cpumQueryGuestMsrInt(PVMCPU pVCpu, uint32_t idMsr, uint64_t *puValue)
884{
885 /*
886 * If we don't indicate MSR support in the CPUID feature bits, indicate
887 * that a #GP(0) should be raised.
888 */
889 if (!(pVCpu->CTX_SUFF(pVM)->cpum.s.aGuestCpuIdStd[1].edx & X86_CPUID_FEATURE_EDX_MSR))
890 {
891 *puValue = 0;
892 return VERR_CPUM_RAISE_GP_0; /** @todo isn't \#UD more correct if not supported? */
893 }
894
895 int rc = VINF_SUCCESS;
896 uint8_t const u8Multiplier = 4;
897 switch (idMsr)
898 {
899 case MSR_IA32_TSC:
900 *puValue = TMCpuTickGet(pVCpu);
901 break;
902
903 case MSR_IA32_APICBASE:
904 {
905 /* See @bugref{7097} comment 6. */
906 PVM pVM = pVCpu->CTX_SUFF(pVM);
907 if (PDMHasApic(pVM))
908 *puValue = pVCpu->cpum.s.Guest.msrApicBase;
909 else
910 {
911 rc = VERR_CPUM_RAISE_GP_0;
912 *puValue = 0;
913 }
914 break;
915 }
916
917 case MSR_IA32_CR_PAT:
918 *puValue = pVCpu->cpum.s.Guest.msrPAT;
919 break;
920
921 case MSR_IA32_SYSENTER_CS:
922 *puValue = pVCpu->cpum.s.Guest.SysEnter.cs;
923 break;
924
925 case MSR_IA32_SYSENTER_EIP:
926 *puValue = pVCpu->cpum.s.Guest.SysEnter.eip;
927 break;
928
929 case MSR_IA32_SYSENTER_ESP:
930 *puValue = pVCpu->cpum.s.Guest.SysEnter.esp;
931 break;
932
933 case MSR_IA32_MTRR_CAP:
934 {
935 /* This is currently a bit weird. :-) */
936 uint8_t const cVariableRangeRegs = 0;
937 bool const fSystemManagementRangeRegisters = false;
938 bool const fFixedRangeRegisters = false;
939 bool const fWriteCombiningType = false;
940 *puValue = cVariableRangeRegs
941 | (fFixedRangeRegisters ? RT_BIT_64(8) : 0)
942 | (fWriteCombiningType ? RT_BIT_64(10) : 0)
943 | (fSystemManagementRangeRegisters ? RT_BIT_64(11) : 0);
944 break;
945 }
946
947 case IA32_MTRR_PHYSBASE0: case IA32_MTRR_PHYSMASK0:
948 case IA32_MTRR_PHYSBASE1: case IA32_MTRR_PHYSMASK1:
949 case IA32_MTRR_PHYSBASE2: case IA32_MTRR_PHYSMASK2:
950 case IA32_MTRR_PHYSBASE3: case IA32_MTRR_PHYSMASK3:
951 case IA32_MTRR_PHYSBASE4: case IA32_MTRR_PHYSMASK4:
952 case IA32_MTRR_PHYSBASE5: case IA32_MTRR_PHYSMASK5:
953 case IA32_MTRR_PHYSBASE6: case IA32_MTRR_PHYSMASK6:
954 case IA32_MTRR_PHYSBASE7: case IA32_MTRR_PHYSMASK7:
955 /** @todo implement variable MTRRs. */
956 *puValue = 0;
957 break;
958#if 0 /** @todo newer CPUs have more, figure since when and do selective GP(). */
959 case IA32_MTRR_PHYSBASE8: case IA32_MTRR_PHYSMASK8:
960 case IA32_MTRR_PHYSBASE9: case IA32_MTRR_PHYSMASK9:
961 *puValue = 0;
962 break;
963#endif
964
965 case MSR_IA32_MTRR_DEF_TYPE:
966 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrDefType;
967 break;
968
969 case IA32_MTRR_FIX64K_00000:
970 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix64K_00000;
971 break;
972 case IA32_MTRR_FIX16K_80000:
973 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix16K_80000;
974 break;
975 case IA32_MTRR_FIX16K_A0000:
976 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix16K_A0000;
977 break;
978 case IA32_MTRR_FIX4K_C0000:
979 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_C0000;
980 break;
981 case IA32_MTRR_FIX4K_C8000:
982 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_C8000;
983 break;
984 case IA32_MTRR_FIX4K_D0000:
985 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_D0000;
986 break;
987 case IA32_MTRR_FIX4K_D8000:
988 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_D8000;
989 break;
990 case IA32_MTRR_FIX4K_E0000:
991 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_E0000;
992 break;
993 case IA32_MTRR_FIX4K_E8000:
994 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_E8000;
995 break;
996 case IA32_MTRR_FIX4K_F0000:
997 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_F0000;
998 break;
999 case IA32_MTRR_FIX4K_F8000:
1000 *puValue = pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_F8000;
1001 break;
1002
1003 case MSR_K6_EFER:
1004 *puValue = pVCpu->cpum.s.Guest.msrEFER;
1005 break;
1006
1007 case MSR_K8_SF_MASK:
1008 *puValue = pVCpu->cpum.s.Guest.msrSFMASK;
1009 break;
1010
1011 case MSR_K6_STAR:
1012 *puValue = pVCpu->cpum.s.Guest.msrSTAR;
1013 break;
1014
1015 case MSR_K8_LSTAR:
1016 *puValue = pVCpu->cpum.s.Guest.msrLSTAR;
1017 break;
1018
1019 case MSR_K8_CSTAR:
1020 *puValue = pVCpu->cpum.s.Guest.msrCSTAR;
1021 break;
1022
1023 case MSR_K8_FS_BASE:
1024 *puValue = pVCpu->cpum.s.Guest.fs.u64Base;
1025 break;
1026
1027 case MSR_K8_GS_BASE:
1028 *puValue = pVCpu->cpum.s.Guest.gs.u64Base;
1029 break;
1030
1031 case MSR_K8_KERNEL_GS_BASE:
1032 *puValue = pVCpu->cpum.s.Guest.msrKERNELGSBASE;
1033 break;
1034
1035 case MSR_K8_TSC_AUX:
1036 *puValue = pVCpu->cpum.s.GuestMsrs.msr.TscAux;
1037 break;
1038
1039 case MSR_IA32_PERF_STATUS:
1040 /** @todo could really be not exactly correct, maybe use host's values
1041 * Apple code indicates that we should use CPU Hz / 1.333MHz here. */
1042 /** @todo Where are the specs implemented here found? */
1043 *puValue = UINT64_C(1000) /* TSC increment by tick */
1044 | ((uint64_t)u8Multiplier << 24) /* CPU multiplier (aka bus ratio) min */
1045 | ((uint64_t)u8Multiplier << 40) /* CPU multiplier (aka bus ratio) max */;
1046 break;
1047
1048 case MSR_IA32_FSB_CLOCK_STS:
1049 /*
1050 * Encoded as:
1051 * 0 - 266
1052 * 1 - 133
1053 * 2 - 200
1054 * 3 - return 166
1055 * 5 - return 100
1056 */
1057 *puValue = (2 << 4);
1058 break;
1059
1060 case MSR_IA32_PLATFORM_INFO:
1061 *puValue = ((uint32_t)u8Multiplier << 8) /* Flex ratio max */
1062 | ((uint64_t)u8Multiplier << 40) /* Flex ratio min */;
1063 break;
1064
1065 case MSR_IA32_THERM_STATUS:
1066 /* CPU temperature relative to TCC, to actually activate, CPUID leaf 6 EAX[0] must be set */
1067 *puValue = RT_BIT(31) /* validity bit */
1068 | (UINT64_C(20) << 16) /* degrees till TCC */;
1069 break;
1070
1071 case MSR_IA32_MISC_ENABLE:
1072#if 0
1073 /* Needs to be tested more before enabling. */
1074 *puValue = pVCpu->cpum.s.GuestMsr.msr.miscEnable;
1075#else
1076 /* Currenty we don't allow guests to modify enable MSRs. */
1077 *puValue = MSR_IA32_MISC_ENABLE_FAST_STRINGS /* by default */;
1078
1079 if ((pVCpu->CTX_SUFF(pVM)->cpum.s.aGuestCpuIdStd[1].ecx & X86_CPUID_FEATURE_ECX_MONITOR) != 0)
1080
1081 *puValue |= MSR_IA32_MISC_ENABLE_MONITOR /* if mwait/monitor available */;
1082 /** @todo: add more cpuid-controlled features this way. */
1083#endif
1084 break;
1085
1086 /** @todo virtualize DEBUGCTL and relatives */
1087 case MSR_IA32_DEBUGCTL:
1088 *puValue = 0;
1089 break;
1090
1091#if 0 /*def IN_RING0 */
1092 case MSR_IA32_PLATFORM_ID:
1093 case MSR_IA32_BIOS_SIGN_ID:
1094 if (CPUMGetCPUVendor(pVM) == CPUMCPUVENDOR_INTEL)
1095 {
1096 /* Available since the P6 family. VT-x implies that this feature is present. */
1097 if (idMsr == MSR_IA32_PLATFORM_ID)
1098 *puValue = ASMRdMsr(MSR_IA32_PLATFORM_ID);
1099 else if (idMsr == MSR_IA32_BIOS_SIGN_ID)
1100 *puValue = ASMRdMsr(MSR_IA32_BIOS_SIGN_ID);
1101 break;
1102 }
1103 /* no break */
1104#endif
1105 /*
1106 * The BIOS_SIGN_ID MSR and MSR_IA32_MCP_CAP et al exist on AMD64 as
1107 * well, at least bulldozer have them. Windows 7 is querying them.
1108 * XP has been observed querying MSR_IA32_MC0_CTL.
1109 * XP64 has been observed querying MSR_P4_LASTBRANCH_0 (also on AMD).
1110 */
1111 case MSR_IA32_BIOS_SIGN_ID: /* fam/mod >= 6_01 */
1112 case MSR_IA32_MCG_CAP: /* fam/mod >= 6_01 */
1113 case MSR_IA32_MCG_STATUS: /* indicated as not present in CAP */
1114 /*case MSR_IA32_MCG_CTRL: - indicated as not present in CAP */
1115 case MSR_IA32_MC0_CTL:
1116 case MSR_IA32_MC0_STATUS:
1117 case MSR_P4_LASTBRANCH_0:
1118 case MSR_P4_LASTBRANCH_1:
1119 case MSR_P4_LASTBRANCH_2:
1120 case MSR_P4_LASTBRANCH_3:
1121 *puValue = 0;
1122 break;
1123
1124
1125 /*
1126 * Intel specifics MSRs:
1127 */
1128 case MSR_P5_MC_ADDR:
1129 case MSR_P5_MC_TYPE:
1130 case MSR_P4_LASTBRANCH_TOS: /** @todo Are these branch regs still here on more recent CPUs? The documentation doesn't mention them for several archs. */
1131 case MSR_IA32_PERFEVTSEL0: /* NetWare 6.5 wants the these four. (Bet on AMD as well.) */
1132 case MSR_IA32_PERFEVTSEL1:
1133 case MSR_IA32_PMC0:
1134 case MSR_IA32_PMC1:
1135 case MSR_IA32_PLATFORM_ID: /* fam/mod >= 6_01 */
1136 case MSR_IA32_MPERF: /* intel_pstate depends on this but does a validation test */
1137 case MSR_IA32_APERF: /* intel_pstate depends on this but does a validation test */
1138 /*case MSR_IA32_BIOS_UPDT_TRIG: - write-only? */
1139 case MSR_RAPL_POWER_UNIT:
1140 case MSR_BBL_CR_CTL3: /* ca. core arch? */
1141 case MSR_PKG_CST_CONFIG_CONTROL: /* Nahalem, Sandy Bridge */
1142 case MSR_CORE_THREAD_COUNT: /* Apple queries this. */
1143 case MSR_FLEX_RATIO: /* Apple queries this. */
1144 *puValue = 0;
1145 if (CPUMGetGuestCpuVendor(pVCpu->CTX_SUFF(pVM)) != CPUMCPUVENDOR_INTEL)
1146 {
1147 Log(("CPUM: MSR %#x is Intel, the virtual CPU isn't an Intel one -> #GP\n", idMsr));
1148 rc = VERR_CPUM_RAISE_GP_0;
1149 break;
1150 }
1151
1152 /* Provide more plausive values for some of them. */
1153 switch (idMsr)
1154 {
1155 case MSR_RAPL_POWER_UNIT:
1156 *puValue = RT_MAKE_U32_FROM_U8(3 /* power units (1/8 W)*/,
1157 16 /* 15.3 micro-Joules */,
1158 10 /* 976 microseconds increments */,
1159 0);
1160 break;
1161 case MSR_BBL_CR_CTL3:
1162 *puValue = RT_MAKE_U32_FROM_U8(1, /* bit 0 - L2 Hardware Enabled. (RO) */
1163 1, /* bit 8 - L2 Enabled (R/W). */
1164 0, /* bit 23 - L2 Not Present (RO). */
1165 0);
1166 break;
1167 case MSR_PKG_CST_CONFIG_CONTROL:
1168 *puValue = pVCpu->cpum.s.GuestMsrs.msr.PkgCStateCfgCtrl;
1169 break;
1170 case MSR_CORE_THREAD_COUNT:
1171 {
1172 /** @todo restrict this to nehalem. */
1173 PVM pVM = pVCpu->CTX_SUFF(pVM); /* Note! Not sweating the 4-bit core count limit on westmere. */
1174 *puValue = (pVM->cCpus & 0xffff) | ((pVM->cCpus & 0xffff) << 16);
1175 break;
1176 }
1177
1178 case MSR_FLEX_RATIO:
1179 {
1180 /** @todo Check for P4, it's different there. Try find accurate specs. */
1181 *puValue = (uint32_t)u8Multiplier << 8;
1182 break;
1183 }
1184 }
1185 break;
1186
1187#if 0 /* Only on pentium CPUs! */
1188 /* Event counters, not supported. */
1189 case MSR_IA32_CESR:
1190 case MSR_IA32_CTR0:
1191 case MSR_IA32_CTR1:
1192 *puValue = 0;
1193 break;
1194#endif
1195
1196
1197 /*
1198 * AMD specific MSRs:
1199 */
1200 case MSR_K8_SYSCFG:
1201 case MSR_K8_INT_PENDING:
1202 case MSR_K8_NB_CFG: /* (All known values are 0 on reset.) */
1203 case MSR_K8_HWCR: /* Very interesting bits here. :) */
1204 case MSR_K8_VM_CR: /* Windows 8 */
1205 case 0xc0011029: /* quick fix for FreeBSd 9.1. */
1206 case 0xc0010042: /* quick fix for something. */
1207 case 0xc001102a: /* quick fix for w2k8 + opposition. */
1208 case 0xc0011004: /* quick fix for the opposition. */
1209 case 0xc0011005: /* quick fix for the opposition. */
1210 case MSR_K7_EVNTSEL0: /* quick fix for the opposition. */
1211 case MSR_K7_EVNTSEL1: /* quick fix for the opposition. */
1212 case MSR_K7_EVNTSEL2: /* quick fix for the opposition. */
1213 case MSR_K7_EVNTSEL3: /* quick fix for the opposition. */
1214 case MSR_K7_PERFCTR0: /* quick fix for the opposition. */
1215 case MSR_K7_PERFCTR1: /* quick fix for the opposition. */
1216 case MSR_K7_PERFCTR2: /* quick fix for the opposition. */
1217 case MSR_K7_PERFCTR3: /* quick fix for the opposition. */
1218 *puValue = 0;
1219 if (CPUMGetGuestCpuVendor(pVCpu->CTX_SUFF(pVM)) != CPUMCPUVENDOR_AMD)
1220 {
1221 Log(("CPUM: MSR %#x is AMD, the virtual CPU isn't an Intel one -> #GP\n", idMsr));
1222 return VERR_CPUM_RAISE_GP_0;
1223 }
1224 /* ignored */
1225 break;
1226
1227 default:
1228 /*
1229 * Hand the X2APIC range to PDM and the APIC.
1230 */
1231 if ( idMsr >= MSR_IA32_X2APIC_START
1232 && idMsr <= MSR_IA32_X2APIC_END)
1233 {
1234 rc = PDMApicReadMSR(pVCpu->CTX_SUFF(pVM), pVCpu->idCpu, idMsr, puValue);
1235 if (RT_SUCCESS(rc))
1236 rc = VINF_SUCCESS;
1237 else
1238 {
1239 *puValue = 0;
1240 rc = VERR_CPUM_RAISE_GP_0;
1241 }
1242 }
1243 else
1244 {
1245 *puValue = 0;
1246 rc = VERR_CPUM_RAISE_GP_0;
1247 }
1248 break;
1249 }
1250
1251 return rc;
1252}
1253
1254
1255/**
1256 * Query an MSR.
1257 *
1258 * The caller is responsible for checking privilege if the call is the result
1259 * of a RDMSR instruction. We'll do the rest.
1260 *
1261 * @retval VINF_SUCCESS on success.
1262 * @retval VERR_CPUM_RAISE_GP_0 on failure (invalid MSR), the caller is
1263 * expected to take the appropriate actions. @a *puValue is set to 0.
1264 * @param pVCpu Pointer to the VMCPU.
1265 * @param idMsr The MSR.
1266 * @param puValue Where to return the value.
1267 *
1268 * @remarks This will always return the right values, even when we're in the
1269 * recompiler.
1270 */
1271VMMDECL(int) CPUMQueryGuestMsr(PVMCPU pVCpu, uint32_t idMsr, uint64_t *puValue)
1272{
1273 int rc = cpumQueryGuestMsrInt(pVCpu, idMsr, puValue);
1274 LogFlow(("CPUMQueryGuestMsr: %#x -> %llx rc=%d\n", idMsr, *puValue, rc));
1275 return rc;
1276}
1277
1278
1279/**
1280 * Sets the MSR.
1281 *
1282 * The caller is responsible for checking privilege if the call is the result
1283 * of a WRMSR instruction. We'll do the rest.
1284 *
1285 * @retval VINF_SUCCESS on success.
1286 * @retval VERR_CPUM_RAISE_GP_0 on failure, the caller is expected to take the
1287 * appropriate actions.
1288 *
1289 * @param pVCpu Pointer to the VMCPU.
1290 * @param idMsr The MSR id.
1291 * @param uValue The value to set.
1292 *
1293 * @remarks Everyone changing MSR values, including the recompiler, shall do it
1294 * by calling this method. This makes sure we have current values and
1295 * that we trigger all the right actions when something changes.
1296 */
1297VMMDECL(int) CPUMSetGuestMsr(PVMCPU pVCpu, uint32_t idMsr, uint64_t uValue)
1298{
1299 LogFlow(("CPUMSetGuestMsr: %#x <- %#llx\n", idMsr, uValue));
1300
1301 /*
1302 * If we don't indicate MSR support in the CPUID feature bits, indicate
1303 * that a #GP(0) should be raised.
1304 */
1305 if (!(pVCpu->CTX_SUFF(pVM)->cpum.s.aGuestCpuIdStd[1].edx & X86_CPUID_FEATURE_EDX_MSR))
1306 return VERR_CPUM_RAISE_GP_0; /** @todo isn't \#UD more correct if not supported? */
1307
1308 int rc = VINF_SUCCESS;
1309 switch (idMsr)
1310 {
1311 case MSR_IA32_MISC_ENABLE:
1312 pVCpu->cpum.s.GuestMsrs.msr.MiscEnable = uValue;
1313 break;
1314
1315 case MSR_IA32_TSC:
1316 TMCpuTickSet(pVCpu->CTX_SUFF(pVM), pVCpu, uValue);
1317 break;
1318
1319 case MSR_IA32_APICBASE:
1320 rc = PDMApicSetBase(pVCpu, uValue);
1321 if (rc != VINF_SUCCESS)
1322 rc = VERR_CPUM_RAISE_GP_0;
1323 break;
1324
1325 case MSR_IA32_CR_PAT:
1326 pVCpu->cpum.s.Guest.msrPAT = uValue;
1327 break;
1328
1329 case MSR_IA32_SYSENTER_CS:
1330 pVCpu->cpum.s.Guest.SysEnter.cs = uValue & 0xffff; /* 16 bits selector */
1331 break;
1332
1333 case MSR_IA32_SYSENTER_EIP:
1334 pVCpu->cpum.s.Guest.SysEnter.eip = uValue;
1335 break;
1336
1337 case MSR_IA32_SYSENTER_ESP:
1338 pVCpu->cpum.s.Guest.SysEnter.esp = uValue;
1339 break;
1340
1341 case MSR_IA32_MTRR_CAP:
1342 return VERR_CPUM_RAISE_GP_0;
1343
1344 case MSR_IA32_MTRR_DEF_TYPE:
1345 if ( (uValue & UINT64_C(0xfffffffffffff300))
1346 || ( (uValue & 0xff) != 0
1347 && (uValue & 0xff) != 1
1348 && (uValue & 0xff) != 4
1349 && (uValue & 0xff) != 5
1350 && (uValue & 0xff) != 6) )
1351 {
1352 Log(("CPUM: MSR_IA32_MTRR_DEF_TYPE: #GP(0) - writing reserved value (%#llx)\n", uValue));
1353 return VERR_CPUM_RAISE_GP_0;
1354 }
1355 pVCpu->cpum.s.GuestMsrs.msr.MtrrDefType = uValue;
1356 break;
1357
1358 case IA32_MTRR_PHYSBASE0: case IA32_MTRR_PHYSMASK0:
1359 case IA32_MTRR_PHYSBASE1: case IA32_MTRR_PHYSMASK1:
1360 case IA32_MTRR_PHYSBASE2: case IA32_MTRR_PHYSMASK2:
1361 case IA32_MTRR_PHYSBASE3: case IA32_MTRR_PHYSMASK3:
1362 case IA32_MTRR_PHYSBASE4: case IA32_MTRR_PHYSMASK4:
1363 case IA32_MTRR_PHYSBASE5: case IA32_MTRR_PHYSMASK5:
1364 case IA32_MTRR_PHYSBASE6: case IA32_MTRR_PHYSMASK6:
1365 case IA32_MTRR_PHYSBASE7: case IA32_MTRR_PHYSMASK7:
1366 /** @todo implement variable MTRRs. */
1367 break;
1368#if 0 /** @todo newer CPUs have more, figure since when and do selective GP(). */
1369 case IA32_MTRR_PHYSBASE8: case IA32_MTRR_PHYSMASK8:
1370 case IA32_MTRR_PHYSBASE9: case IA32_MTRR_PHYSMASK9:
1371 break;
1372#endif
1373
1374 case IA32_MTRR_FIX64K_00000:
1375 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix64K_00000 = uValue;
1376 break;
1377 case IA32_MTRR_FIX16K_80000:
1378 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix16K_80000 = uValue;
1379 break;
1380 case IA32_MTRR_FIX16K_A0000:
1381 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix16K_A0000 = uValue;
1382 break;
1383 case IA32_MTRR_FIX4K_C0000:
1384 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_C0000 = uValue;
1385 break;
1386 case IA32_MTRR_FIX4K_C8000:
1387 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_C8000 = uValue;
1388 break;
1389 case IA32_MTRR_FIX4K_D0000:
1390 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_D0000 = uValue;
1391 break;
1392 case IA32_MTRR_FIX4K_D8000:
1393 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_D8000 = uValue;
1394 break;
1395 case IA32_MTRR_FIX4K_E0000:
1396 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_E0000 = uValue;
1397 break;
1398 case IA32_MTRR_FIX4K_E8000:
1399 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_E8000 = uValue;
1400 break;
1401 case IA32_MTRR_FIX4K_F0000:
1402 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_F0000 = uValue;
1403 break;
1404 case IA32_MTRR_FIX4K_F8000:
1405 pVCpu->cpum.s.GuestMsrs.msr.MtrrFix4K_F8000 = uValue;
1406 break;
1407
1408 /*
1409 * AMD64 MSRs.
1410 */
1411 case MSR_K6_EFER:
1412 {
1413 PVM pVM = pVCpu->CTX_SUFF(pVM);
1414 uint64_t const uOldEFER = pVCpu->cpum.s.Guest.msrEFER;
1415 uint32_t const fExtFeatures = pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
1416 ? pVM->cpum.s.aGuestCpuIdExt[1].edx
1417 : 0;
1418 uint64_t fMask = 0;
1419
1420 /* Filter out those bits the guest is allowed to change. (e.g. LMA is read-only) */
1421 if (fExtFeatures & X86_CPUID_EXT_FEATURE_EDX_NX)
1422 fMask |= MSR_K6_EFER_NXE;
1423 if (fExtFeatures & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE)
1424 fMask |= MSR_K6_EFER_LME;
1425 if (fExtFeatures & X86_CPUID_EXT_FEATURE_EDX_SYSCALL)
1426 fMask |= MSR_K6_EFER_SCE;
1427 if (fExtFeatures & X86_CPUID_AMD_FEATURE_EDX_FFXSR)
1428 fMask |= MSR_K6_EFER_FFXSR;
1429
1430 /* Check for illegal MSR_K6_EFER_LME transitions: not allowed to change LME if
1431 paging is enabled. (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */
1432 if ( (uOldEFER & MSR_K6_EFER_LME) != (uValue & fMask & MSR_K6_EFER_LME)
1433 && (pVCpu->cpum.s.Guest.cr0 & X86_CR0_PG))
1434 {
1435 Log(("CPUM: Illegal MSR_K6_EFER_LME change: paging is enabled!!\n"));
1436 return VERR_CPUM_RAISE_GP_0;
1437 }
1438
1439 /* There are a few more: e.g. MSR_K6_EFER_LMSLE */
1440 AssertMsg(!(uValue & ~(MSR_K6_EFER_NXE | MSR_K6_EFER_LME | MSR_K6_EFER_LMA /* ignored anyway */ | MSR_K6_EFER_SCE | MSR_K6_EFER_FFXSR)),
1441 ("Unexpected value %RX64\n", uValue));
1442 pVCpu->cpum.s.Guest.msrEFER = (uOldEFER & ~fMask) | (uValue & fMask);
1443
1444 /* AMD64 Architecture Programmer's Manual: 15.15 TLB Control; flush the TLB
1445 if MSR_K6_EFER_NXE, MSR_K6_EFER_LME or MSR_K6_EFER_LMA are changed. */
1446 if ( (uOldEFER & (MSR_K6_EFER_NXE | MSR_K6_EFER_LME | MSR_K6_EFER_LMA))
1447 != (pVCpu->cpum.s.Guest.msrEFER & (MSR_K6_EFER_NXE | MSR_K6_EFER_LME | MSR_K6_EFER_LMA)))
1448 {
1449 /// @todo PGMFlushTLB(pVCpu, cr3, true /*fGlobal*/);
1450 HMFlushTLB(pVCpu);
1451
1452 /* Notify PGM about NXE changes. */
1453 if ( (uOldEFER & MSR_K6_EFER_NXE)
1454 != (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_NXE))
1455 PGMNotifyNxeChanged(pVCpu, !(uOldEFER & MSR_K6_EFER_NXE));
1456 }
1457 break;
1458 }
1459
1460 case MSR_K8_SF_MASK:
1461 pVCpu->cpum.s.Guest.msrSFMASK = uValue;
1462 break;
1463
1464 case MSR_K6_STAR:
1465 pVCpu->cpum.s.Guest.msrSTAR = uValue;
1466 break;
1467
1468 case MSR_K8_LSTAR:
1469 pVCpu->cpum.s.Guest.msrLSTAR = uValue;
1470 break;
1471
1472 case MSR_K8_CSTAR:
1473 pVCpu->cpum.s.Guest.msrCSTAR = uValue;
1474 break;
1475
1476 case MSR_K8_FS_BASE:
1477 pVCpu->cpum.s.Guest.fs.u64Base = uValue;
1478 break;
1479
1480 case MSR_K8_GS_BASE:
1481 pVCpu->cpum.s.Guest.gs.u64Base = uValue;
1482 break;
1483
1484 case MSR_K8_KERNEL_GS_BASE:
1485 pVCpu->cpum.s.Guest.msrKERNELGSBASE = uValue;
1486 break;
1487
1488 case MSR_K8_TSC_AUX:
1489 pVCpu->cpum.s.GuestMsrs.msr.TscAux = uValue;
1490 break;
1491
1492 case MSR_IA32_DEBUGCTL:
1493 /** @todo virtualize DEBUGCTL and relatives */
1494 break;
1495
1496 /*
1497 * Intel specifics MSRs:
1498 */
1499 /*case MSR_IA32_PLATFORM_ID: - read-only */
1500 case MSR_IA32_BIOS_SIGN_ID: /* fam/mod >= 6_01 */
1501 case MSR_IA32_BIOS_UPDT_TRIG: /* fam/mod >= 6_01 */
1502 /*case MSR_IA32_MCP_CAP: - read-only */
1503 /*case MSR_IA32_MCG_STATUS: - read-only */
1504 /*case MSR_IA32_MCG_CTRL: - indicated as not present in CAP */
1505 /*case MSR_IA32_MC0_CTL: - read-only? */
1506 /*case MSR_IA32_MC0_STATUS: - read-only? */
1507 case MSR_PKG_CST_CONFIG_CONTROL:
1508 if (CPUMGetGuestCpuVendor(pVCpu->CTX_SUFF(pVM)) != CPUMCPUVENDOR_INTEL)
1509 {
1510 Log(("CPUM: MSR %#x is Intel, the virtual CPU isn't an Intel one -> #GP\n", idMsr));
1511 return VERR_CPUM_RAISE_GP_0;
1512 }
1513
1514 switch (idMsr)
1515 {
1516 case MSR_PKG_CST_CONFIG_CONTROL:
1517 {
1518 if (pVCpu->cpum.s.GuestMsrs.msr.PkgCStateCfgCtrl & RT_BIT_64(15))
1519 {
1520 Log(("MSR_PKG_CST_CONFIG_CONTROL: Write protected -> #GP\n"));
1521 return VERR_CPUM_RAISE_GP_0;
1522 }
1523 static uint64_t s_fMask = UINT64_C(0x01f08407); /** @todo Only Nehalem has 24; Only Sandy has 27 and 28. */
1524 static uint64_t s_fGpInvalid = UINT64_C(0xffffffff00ff0000); /** @todo figure out exactly what's off limits. */
1525 if ((uValue & s_fGpInvalid) || (uValue & 7) >= 5)
1526 {
1527 Log(("MSR_PKG_CST_CONFIG_CONTROL: Invalid value %#llx -> #GP\n", uValue));
1528 return VERR_CPUM_RAISE_GP_0;
1529 }
1530 pVCpu->cpum.s.GuestMsrs.msr.PkgCStateCfgCtrl = uValue & s_fMask;
1531 break;
1532 }
1533
1534 }
1535 /* ignored */
1536 break;
1537
1538 /*
1539 * AMD specific MSRs:
1540 */
1541 case MSR_K8_SYSCFG: /** @todo can be written, but we ignore that for now. */
1542 case MSR_K8_INT_PENDING: /** @todo can be written, but we ignore that for now. */
1543 case MSR_K8_NB_CFG: /** @todo can be written; the apicid swapping might be used and would need saving, but probably unnecessary. */
1544 case 0xc0011029: /* quick fix for FreeBSd 9.1. */
1545 case 0xc0010042: /* quick fix for something. */
1546 case 0xc001102a: /* quick fix for w2k8 + opposition. */
1547 case 0xc0011004: /* quick fix for the opposition. */
1548 case 0xc0011005: /* quick fix for the opposition. */
1549 case MSR_K7_EVNTSEL0: /* quick fix for the opposition. */
1550 case MSR_K7_EVNTSEL1: /* quick fix for the opposition. */
1551 case MSR_K7_EVNTSEL2: /* quick fix for the opposition. */
1552 case MSR_K7_EVNTSEL3: /* quick fix for the opposition. */
1553 case MSR_K7_PERFCTR0: /* quick fix for the opposition. */
1554 case MSR_K7_PERFCTR1: /* quick fix for the opposition. */
1555 case MSR_K7_PERFCTR2: /* quick fix for the opposition. */
1556 case MSR_K7_PERFCTR3: /* quick fix for the opposition. */
1557 if (CPUMGetGuestCpuVendor(pVCpu->CTX_SUFF(pVM)) != CPUMCPUVENDOR_AMD)
1558 {
1559 Log(("CPUM: MSR %#x is AMD, the virtual CPU isn't an Intel one -> #GP\n", idMsr));
1560 return VERR_CPUM_RAISE_GP_0;
1561 }
1562 /* ignored */
1563 break;
1564
1565
1566 default:
1567 /*
1568 * Hand the X2APIC range to PDM and the APIC.
1569 */
1570 if ( idMsr >= MSR_IA32_X2APIC_START
1571 && idMsr <= MSR_IA32_X2APIC_END)
1572 {
1573 rc = PDMApicWriteMSR(pVCpu->CTX_SUFF(pVM), pVCpu->idCpu, idMsr, uValue);
1574 if (rc != VINF_SUCCESS)
1575 rc = VERR_CPUM_RAISE_GP_0;
1576 }
1577 else
1578 {
1579 /* We should actually trigger a #GP here, but don't as that might cause more trouble. */
1580 /** @todo rc = VERR_CPUM_RAISE_GP_0 */
1581 Log(("CPUMSetGuestMsr: Unknown MSR %#x attempted set to %#llx\n", idMsr, uValue));
1582 }
1583 break;
1584 }
1585 return rc;
1586}
1587
1588#endif /* !VBOX_WITH_NEW_MSR_CODE */
1589
1590
1591VMMDECL(RTGCPTR) CPUMGetGuestIDTR(PVMCPU pVCpu, uint16_t *pcbLimit)
1592{
1593 if (pcbLimit)
1594 *pcbLimit = pVCpu->cpum.s.Guest.idtr.cbIdt;
1595 return pVCpu->cpum.s.Guest.idtr.pIdt;
1596}
1597
1598
1599VMMDECL(RTSEL) CPUMGetGuestTR(PVMCPU pVCpu, PCPUMSELREGHID pHidden)
1600{
1601 if (pHidden)
1602 *pHidden = pVCpu->cpum.s.Guest.tr;
1603 return pVCpu->cpum.s.Guest.tr.Sel;
1604}
1605
1606
1607VMMDECL(RTSEL) CPUMGetGuestCS(PVMCPU pVCpu)
1608{
1609 return pVCpu->cpum.s.Guest.cs.Sel;
1610}
1611
1612
1613VMMDECL(RTSEL) CPUMGetGuestDS(PVMCPU pVCpu)
1614{
1615 return pVCpu->cpum.s.Guest.ds.Sel;
1616}
1617
1618
1619VMMDECL(RTSEL) CPUMGetGuestES(PVMCPU pVCpu)
1620{
1621 return pVCpu->cpum.s.Guest.es.Sel;
1622}
1623
1624
1625VMMDECL(RTSEL) CPUMGetGuestFS(PVMCPU pVCpu)
1626{
1627 return pVCpu->cpum.s.Guest.fs.Sel;
1628}
1629
1630
1631VMMDECL(RTSEL) CPUMGetGuestGS(PVMCPU pVCpu)
1632{
1633 return pVCpu->cpum.s.Guest.gs.Sel;
1634}
1635
1636
1637VMMDECL(RTSEL) CPUMGetGuestSS(PVMCPU pVCpu)
1638{
1639 return pVCpu->cpum.s.Guest.ss.Sel;
1640}
1641
1642
1643VMMDECL(RTSEL) CPUMGetGuestLDTR(PVMCPU pVCpu)
1644{
1645 return pVCpu->cpum.s.Guest.ldtr.Sel;
1646}
1647
1648
1649VMMDECL(RTSEL) CPUMGetGuestLdtrEx(PVMCPU pVCpu, uint64_t *pGCPtrBase, uint32_t *pcbLimit)
1650{
1651 *pGCPtrBase = pVCpu->cpum.s.Guest.ldtr.u64Base;
1652 *pcbLimit = pVCpu->cpum.s.Guest.ldtr.u32Limit;
1653 return pVCpu->cpum.s.Guest.ldtr.Sel;
1654}
1655
1656
1657VMMDECL(uint64_t) CPUMGetGuestCR0(PVMCPU pVCpu)
1658{
1659 return pVCpu->cpum.s.Guest.cr0;
1660}
1661
1662
1663VMMDECL(uint64_t) CPUMGetGuestCR2(PVMCPU pVCpu)
1664{
1665 return pVCpu->cpum.s.Guest.cr2;
1666}
1667
1668
1669VMMDECL(uint64_t) CPUMGetGuestCR3(PVMCPU pVCpu)
1670{
1671 return pVCpu->cpum.s.Guest.cr3;
1672}
1673
1674
1675VMMDECL(uint64_t) CPUMGetGuestCR4(PVMCPU pVCpu)
1676{
1677 return pVCpu->cpum.s.Guest.cr4;
1678}
1679
1680
1681VMMDECL(uint64_t) CPUMGetGuestCR8(PVMCPU pVCpu)
1682{
1683 uint64_t u64;
1684 int rc = CPUMGetGuestCRx(pVCpu, DISCREG_CR8, &u64);
1685 if (RT_FAILURE(rc))
1686 u64 = 0;
1687 return u64;
1688}
1689
1690
1691VMMDECL(void) CPUMGetGuestGDTR(PVMCPU pVCpu, PVBOXGDTR pGDTR)
1692{
1693 *pGDTR = pVCpu->cpum.s.Guest.gdtr;
1694}
1695
1696
1697VMMDECL(uint32_t) CPUMGetGuestEIP(PVMCPU pVCpu)
1698{
1699 return pVCpu->cpum.s.Guest.eip;
1700}
1701
1702
1703VMMDECL(uint64_t) CPUMGetGuestRIP(PVMCPU pVCpu)
1704{
1705 return pVCpu->cpum.s.Guest.rip;
1706}
1707
1708
1709VMMDECL(uint32_t) CPUMGetGuestEAX(PVMCPU pVCpu)
1710{
1711 return pVCpu->cpum.s.Guest.eax;
1712}
1713
1714
1715VMMDECL(uint32_t) CPUMGetGuestEBX(PVMCPU pVCpu)
1716{
1717 return pVCpu->cpum.s.Guest.ebx;
1718}
1719
1720
1721VMMDECL(uint32_t) CPUMGetGuestECX(PVMCPU pVCpu)
1722{
1723 return pVCpu->cpum.s.Guest.ecx;
1724}
1725
1726
1727VMMDECL(uint32_t) CPUMGetGuestEDX(PVMCPU pVCpu)
1728{
1729 return pVCpu->cpum.s.Guest.edx;
1730}
1731
1732
1733VMMDECL(uint32_t) CPUMGetGuestESI(PVMCPU pVCpu)
1734{
1735 return pVCpu->cpum.s.Guest.esi;
1736}
1737
1738
1739VMMDECL(uint32_t) CPUMGetGuestEDI(PVMCPU pVCpu)
1740{
1741 return pVCpu->cpum.s.Guest.edi;
1742}
1743
1744
1745VMMDECL(uint32_t) CPUMGetGuestESP(PVMCPU pVCpu)
1746{
1747 return pVCpu->cpum.s.Guest.esp;
1748}
1749
1750
1751VMMDECL(uint32_t) CPUMGetGuestEBP(PVMCPU pVCpu)
1752{
1753 return pVCpu->cpum.s.Guest.ebp;
1754}
1755
1756
1757VMMDECL(uint32_t) CPUMGetGuestEFlags(PVMCPU pVCpu)
1758{
1759 return pVCpu->cpum.s.Guest.eflags.u32;
1760}
1761
1762
1763VMMDECL(int) CPUMGetGuestCRx(PVMCPU pVCpu, unsigned iReg, uint64_t *pValue)
1764{
1765 switch (iReg)
1766 {
1767 case DISCREG_CR0:
1768 *pValue = pVCpu->cpum.s.Guest.cr0;
1769 break;
1770
1771 case DISCREG_CR2:
1772 *pValue = pVCpu->cpum.s.Guest.cr2;
1773 break;
1774
1775 case DISCREG_CR3:
1776 *pValue = pVCpu->cpum.s.Guest.cr3;
1777 break;
1778
1779 case DISCREG_CR4:
1780 *pValue = pVCpu->cpum.s.Guest.cr4;
1781 break;
1782
1783 case DISCREG_CR8:
1784 {
1785 uint8_t u8Tpr;
1786 int rc = PDMApicGetTPR(pVCpu, &u8Tpr, NULL /* pfPending */, NULL /* pu8PendingIrq */);
1787 if (RT_FAILURE(rc))
1788 {
1789 AssertMsg(rc == VERR_PDM_NO_APIC_INSTANCE, ("%Rrc\n", rc));
1790 *pValue = 0;
1791 return rc;
1792 }
1793 *pValue = u8Tpr >> 4; /* bits 7-4 contain the task priority that go in cr8, bits 3-0*/
1794 break;
1795 }
1796
1797 default:
1798 return VERR_INVALID_PARAMETER;
1799 }
1800 return VINF_SUCCESS;
1801}
1802
1803
1804VMMDECL(uint64_t) CPUMGetGuestDR0(PVMCPU pVCpu)
1805{
1806 return pVCpu->cpum.s.Guest.dr[0];
1807}
1808
1809
1810VMMDECL(uint64_t) CPUMGetGuestDR1(PVMCPU pVCpu)
1811{
1812 return pVCpu->cpum.s.Guest.dr[1];
1813}
1814
1815
1816VMMDECL(uint64_t) CPUMGetGuestDR2(PVMCPU pVCpu)
1817{
1818 return pVCpu->cpum.s.Guest.dr[2];
1819}
1820
1821
1822VMMDECL(uint64_t) CPUMGetGuestDR3(PVMCPU pVCpu)
1823{
1824 return pVCpu->cpum.s.Guest.dr[3];
1825}
1826
1827
1828VMMDECL(uint64_t) CPUMGetGuestDR6(PVMCPU pVCpu)
1829{
1830 return pVCpu->cpum.s.Guest.dr[6];
1831}
1832
1833
1834VMMDECL(uint64_t) CPUMGetGuestDR7(PVMCPU pVCpu)
1835{
1836 return pVCpu->cpum.s.Guest.dr[7];
1837}
1838
1839
1840VMMDECL(int) CPUMGetGuestDRx(PVMCPU pVCpu, uint32_t iReg, uint64_t *pValue)
1841{
1842 AssertReturn(iReg <= DISDREG_DR7, VERR_INVALID_PARAMETER);
1843 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
1844 if (iReg == 4 || iReg == 5)
1845 iReg += 2;
1846 *pValue = pVCpu->cpum.s.Guest.dr[iReg];
1847 return VINF_SUCCESS;
1848}
1849
1850
1851VMMDECL(uint64_t) CPUMGetGuestEFER(PVMCPU pVCpu)
1852{
1853 return pVCpu->cpum.s.Guest.msrEFER;
1854}
1855
1856
1857/**
1858 * Looks up a CPUID leaf in the CPUID leaf array.
1859 *
1860 * @returns Pointer to the leaf if found, NULL if not.
1861 *
1862 * @param pVM Pointer to the cross context VM structure.
1863 * @param uLeaf The leaf to get.
1864 * @param uSubLeaf The subleaf, if applicable. Just pass 0 if it
1865 * isn't.
1866 */
1867PCPUMCPUIDLEAF cpumCpuIdGetLeaf(PVM pVM, uint32_t uLeaf, uint32_t uSubLeaf)
1868{
1869 unsigned iEnd = pVM->cpum.s.GuestInfo.cCpuIdLeaves;
1870 if (iEnd)
1871 {
1872 unsigned iStart = 0;
1873 PCPUMCPUIDLEAF paLeaves = pVM->cpum.s.GuestInfo.CTX_SUFF(paCpuIdLeaves);
1874 for (;;)
1875 {
1876 unsigned i = iStart + (iEnd - iStart) / 2U;
1877 if (uLeaf < paLeaves[i].uLeaf)
1878 {
1879 if (i <= iStart)
1880 return NULL;
1881 iEnd = i;
1882 }
1883 else if (uLeaf > paLeaves[i].uLeaf)
1884 {
1885 i += 1;
1886 if (i >= iEnd)
1887 return NULL;
1888 iStart = i;
1889 }
1890 else
1891 {
1892 uSubLeaf &= paLeaves[i].fSubLeafMask;
1893 if (uSubLeaf != paLeaves[i].uSubLeaf)
1894 {
1895 /* Find the right subleaf. We return the last one before
1896 uSubLeaf if we don't find an exact match. */
1897 if (uSubLeaf < paLeaves[i].uSubLeaf)
1898 while ( i > 0
1899 && uLeaf == paLeaves[i].uLeaf
1900 && uSubLeaf < paLeaves[i].uSubLeaf)
1901 i--;
1902 else
1903 while ( i + 1 < pVM->cpum.s.GuestInfo.cCpuIdLeaves
1904 && uLeaf == paLeaves[i + 1].uLeaf
1905 && uSubLeaf >= paLeaves[i + 1].uSubLeaf)
1906 i++;
1907 }
1908 return &paLeaves[i];
1909 }
1910 }
1911 }
1912
1913 return NULL;
1914}
1915
1916
1917/**
1918 * Gets a CPUID leaf.
1919 *
1920 * @param pVCpu Pointer to the VMCPU.
1921 * @param iLeaf The CPUID leaf to get.
1922 * @param pEax Where to store the EAX value.
1923 * @param pEbx Where to store the EBX value.
1924 * @param pEcx Where to store the ECX value.
1925 * @param pEdx Where to store the EDX value.
1926 */
1927VMMDECL(void) CPUMGetGuestCpuId(PVMCPU pVCpu, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)
1928{
1929 PVM pVM = pVCpu->CTX_SUFF(pVM);
1930
1931 PCCPUMCPUID pCpuId;
1932 if (iLeaf < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd))
1933 pCpuId = &pVM->cpum.s.aGuestCpuIdStd[iLeaf];
1934 else if (iLeaf - UINT32_C(0x80000000) < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdExt))
1935 pCpuId = &pVM->cpum.s.aGuestCpuIdExt[iLeaf - UINT32_C(0x80000000)];
1936 else if ( iLeaf - UINT32_C(0x40000000) < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdHyper)
1937 && (pVCpu->CTX_SUFF(pVM)->cpum.s.aGuestCpuIdStd[1].ecx & X86_CPUID_FEATURE_ECX_HVP))
1938 pCpuId = &pVM->cpum.s.aGuestCpuIdHyper[iLeaf - UINT32_C(0x40000000)]; /* Only report if HVP bit set. */
1939 else if (iLeaf - UINT32_C(0xc0000000) < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdCentaur))
1940 pCpuId = &pVM->cpum.s.aGuestCpuIdCentaur[iLeaf - UINT32_C(0xc0000000)];
1941 else
1942 pCpuId = &pVM->cpum.s.GuestCpuIdDef;
1943
1944 uint32_t cCurrentCacheIndex = *pEcx;
1945
1946 *pEax = pCpuId->eax;
1947 *pEbx = pCpuId->ebx;
1948 *pEcx = pCpuId->ecx;
1949 *pEdx = pCpuId->edx;
1950
1951 if ( iLeaf == 1)
1952 {
1953 /* Bits 31-24: Initial APIC ID */
1954 Assert(pVCpu->idCpu <= 255);
1955 *pEbx |= (pVCpu->idCpu << 24);
1956 }
1957
1958 if ( iLeaf == 4
1959 && cCurrentCacheIndex < 3
1960 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_INTEL)
1961 {
1962 uint32_t type, level, sharing, linesize,
1963 partitions, associativity, sets, cores;
1964
1965 /* For type: 1 - data cache, 2 - i-cache, 3 - unified */
1966 partitions = 1;
1967 /* Those are only to shut up compiler, as they will always
1968 get overwritten, and compiler should be able to figure that out */
1969 sets = associativity = sharing = level = 1;
1970 cores = pVM->cCpus > 32 ? 32 : pVM->cCpus;
1971 switch (cCurrentCacheIndex)
1972 {
1973 case 0:
1974 type = 1;
1975 level = 1;
1976 sharing = 1;
1977 linesize = 64;
1978 associativity = 8;
1979 sets = 64;
1980 break;
1981 case 1:
1982 level = 1;
1983 type = 2;
1984 sharing = 1;
1985 linesize = 64;
1986 associativity = 8;
1987 sets = 64;
1988 break;
1989 default: /* shut up gcc.*/
1990 AssertFailed();
1991 case 2:
1992 level = 2;
1993 type = 3;
1994 sharing = cores; /* our L2 cache is modelled as shared between all cores */
1995 linesize = 64;
1996 associativity = 24;
1997 sets = 4096;
1998 break;
1999 }
2000
2001 NOREF(type);
2002 *pEax |= ((cores - 1) << 26) |
2003 ((sharing - 1) << 14) |
2004 (level << 5) |
2005 1;
2006 *pEbx = (linesize - 1) |
2007 ((partitions - 1) << 12) |
2008 ((associativity - 1) << 22); /* -1 encoding */
2009 *pEcx = sets - 1;
2010 }
2011
2012 Log2(("CPUMGetGuestCpuId: iLeaf=%#010x %RX32 %RX32 %RX32 %RX32\n", iLeaf, *pEax, *pEbx, *pEcx, *pEdx));
2013}
2014
2015/**
2016 * Gets a number of standard CPUID leafs.
2017 *
2018 * @returns Number of leafs.
2019 * @param pVM Pointer to the VM.
2020 * @remark Intended for PATM.
2021 */
2022VMMDECL(uint32_t) CPUMGetGuestCpuIdStdMax(PVM pVM)
2023{
2024 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd);
2025}
2026
2027
2028/**
2029 * Gets a number of extended CPUID leafs.
2030 *
2031 * @returns Number of leafs.
2032 * @param pVM Pointer to the VM.
2033 * @remark Intended for PATM.
2034 */
2035VMMDECL(uint32_t) CPUMGetGuestCpuIdExtMax(PVM pVM)
2036{
2037 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdExt);
2038}
2039
2040
2041/**
2042 * Gets a number of centaur CPUID leafs.
2043 *
2044 * @returns Number of leafs.
2045 * @param pVM Pointer to the VM.
2046 * @remark Intended for PATM.
2047 */
2048VMMDECL(uint32_t) CPUMGetGuestCpuIdCentaurMax(PVM pVM)
2049{
2050 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdCentaur);
2051}
2052
2053
2054/**
2055 * Sets a CPUID feature bit.
2056 *
2057 * @param pVM Pointer to the VM.
2058 * @param enmFeature The feature to set.
2059 */
2060VMMDECL(void) CPUMSetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
2061{
2062 PCPUMCPUIDLEAF pLeaf;
2063
2064 switch (enmFeature)
2065 {
2066 /*
2067 * Set the APIC bit in both feature masks.
2068 */
2069 case CPUMCPUIDFEATURE_APIC:
2070 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2071 if (pLeaf)
2072 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_APIC;
2073
2074 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2075 if ( pLeaf
2076 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2077 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_AMD_FEATURE_EDX_APIC;
2078
2079 pVM->cpum.s.GuestFeatures.fApic = 1;
2080 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled APIC\n"));
2081 break;
2082
2083 /*
2084 * Set the x2APIC bit in the standard feature mask.
2085 */
2086 case CPUMCPUIDFEATURE_X2APIC:
2087 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2088 if (pLeaf)
2089 pVM->cpum.s.aGuestCpuIdStd[1].ecx = pLeaf->uEcx |= X86_CPUID_FEATURE_ECX_X2APIC;
2090 pVM->cpum.s.GuestFeatures.fX2Apic = 1;
2091 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled x2APIC\n"));
2092 break;
2093
2094 /*
2095 * Set the sysenter/sysexit bit in the standard feature mask.
2096 * Assumes the caller knows what it's doing! (host must support these)
2097 */
2098 case CPUMCPUIDFEATURE_SEP:
2099 if (!pVM->cpum.s.HostFeatures.fSysEnter)
2100 {
2101 AssertMsgFailed(("ERROR: Can't turn on SEP when the host doesn't support it!!\n"));
2102 return;
2103 }
2104
2105 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2106 if (pLeaf)
2107 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_SEP;
2108 pVM->cpum.s.GuestFeatures.fSysEnter = 1;
2109 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled SYSENTER/EXIT\n"));
2110 break;
2111
2112 /*
2113 * Set the syscall/sysret bit in the extended feature mask.
2114 * Assumes the caller knows what it's doing! (host must support these)
2115 */
2116 case CPUMCPUIDFEATURE_SYSCALL:
2117 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2118 if ( !pLeaf
2119 || !pVM->cpum.s.HostFeatures.fSysCall)
2120 {
2121#if HC_ARCH_BITS == 32
2122 /* X86_CPUID_EXT_FEATURE_EDX_SYSCALL not set it seems in 32-bit
2123 mode by Intel, even when the cpu is capable of doing so in
2124 64-bit mode. Long mode requires syscall support. */
2125 if (!pVM->cpum.s.HostFeatures.fLongMode)
2126#endif
2127 {
2128 LogRel(("CPUM: WARNING! Can't turn on SYSCALL/SYSRET when the host doesn't support it!\n"));
2129 return;
2130 }
2131 }
2132
2133 /* Valid for both Intel and AMD CPUs, although only in 64 bits mode for Intel. */
2134 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_SYSCALL;
2135 pVM->cpum.s.GuestFeatures.fSysCall = 1;
2136 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled SYSCALL/RET\n"));
2137 break;
2138
2139 /*
2140 * Set the PAE bit in both feature masks.
2141 * Assumes the caller knows what it's doing! (host must support these)
2142 */
2143 case CPUMCPUIDFEATURE_PAE:
2144 if (!pVM->cpum.s.HostFeatures.fPae)
2145 {
2146 LogRel(("CPUM: WARNING! Can't turn on PAE when the host doesn't support it!\n"));
2147 return;
2148 }
2149
2150 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2151 if (pLeaf)
2152 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_PAE;
2153
2154 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2155 if ( pLeaf
2156 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2157 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_AMD_FEATURE_EDX_PAE;
2158
2159 pVM->cpum.s.GuestFeatures.fPae = 1;
2160 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled PAE\n"));
2161 break;
2162
2163 /*
2164 * Set the LONG MODE bit in the extended feature mask.
2165 * Assumes the caller knows what it's doing! (host must support these)
2166 */
2167 case CPUMCPUIDFEATURE_LONG_MODE:
2168 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2169 if ( !pLeaf
2170 || !pVM->cpum.s.HostFeatures.fLongMode)
2171 {
2172 LogRel(("CPUM: WARNING! Can't turn on LONG MODE when the host doesn't support it!\n"));
2173 return;
2174 }
2175
2176 /* Valid for both Intel and AMD. */
2177 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_LONG_MODE;
2178 pVM->cpum.s.GuestFeatures.fLongMode = 1;
2179 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled LONG MODE\n"));
2180 break;
2181
2182 /*
2183 * Set the NX/XD bit in the extended feature mask.
2184 * Assumes the caller knows what it's doing! (host must support these)
2185 */
2186 case CPUMCPUIDFEATURE_NX:
2187 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2188 if ( !pLeaf
2189 || !pVM->cpum.s.HostFeatures.fNoExecute)
2190 {
2191 LogRel(("CPUM: WARNING! Can't turn on NX/XD when the host doesn't support it!\n"));
2192 return;
2193 }
2194
2195 /* Valid for both Intel and AMD. */
2196 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_NX;
2197 pVM->cpum.s.GuestFeatures.fNoExecute = 1;
2198 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled NX\n"));
2199 break;
2200
2201
2202 /*
2203 * Set the LAHF/SAHF support in 64-bit mode.
2204 * Assumes the caller knows what it's doing! (host must support this)
2205 */
2206 case CPUMCPUIDFEATURE_LAHF:
2207 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2208 if ( !pLeaf
2209 || !pVM->cpum.s.HostFeatures.fLahfSahf)
2210 {
2211 LogRel(("CPUM: WARNING! Can't turn on LAHF/SAHF when the host doesn't support it!\n"));
2212 return;
2213 }
2214
2215 /* Valid for both Intel and AMD. */
2216 pVM->cpum.s.aGuestCpuIdExt[1].ecx = pLeaf->uEcx |= X86_CPUID_EXT_FEATURE_ECX_LAHF_SAHF;
2217 pVM->cpum.s.GuestFeatures.fLahfSahf = 1;
2218 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled LAHF/SAHF\n"));
2219 break;
2220
2221 /*
2222 * Set the page attribute table bit. This is alternative page level
2223 * cache control that doesn't much matter when everything is
2224 * virtualized, though it may when passing thru device memory.
2225 */
2226 case CPUMCPUIDFEATURE_PAT:
2227 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2228 if (pLeaf)
2229 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_PAT;
2230
2231 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2232 if ( pLeaf
2233 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2234 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_AMD_FEATURE_EDX_PAT;
2235
2236 pVM->cpum.s.GuestFeatures.fPat = 1;
2237 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled PAT\n"));
2238 break;
2239
2240 /*
2241 * Set the RDTSCP support bit.
2242 * Assumes the caller knows what it's doing! (host must support this)
2243 */
2244 case CPUMCPUIDFEATURE_RDTSCP:
2245 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2246 if ( !pLeaf
2247 || !pVM->cpum.s.HostFeatures.fRdTscP
2248 || pVM->cpum.s.u8PortableCpuIdLevel > 0)
2249 {
2250 if (!pVM->cpum.s.u8PortableCpuIdLevel)
2251 LogRel(("CPUM: WARNING! Can't turn on RDTSCP when the host doesn't support it!\n"));
2252 return;
2253 }
2254
2255 /* Valid for both Intel and AMD. */
2256 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_RDTSCP;
2257 pVM->cpum.s.HostFeatures.fRdTscP = 1;
2258 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled RDTSCP.\n"));
2259 break;
2260
2261 /*
2262 * Set the Hypervisor Present bit in the standard feature mask.
2263 */
2264 case CPUMCPUIDFEATURE_HVP:
2265 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2266 if (pLeaf)
2267 pVM->cpum.s.aGuestCpuIdStd[1].ecx = pLeaf->uEcx |= X86_CPUID_FEATURE_ECX_HVP;
2268 pVM->cpum.s.GuestFeatures.fHypervisorPresent = 1;
2269 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled Hypervisor Present bit\n"));
2270 break;
2271
2272 default:
2273 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
2274 break;
2275 }
2276
2277 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2278 {
2279 PVMCPU pVCpu = &pVM->aCpus[i];
2280 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CPUID;
2281 }
2282}
2283
2284
2285/**
2286 * Queries a CPUID feature bit.
2287 *
2288 * @returns boolean for feature presence
2289 * @param pVM Pointer to the VM.
2290 * @param enmFeature The feature to query.
2291 */
2292VMMDECL(bool) CPUMGetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
2293{
2294 switch (enmFeature)
2295 {
2296 case CPUMCPUIDFEATURE_APIC: return pVM->cpum.s.GuestFeatures.fApic;
2297 case CPUMCPUIDFEATURE_X2APIC: return pVM->cpum.s.GuestFeatures.fX2Apic;
2298 case CPUMCPUIDFEATURE_SYSCALL: return pVM->cpum.s.GuestFeatures.fSysCall;
2299 case CPUMCPUIDFEATURE_SEP: return pVM->cpum.s.GuestFeatures.fSysEnter;
2300 case CPUMCPUIDFEATURE_PAE: return pVM->cpum.s.GuestFeatures.fPae;
2301 case CPUMCPUIDFEATURE_NX: return pVM->cpum.s.GuestFeatures.fNoExecute;
2302 case CPUMCPUIDFEATURE_LAHF: return pVM->cpum.s.GuestFeatures.fLahfSahf;
2303 case CPUMCPUIDFEATURE_LONG_MODE: return pVM->cpum.s.GuestFeatures.fLongMode;
2304 case CPUMCPUIDFEATURE_PAT: return pVM->cpum.s.GuestFeatures.fPat;
2305 case CPUMCPUIDFEATURE_RDTSCP: return pVM->cpum.s.GuestFeatures.fRdTscP;
2306 case CPUMCPUIDFEATURE_HVP: return pVM->cpum.s.GuestFeatures.fHypervisorPresent;
2307
2308 case CPUMCPUIDFEATURE_INVALID:
2309 case CPUMCPUIDFEATURE_32BIT_HACK:
2310 break;
2311 }
2312 AssertFailed();
2313 return false;
2314}
2315
2316
2317/**
2318 * Clears a CPUID feature bit.
2319 *
2320 * @param pVM Pointer to the VM.
2321 * @param enmFeature The feature to clear.
2322 */
2323VMMDECL(void) CPUMClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
2324{
2325 PCPUMCPUIDLEAF pLeaf;
2326 switch (enmFeature)
2327 {
2328 case CPUMCPUIDFEATURE_APIC:
2329 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2330 if (pLeaf)
2331 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx &= ~X86_CPUID_FEATURE_EDX_APIC;
2332
2333 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2334 if ( pLeaf
2335 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2336 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx &= ~X86_CPUID_AMD_FEATURE_EDX_APIC;
2337
2338 pVM->cpum.s.GuestFeatures.fApic = 0;
2339 Log(("CPUM: ClearGuestCpuIdFeature: Disabled APIC\n"));
2340 break;
2341
2342 case CPUMCPUIDFEATURE_X2APIC:
2343 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2344 if (pLeaf)
2345 pVM->cpum.s.aGuestCpuIdStd[1].ecx = pLeaf->uEcx &= ~X86_CPUID_FEATURE_ECX_X2APIC;
2346 pVM->cpum.s.GuestFeatures.fX2Apic = 0;
2347 Log(("CPUM: ClearGuestCpuIdFeature: Disabled x2APIC\n"));
2348 break;
2349
2350 case CPUMCPUIDFEATURE_PAE:
2351 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2352 if (pLeaf)
2353 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx &= ~X86_CPUID_FEATURE_EDX_PAE;
2354
2355 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2356 if ( pLeaf
2357 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2358 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx &= ~X86_CPUID_AMD_FEATURE_EDX_PAE;
2359
2360 pVM->cpum.s.GuestFeatures.fPae = 0;
2361 Log(("CPUM: ClearGuestCpuIdFeature: Disabled PAE!\n"));
2362 break;
2363
2364 case CPUMCPUIDFEATURE_PAT:
2365 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2366 if (pLeaf)
2367 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx &= ~X86_CPUID_FEATURE_EDX_PAT;
2368
2369 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2370 if ( pLeaf
2371 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2372 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx &= ~X86_CPUID_AMD_FEATURE_EDX_PAT;
2373
2374 pVM->cpum.s.GuestFeatures.fPat = 0;
2375 Log(("CPUM: ClearGuestCpuIdFeature: Disabled PAT!\n"));
2376 break;
2377
2378 case CPUMCPUIDFEATURE_LONG_MODE:
2379 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2380 if (pLeaf)
2381 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx &= ~X86_CPUID_EXT_FEATURE_EDX_LONG_MODE;
2382 pVM->cpum.s.GuestFeatures.fLongMode = 0;
2383 break;
2384
2385 case CPUMCPUIDFEATURE_LAHF:
2386 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2387 if (pLeaf)
2388 pVM->cpum.s.aGuestCpuIdExt[1].ecx = pLeaf->uEcx &= ~X86_CPUID_EXT_FEATURE_ECX_LAHF_SAHF;
2389 pVM->cpum.s.GuestFeatures.fLahfSahf = 0;
2390 break;
2391
2392 case CPUMCPUIDFEATURE_RDTSCP:
2393 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2394 if (pLeaf)
2395 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx &= ~X86_CPUID_EXT_FEATURE_EDX_RDTSCP;
2396 pVM->cpum.s.GuestFeatures.fRdTscP = 0;
2397 Log(("CPUM: ClearGuestCpuIdFeature: Disabled RDTSCP!\n"));
2398 break;
2399
2400 case CPUMCPUIDFEATURE_HVP:
2401 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2402 if (pLeaf)
2403 pVM->cpum.s.aGuestCpuIdStd[1].ecx = pLeaf->uEcx &= ~X86_CPUID_FEATURE_ECX_HVP;
2404 pVM->cpum.s.GuestFeatures.fHypervisorPresent = 0;
2405 break;
2406
2407 default:
2408 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
2409 break;
2410 }
2411
2412 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2413 {
2414 PVMCPU pVCpu = &pVM->aCpus[i];
2415 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CPUID;
2416 }
2417}
2418
2419
2420/**
2421 * Gets the host CPU vendor.
2422 *
2423 * @returns CPU vendor.
2424 * @param pVM Pointer to the VM.
2425 */
2426VMMDECL(CPUMCPUVENDOR) CPUMGetHostCpuVendor(PVM pVM)
2427{
2428 return (CPUMCPUVENDOR)pVM->cpum.s.HostFeatures.enmCpuVendor;
2429}
2430
2431
2432/**
2433 * Gets the CPU vendor.
2434 *
2435 * @returns CPU vendor.
2436 * @param pVM Pointer to the VM.
2437 */
2438VMMDECL(CPUMCPUVENDOR) CPUMGetGuestCpuVendor(PVM pVM)
2439{
2440 return (CPUMCPUVENDOR)pVM->cpum.s.GuestFeatures.enmCpuVendor;
2441}
2442
2443
2444VMMDECL(int) CPUMSetGuestDR0(PVMCPU pVCpu, uint64_t uDr0)
2445{
2446 pVCpu->cpum.s.Guest.dr[0] = uDr0;
2447 return CPUMRecalcHyperDRx(pVCpu, 0, false);
2448}
2449
2450
2451VMMDECL(int) CPUMSetGuestDR1(PVMCPU pVCpu, uint64_t uDr1)
2452{
2453 pVCpu->cpum.s.Guest.dr[1] = uDr1;
2454 return CPUMRecalcHyperDRx(pVCpu, 1, false);
2455}
2456
2457
2458VMMDECL(int) CPUMSetGuestDR2(PVMCPU pVCpu, uint64_t uDr2)
2459{
2460 pVCpu->cpum.s.Guest.dr[2] = uDr2;
2461 return CPUMRecalcHyperDRx(pVCpu, 2, false);
2462}
2463
2464
2465VMMDECL(int) CPUMSetGuestDR3(PVMCPU pVCpu, uint64_t uDr3)
2466{
2467 pVCpu->cpum.s.Guest.dr[3] = uDr3;
2468 return CPUMRecalcHyperDRx(pVCpu, 3, false);
2469}
2470
2471
2472VMMDECL(int) CPUMSetGuestDR6(PVMCPU pVCpu, uint64_t uDr6)
2473{
2474 pVCpu->cpum.s.Guest.dr[6] = uDr6;
2475 return VINF_SUCCESS; /* No need to recalc. */
2476}
2477
2478
2479VMMDECL(int) CPUMSetGuestDR7(PVMCPU pVCpu, uint64_t uDr7)
2480{
2481 pVCpu->cpum.s.Guest.dr[7] = uDr7;
2482 return CPUMRecalcHyperDRx(pVCpu, 7, false);
2483}
2484
2485
2486VMMDECL(int) CPUMSetGuestDRx(PVMCPU pVCpu, uint32_t iReg, uint64_t Value)
2487{
2488 AssertReturn(iReg <= DISDREG_DR7, VERR_INVALID_PARAMETER);
2489 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
2490 if (iReg == 4 || iReg == 5)
2491 iReg += 2;
2492 pVCpu->cpum.s.Guest.dr[iReg] = Value;
2493 return CPUMRecalcHyperDRx(pVCpu, iReg, false);
2494}
2495
2496
2497/**
2498 * Recalculates the hypervisor DRx register values based on current guest
2499 * registers and DBGF breakpoints, updating changed registers depending on the
2500 * context.
2501 *
2502 * This is called whenever a guest DRx register is modified (any context) and
2503 * when DBGF sets a hardware breakpoint (ring-3 only, rendezvous).
2504 *
2505 * In raw-mode context this function will reload any (hyper) DRx registers which
2506 * comes out with a different value. It may also have to save the host debug
2507 * registers if that haven't been done already. In this context though, we'll
2508 * be intercepting and emulating all DRx accesses, so the hypervisor DRx values
2509 * are only important when breakpoints are actually enabled.
2510 *
2511 * In ring-0 (HM) context DR0-3 will be relocated by us, while DR7 will be
2512 * reloaded by the HM code if it changes. Further more, we will only use the
2513 * combined register set when the VBox debugger is actually using hardware BPs,
2514 * when it isn't we'll keep the guest DR0-3 + (maybe) DR6 loaded (DR6 doesn't
2515 * concern us here).
2516 *
2517 * In ring-3 we won't be loading anything, so well calculate hypervisor values
2518 * all the time.
2519 *
2520 * @returns VINF_SUCCESS.
2521 * @param pVCpu Pointer to the VMCPU.
2522 * @param iGstReg The guest debug register number that was modified.
2523 * UINT8_MAX if not guest register.
2524 * @param fForceHyper Used in HM to force hyper registers because of single
2525 * stepping.
2526 */
2527VMMDECL(int) CPUMRecalcHyperDRx(PVMCPU pVCpu, uint8_t iGstReg, bool fForceHyper)
2528{
2529 PVM pVM = pVCpu->CTX_SUFF(pVM);
2530
2531 /*
2532 * Compare the DR7s first.
2533 *
2534 * We only care about the enabled flags. GD is virtualized when we
2535 * dispatch the #DB, we never enable it. The DBGF DR7 value is will
2536 * always have the LE and GE bits set, so no need to check and disable
2537 * stuff if they're cleared like we have to for the guest DR7.
2538 */
2539 RTGCUINTREG uGstDr7 = CPUMGetGuestDR7(pVCpu);
2540 if (!(uGstDr7 & (X86_DR7_LE | X86_DR7_GE)))
2541 uGstDr7 = 0;
2542 else if (!(uGstDr7 & X86_DR7_LE))
2543 uGstDr7 &= ~X86_DR7_LE_ALL;
2544 else if (!(uGstDr7 & X86_DR7_GE))
2545 uGstDr7 &= ~X86_DR7_GE_ALL;
2546
2547 const RTGCUINTREG uDbgfDr7 = DBGFBpGetDR7(pVM);
2548
2549#ifdef IN_RING0
2550 if (!fForceHyper && (pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HYPER))
2551 fForceHyper = true;
2552#endif
2553 if (( HMIsEnabled(pVCpu->CTX_SUFF(pVM)) && !fForceHyper ? uDbgfDr7 : (uGstDr7 | uDbgfDr7)) & X86_DR7_ENABLED_MASK)
2554 {
2555 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
2556#ifdef IN_RC
2557 bool const fHmEnabled = false;
2558#elif defined(IN_RING3)
2559 bool const fHmEnabled = HMIsEnabled(pVM);
2560#endif
2561
2562 /*
2563 * Ok, something is enabled. Recalc each of the breakpoints, taking
2564 * the VM debugger ones of the guest ones. In raw-mode context we will
2565 * not allow breakpoints with values inside the hypervisor area.
2566 */
2567 RTGCUINTREG uNewDr7 = X86_DR7_GE | X86_DR7_LE | X86_DR7_RA1_MASK;
2568
2569 /* bp 0 */
2570 RTGCUINTREG uNewDr0;
2571 if (uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0))
2572 {
2573 uNewDr7 |= uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
2574 uNewDr0 = DBGFBpGetDR0(pVM);
2575 }
2576 else if (uGstDr7 & (X86_DR7_L0 | X86_DR7_G0))
2577 {
2578 uNewDr0 = CPUMGetGuestDR0(pVCpu);
2579#ifndef IN_RING0
2580 if (fHmEnabled && MMHyperIsInsideArea(pVM, uNewDr0))
2581 uNewDr0 = 0;
2582 else
2583#endif
2584 uNewDr7 |= uGstDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
2585 }
2586 else
2587 uNewDr0 = 0;
2588
2589 /* bp 1 */
2590 RTGCUINTREG uNewDr1;
2591 if (uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1))
2592 {
2593 uNewDr7 |= uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
2594 uNewDr1 = DBGFBpGetDR1(pVM);
2595 }
2596 else if (uGstDr7 & (X86_DR7_L1 | X86_DR7_G1))
2597 {
2598 uNewDr1 = CPUMGetGuestDR1(pVCpu);
2599#ifndef IN_RING0
2600 if (fHmEnabled && MMHyperIsInsideArea(pVM, uNewDr1))
2601 uNewDr1 = 0;
2602 else
2603#endif
2604 uNewDr7 |= uGstDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
2605 }
2606 else
2607 uNewDr1 = 0;
2608
2609 /* bp 2 */
2610 RTGCUINTREG uNewDr2;
2611 if (uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2))
2612 {
2613 uNewDr7 |= uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
2614 uNewDr2 = DBGFBpGetDR2(pVM);
2615 }
2616 else if (uGstDr7 & (X86_DR7_L2 | X86_DR7_G2))
2617 {
2618 uNewDr2 = CPUMGetGuestDR2(pVCpu);
2619#ifndef IN_RING0
2620 if (fHmEnabled && MMHyperIsInsideArea(pVM, uNewDr2))
2621 uNewDr2 = 0;
2622 else
2623#endif
2624 uNewDr7 |= uGstDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
2625 }
2626 else
2627 uNewDr2 = 0;
2628
2629 /* bp 3 */
2630 RTGCUINTREG uNewDr3;
2631 if (uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3))
2632 {
2633 uNewDr7 |= uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
2634 uNewDr3 = DBGFBpGetDR3(pVM);
2635 }
2636 else if (uGstDr7 & (X86_DR7_L3 | X86_DR7_G3))
2637 {
2638 uNewDr3 = CPUMGetGuestDR3(pVCpu);
2639#ifndef IN_RING0
2640 if (fHmEnabled && MMHyperIsInsideArea(pVM, uNewDr3))
2641 uNewDr3 = 0;
2642 else
2643#endif
2644 uNewDr7 |= uGstDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
2645 }
2646 else
2647 uNewDr3 = 0;
2648
2649 /*
2650 * Apply the updates.
2651 */
2652#ifdef IN_RC
2653 /* Make sure to save host registers first. */
2654 if (!(pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HOST))
2655 {
2656 if (!(pVCpu->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS_HOST))
2657 {
2658 pVCpu->cpum.s.Host.dr6 = ASMGetDR6();
2659 pVCpu->cpum.s.Host.dr7 = ASMGetDR7();
2660 }
2661 pVCpu->cpum.s.Host.dr0 = ASMGetDR0();
2662 pVCpu->cpum.s.Host.dr1 = ASMGetDR1();
2663 pVCpu->cpum.s.Host.dr2 = ASMGetDR2();
2664 pVCpu->cpum.s.Host.dr3 = ASMGetDR3();
2665 pVCpu->cpum.s.fUseFlags |= CPUM_USED_DEBUG_REGS_HOST | CPUM_USE_DEBUG_REGS_HYPER | CPUM_USED_DEBUG_REGS_HYPER;
2666
2667 /* We haven't loaded any hyper DRxes yet, so we'll have to load them all now. */
2668 pVCpu->cpum.s.Hyper.dr[0] = uNewDr0;
2669 ASMSetDR0(uNewDr0);
2670 pVCpu->cpum.s.Hyper.dr[1] = uNewDr1;
2671 ASMSetDR1(uNewDr1);
2672 pVCpu->cpum.s.Hyper.dr[2] = uNewDr2;
2673 ASMSetDR2(uNewDr2);
2674 pVCpu->cpum.s.Hyper.dr[3] = uNewDr3;
2675 ASMSetDR3(uNewDr3);
2676 ASMSetDR6(X86_DR6_INIT_VAL);
2677 pVCpu->cpum.s.Hyper.dr[7] = uNewDr7;
2678 ASMSetDR7(uNewDr7);
2679 }
2680 else
2681#endif
2682 {
2683 pVCpu->cpum.s.fUseFlags |= CPUM_USE_DEBUG_REGS_HYPER;
2684 if (uNewDr3 != pVCpu->cpum.s.Hyper.dr[3])
2685 CPUMSetHyperDR3(pVCpu, uNewDr3);
2686 if (uNewDr2 != pVCpu->cpum.s.Hyper.dr[2])
2687 CPUMSetHyperDR2(pVCpu, uNewDr2);
2688 if (uNewDr1 != pVCpu->cpum.s.Hyper.dr[1])
2689 CPUMSetHyperDR1(pVCpu, uNewDr1);
2690 if (uNewDr0 != pVCpu->cpum.s.Hyper.dr[0])
2691 CPUMSetHyperDR0(pVCpu, uNewDr0);
2692 if (uNewDr7 != pVCpu->cpum.s.Hyper.dr[7])
2693 CPUMSetHyperDR7(pVCpu, uNewDr7);
2694 }
2695 }
2696#ifdef IN_RING0
2697 else if (CPUMIsGuestDebugStateActive(pVCpu))
2698 {
2699 /*
2700 * Reload the register that was modified. Normally this won't happen
2701 * as we won't intercept DRx writes when not having the hyper debug
2702 * state loaded, but in case we do for some reason we'll simply deal
2703 * with it.
2704 */
2705 switch (iGstReg)
2706 {
2707 case 0: ASMSetDR0(CPUMGetGuestDR0(pVCpu)); break;
2708 case 1: ASMSetDR1(CPUMGetGuestDR1(pVCpu)); break;
2709 case 2: ASMSetDR2(CPUMGetGuestDR2(pVCpu)); break;
2710 case 3: ASMSetDR3(CPUMGetGuestDR3(pVCpu)); break;
2711 default:
2712 AssertReturn(iGstReg != UINT8_MAX, VERR_INTERNAL_ERROR_3);
2713 }
2714 }
2715#endif
2716 else
2717 {
2718 /*
2719 * No active debug state any more. In raw-mode this means we have to
2720 * make sure DR7 has everything disabled now, if we armed it already.
2721 * In ring-0 we might end up here when just single stepping.
2722 */
2723#if defined(IN_RC) || defined(IN_RING0)
2724 if (pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HYPER)
2725 {
2726# ifdef IN_RC
2727 ASMSetDR7(X86_DR7_INIT_VAL);
2728# endif
2729 if (pVCpu->cpum.s.Hyper.dr[0])
2730 ASMSetDR0(0);
2731 if (pVCpu->cpum.s.Hyper.dr[1])
2732 ASMSetDR1(0);
2733 if (pVCpu->cpum.s.Hyper.dr[2])
2734 ASMSetDR2(0);
2735 if (pVCpu->cpum.s.Hyper.dr[3])
2736 ASMSetDR3(0);
2737 pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_DEBUG_REGS_HYPER;
2738 }
2739#endif
2740 pVCpu->cpum.s.fUseFlags &= ~CPUM_USE_DEBUG_REGS_HYPER;
2741
2742 /* Clear all the registers. */
2743 pVCpu->cpum.s.Hyper.dr[7] = X86_DR7_RA1_MASK;
2744 pVCpu->cpum.s.Hyper.dr[3] = 0;
2745 pVCpu->cpum.s.Hyper.dr[2] = 0;
2746 pVCpu->cpum.s.Hyper.dr[1] = 0;
2747 pVCpu->cpum.s.Hyper.dr[0] = 0;
2748
2749 }
2750 Log2(("CPUMRecalcHyperDRx: fUseFlags=%#x %RGr %RGr %RGr %RGr %RGr %RGr\n",
2751 pVCpu->cpum.s.fUseFlags, pVCpu->cpum.s.Hyper.dr[0], pVCpu->cpum.s.Hyper.dr[1],
2752 pVCpu->cpum.s.Hyper.dr[2], pVCpu->cpum.s.Hyper.dr[3], pVCpu->cpum.s.Hyper.dr[6],
2753 pVCpu->cpum.s.Hyper.dr[7]));
2754
2755 return VINF_SUCCESS;
2756}
2757
2758
2759/**
2760 * Tests if the guest has No-Execute Page Protection Enabled (NXE).
2761 *
2762 * @returns true if in real mode, otherwise false.
2763 * @param pVCpu Pointer to the VMCPU.
2764 */
2765VMMDECL(bool) CPUMIsGuestNXEnabled(PVMCPU pVCpu)
2766{
2767 return !!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_NXE);
2768}
2769
2770
2771/**
2772 * Tests if the guest has the Page Size Extension enabled (PSE).
2773 *
2774 * @returns true if in real mode, otherwise false.
2775 * @param pVCpu Pointer to the VMCPU.
2776 */
2777VMMDECL(bool) CPUMIsGuestPageSizeExtEnabled(PVMCPU pVCpu)
2778{
2779 /* PAE or AMD64 implies support for big pages regardless of CR4.PSE */
2780 return !!(pVCpu->cpum.s.Guest.cr4 & (X86_CR4_PSE | X86_CR4_PAE));
2781}
2782
2783
2784/**
2785 * Tests if the guest has the paging enabled (PG).
2786 *
2787 * @returns true if in real mode, otherwise false.
2788 * @param pVCpu Pointer to the VMCPU.
2789 */
2790VMMDECL(bool) CPUMIsGuestPagingEnabled(PVMCPU pVCpu)
2791{
2792 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PG);
2793}
2794
2795
2796/**
2797 * Tests if the guest has the paging enabled (PG).
2798 *
2799 * @returns true if in real mode, otherwise false.
2800 * @param pVCpu Pointer to the VMCPU.
2801 */
2802VMMDECL(bool) CPUMIsGuestR0WriteProtEnabled(PVMCPU pVCpu)
2803{
2804 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_WP);
2805}
2806
2807
2808/**
2809 * Tests if the guest is running in real mode or not.
2810 *
2811 * @returns true if in real mode, otherwise false.
2812 * @param pVCpu Pointer to the VMCPU.
2813 */
2814VMMDECL(bool) CPUMIsGuestInRealMode(PVMCPU pVCpu)
2815{
2816 return !(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE);
2817}
2818
2819
2820/**
2821 * Tests if the guest is running in real or virtual 8086 mode.
2822 *
2823 * @returns @c true if it is, @c false if not.
2824 * @param pVCpu Pointer to the VMCPU.
2825 */
2826VMMDECL(bool) CPUMIsGuestInRealOrV86Mode(PVMCPU pVCpu)
2827{
2828 return !(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE)
2829 || pVCpu->cpum.s.Guest.eflags.Bits.u1VM; /** @todo verify that this cannot be set in long mode. */
2830}
2831
2832
2833/**
2834 * Tests if the guest is running in protected or not.
2835 *
2836 * @returns true if in protected mode, otherwise false.
2837 * @param pVCpu Pointer to the VMCPU.
2838 */
2839VMMDECL(bool) CPUMIsGuestInProtectedMode(PVMCPU pVCpu)
2840{
2841 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE);
2842}
2843
2844
2845/**
2846 * Tests if the guest is running in paged protected or not.
2847 *
2848 * @returns true if in paged protected mode, otherwise false.
2849 * @param pVCpu Pointer to the VMCPU.
2850 */
2851VMMDECL(bool) CPUMIsGuestInPagedProtectedMode(PVMCPU pVCpu)
2852{
2853 return (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG);
2854}
2855
2856
2857/**
2858 * Tests if the guest is running in long mode or not.
2859 *
2860 * @returns true if in long mode, otherwise false.
2861 * @param pVCpu Pointer to the VMCPU.
2862 */
2863VMMDECL(bool) CPUMIsGuestInLongMode(PVMCPU pVCpu)
2864{
2865 return (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA) == MSR_K6_EFER_LMA;
2866}
2867
2868
2869/**
2870 * Tests if the guest is running in PAE mode or not.
2871 *
2872 * @returns true if in PAE mode, otherwise false.
2873 * @param pVCpu Pointer to the VMCPU.
2874 */
2875VMMDECL(bool) CPUMIsGuestInPAEMode(PVMCPU pVCpu)
2876{
2877 /* Intel mentions EFER.LMA and EFER.LME in different parts of their spec. We shall use EFER.LMA rather
2878 than EFER.LME as it reflects if the CPU has entered paging with EFER.LME set. */
2879 return (pVCpu->cpum.s.Guest.cr4 & X86_CR4_PAE)
2880 && (pVCpu->cpum.s.Guest.cr0 & X86_CR0_PG)
2881 && !(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA);
2882}
2883
2884
2885/**
2886 * Tests if the guest is running in 64 bits mode or not.
2887 *
2888 * @returns true if in 64 bits protected mode, otherwise false.
2889 * @param pVCpu The current virtual CPU.
2890 */
2891VMMDECL(bool) CPUMIsGuestIn64BitCode(PVMCPU pVCpu)
2892{
2893 if (!CPUMIsGuestInLongMode(pVCpu))
2894 return false;
2895 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
2896 return pVCpu->cpum.s.Guest.cs.Attr.n.u1Long;
2897}
2898
2899
2900/**
2901 * Helper for CPUMIsGuestIn64BitCodeEx that handles lazy resolving of hidden CS
2902 * registers.
2903 *
2904 * @returns true if in 64 bits protected mode, otherwise false.
2905 * @param pCtx Pointer to the current guest CPU context.
2906 */
2907VMM_INT_DECL(bool) CPUMIsGuestIn64BitCodeSlow(PCPUMCTX pCtx)
2908{
2909 return CPUMIsGuestIn64BitCode(CPUM_GUEST_CTX_TO_VMCPU(pCtx));
2910}
2911
2912#ifdef VBOX_WITH_RAW_MODE_NOT_R0
2913
2914/**
2915 *
2916 * @returns @c true if we've entered raw-mode and selectors with RPL=1 are
2917 * really RPL=0, @c false if we've not (RPL=1 really is RPL=1).
2918 * @param pVCpu The current virtual CPU.
2919 */
2920VMM_INT_DECL(bool) CPUMIsGuestInRawMode(PVMCPU pVCpu)
2921{
2922 return pVCpu->cpum.s.fRawEntered;
2923}
2924
2925/**
2926 * Transforms the guest CPU state to raw-ring mode.
2927 *
2928 * This function will change the any of the cs and ss register with DPL=0 to DPL=1.
2929 *
2930 * @returns VBox status. (recompiler failure)
2931 * @param pVCpu Pointer to the VMCPU.
2932 * @param pCtxCore The context core (for trap usage).
2933 * @see @ref pg_raw
2934 */
2935VMM_INT_DECL(int) CPUMRawEnter(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
2936{
2937 PVM pVM = pVCpu->CTX_SUFF(pVM);
2938
2939 Assert(!pVCpu->cpum.s.fRawEntered);
2940 Assert(!pVCpu->cpum.s.fRemEntered);
2941 if (!pCtxCore)
2942 pCtxCore = CPUMCTX2CORE(&pVCpu->cpum.s.Guest);
2943
2944 /*
2945 * Are we in Ring-0?
2946 */
2947 if ( pCtxCore->ss.Sel
2948 && (pCtxCore->ss.Sel & X86_SEL_RPL) == 0
2949 && !pCtxCore->eflags.Bits.u1VM)
2950 {
2951 /*
2952 * Enter execution mode.
2953 */
2954 PATMRawEnter(pVM, pCtxCore);
2955
2956 /*
2957 * Set CPL to Ring-1.
2958 */
2959 pCtxCore->ss.Sel |= 1;
2960 if ( pCtxCore->cs.Sel
2961 && (pCtxCore->cs.Sel & X86_SEL_RPL) == 0)
2962 pCtxCore->cs.Sel |= 1;
2963 }
2964 else
2965 {
2966# ifdef VBOX_WITH_RAW_RING1
2967 if ( EMIsRawRing1Enabled(pVM)
2968 && !pCtxCore->eflags.Bits.u1VM
2969 && (pCtxCore->ss.Sel & X86_SEL_RPL) == 1)
2970 {
2971 /* Set CPL to Ring-2. */
2972 pCtxCore->ss.Sel = (pCtxCore->ss.Sel & ~X86_SEL_RPL) | 2;
2973 if (pCtxCore->cs.Sel && (pCtxCore->cs.Sel & X86_SEL_RPL) == 1)
2974 pCtxCore->cs.Sel = (pCtxCore->cs.Sel & ~X86_SEL_RPL) | 2;
2975 }
2976# else
2977 AssertMsg((pCtxCore->ss.Sel & X86_SEL_RPL) >= 2 || pCtxCore->eflags.Bits.u1VM,
2978 ("ring-1 code not supported\n"));
2979# endif
2980 /*
2981 * PATM takes care of IOPL and IF flags for Ring-3 and Ring-2 code as well.
2982 */
2983 PATMRawEnter(pVM, pCtxCore);
2984 }
2985
2986 /*
2987 * Assert sanity.
2988 */
2989 AssertMsg((pCtxCore->eflags.u32 & X86_EFL_IF), ("X86_EFL_IF is clear\n"));
2990 AssertReleaseMsg(pCtxCore->eflags.Bits.u2IOPL == 0,
2991 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss.Sel & X86_SEL_RPL));
2992 Assert((pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) == (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP));
2993
2994 pCtxCore->eflags.u32 |= X86_EFL_IF; /* paranoia */
2995
2996 pVCpu->cpum.s.fRawEntered = true;
2997 return VINF_SUCCESS;
2998}
2999
3000
3001/**
3002 * Transforms the guest CPU state from raw-ring mode to correct values.
3003 *
3004 * This function will change any selector registers with DPL=1 to DPL=0.
3005 *
3006 * @returns Adjusted rc.
3007 * @param pVCpu Pointer to the VMCPU.
3008 * @param rc Raw mode return code
3009 * @param pCtxCore The context core (for trap usage).
3010 * @see @ref pg_raw
3011 */
3012VMM_INT_DECL(int) CPUMRawLeave(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, int rc)
3013{
3014 PVM pVM = pVCpu->CTX_SUFF(pVM);
3015
3016 /*
3017 * Don't leave if we've already left (in RC).
3018 */
3019 Assert(!pVCpu->cpum.s.fRemEntered);
3020 if (!pVCpu->cpum.s.fRawEntered)
3021 return rc;
3022 pVCpu->cpum.s.fRawEntered = false;
3023
3024 PCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
3025 if (!pCtxCore)
3026 pCtxCore = CPUMCTX2CORE(pCtx);
3027 Assert(pCtxCore->eflags.Bits.u1VM || (pCtxCore->ss.Sel & X86_SEL_RPL));
3028 AssertMsg(pCtxCore->eflags.Bits.u1VM || pCtxCore->eflags.Bits.u2IOPL < (unsigned)(pCtxCore->ss.Sel & X86_SEL_RPL),
3029 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss.Sel & X86_SEL_RPL));
3030
3031 /*
3032 * Are we executing in raw ring-1?
3033 */
3034 if ( (pCtxCore->ss.Sel & X86_SEL_RPL) == 1
3035 && !pCtxCore->eflags.Bits.u1VM)
3036 {
3037 /*
3038 * Leave execution mode.
3039 */
3040 PATMRawLeave(pVM, pCtxCore, rc);
3041 /* Not quite sure if this is really required, but shouldn't harm (too much anyways). */
3042 /** @todo See what happens if we remove this. */
3043 if ((pCtxCore->ds.Sel & X86_SEL_RPL) == 1)
3044 pCtxCore->ds.Sel &= ~X86_SEL_RPL;
3045 if ((pCtxCore->es.Sel & X86_SEL_RPL) == 1)
3046 pCtxCore->es.Sel &= ~X86_SEL_RPL;
3047 if ((pCtxCore->fs.Sel & X86_SEL_RPL) == 1)
3048 pCtxCore->fs.Sel &= ~X86_SEL_RPL;
3049 if ((pCtxCore->gs.Sel & X86_SEL_RPL) == 1)
3050 pCtxCore->gs.Sel &= ~X86_SEL_RPL;
3051
3052 /*
3053 * Ring-1 selector => Ring-0.
3054 */
3055 pCtxCore->ss.Sel &= ~X86_SEL_RPL;
3056 if ((pCtxCore->cs.Sel & X86_SEL_RPL) == 1)
3057 pCtxCore->cs.Sel &= ~X86_SEL_RPL;
3058 }
3059 else
3060 {
3061 /*
3062 * PATM is taking care of the IOPL and IF flags for us.
3063 */
3064 PATMRawLeave(pVM, pCtxCore, rc);
3065 if (!pCtxCore->eflags.Bits.u1VM)
3066 {
3067# ifdef VBOX_WITH_RAW_RING1
3068 if ( EMIsRawRing1Enabled(pVM)
3069 && (pCtxCore->ss.Sel & X86_SEL_RPL) == 2)
3070 {
3071 /* Not quite sure if this is really required, but shouldn't harm (too much anyways). */
3072 /** @todo See what happens if we remove this. */
3073 if ((pCtxCore->ds.Sel & X86_SEL_RPL) == 2)
3074 pCtxCore->ds.Sel = (pCtxCore->ds.Sel & ~X86_SEL_RPL) | 1;
3075 if ((pCtxCore->es.Sel & X86_SEL_RPL) == 2)
3076 pCtxCore->es.Sel = (pCtxCore->es.Sel & ~X86_SEL_RPL) | 1;
3077 if ((pCtxCore->fs.Sel & X86_SEL_RPL) == 2)
3078 pCtxCore->fs.Sel = (pCtxCore->fs.Sel & ~X86_SEL_RPL) | 1;
3079 if ((pCtxCore->gs.Sel & X86_SEL_RPL) == 2)
3080 pCtxCore->gs.Sel = (pCtxCore->gs.Sel & ~X86_SEL_RPL) | 1;
3081
3082 /*
3083 * Ring-2 selector => Ring-1.
3084 */
3085 pCtxCore->ss.Sel = (pCtxCore->ss.Sel & ~X86_SEL_RPL) | 1;
3086 if ((pCtxCore->cs.Sel & X86_SEL_RPL) == 2)
3087 pCtxCore->cs.Sel = (pCtxCore->cs.Sel & ~X86_SEL_RPL) | 1;
3088 }
3089 else
3090 {
3091# endif
3092 /** @todo See what happens if we remove this. */
3093 if ((pCtxCore->ds.Sel & X86_SEL_RPL) == 1)
3094 pCtxCore->ds.Sel &= ~X86_SEL_RPL;
3095 if ((pCtxCore->es.Sel & X86_SEL_RPL) == 1)
3096 pCtxCore->es.Sel &= ~X86_SEL_RPL;
3097 if ((pCtxCore->fs.Sel & X86_SEL_RPL) == 1)
3098 pCtxCore->fs.Sel &= ~X86_SEL_RPL;
3099 if ((pCtxCore->gs.Sel & X86_SEL_RPL) == 1)
3100 pCtxCore->gs.Sel &= ~X86_SEL_RPL;
3101# ifdef VBOX_WITH_RAW_RING1
3102 }
3103# endif
3104 }
3105 }
3106
3107 return rc;
3108}
3109
3110#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
3111
3112/**
3113 * Updates the EFLAGS while we're in raw-mode.
3114 *
3115 * @param pVCpu Pointer to the VMCPU.
3116 * @param fEfl The new EFLAGS value.
3117 */
3118VMMDECL(void) CPUMRawSetEFlags(PVMCPU pVCpu, uint32_t fEfl)
3119{
3120#ifdef VBOX_WITH_RAW_MODE_NOT_R0
3121 if (pVCpu->cpum.s.fRawEntered)
3122 PATMRawSetEFlags(pVCpu->CTX_SUFF(pVM), CPUMCTX2CORE(&pVCpu->cpum.s.Guest), fEfl);
3123 else
3124#endif
3125 pVCpu->cpum.s.Guest.eflags.u32 = fEfl;
3126}
3127
3128
3129/**
3130 * Gets the EFLAGS while we're in raw-mode.
3131 *
3132 * @returns The eflags.
3133 * @param pVCpu Pointer to the current virtual CPU.
3134 */
3135VMMDECL(uint32_t) CPUMRawGetEFlags(PVMCPU pVCpu)
3136{
3137#ifdef VBOX_WITH_RAW_MODE_NOT_R0
3138 if (pVCpu->cpum.s.fRawEntered)
3139 return PATMRawGetEFlags(pVCpu->CTX_SUFF(pVM), CPUMCTX2CORE(&pVCpu->cpum.s.Guest));
3140#endif
3141 return pVCpu->cpum.s.Guest.eflags.u32;
3142}
3143
3144
3145/**
3146 * Sets the specified changed flags (CPUM_CHANGED_*).
3147 *
3148 * @param pVCpu Pointer to the current virtual CPU.
3149 */
3150VMMDECL(void) CPUMSetChangedFlags(PVMCPU pVCpu, uint32_t fChangedFlags)
3151{
3152 pVCpu->cpum.s.fChanged |= fChangedFlags;
3153}
3154
3155
3156/**
3157 * Checks if the CPU supports the FXSAVE and FXRSTOR instruction.
3158 * @returns true if supported.
3159 * @returns false if not supported.
3160 * @param pVM Pointer to the VM.
3161 */
3162VMMDECL(bool) CPUMSupportsFXSR(PVM pVM)
3163{
3164 return pVM->cpum.s.CPUFeatures.edx.u1FXSR != 0;
3165}
3166
3167
3168/**
3169 * Checks if the host OS uses the SYSENTER / SYSEXIT instructions.
3170 * @returns true if used.
3171 * @returns false if not used.
3172 * @param pVM Pointer to the VM.
3173 */
3174VMMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM)
3175{
3176 return RT_BOOL(pVM->cpum.s.fHostUseFlags & CPUM_USE_SYSENTER);
3177}
3178
3179
3180/**
3181 * Checks if the host OS uses the SYSCALL / SYSRET instructions.
3182 * @returns true if used.
3183 * @returns false if not used.
3184 * @param pVM Pointer to the VM.
3185 */
3186VMMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM)
3187{
3188 return RT_BOOL(pVM->cpum.s.fHostUseFlags & CPUM_USE_SYSCALL);
3189}
3190
3191#ifdef IN_RC
3192
3193/**
3194 * Lazily sync in the FPU/XMM state.
3195 *
3196 * @returns VBox status code.
3197 * @param pVCpu Pointer to the VMCPU.
3198 */
3199VMMDECL(int) CPUMHandleLazyFPU(PVMCPU pVCpu)
3200{
3201 return cpumHandleLazyFPUAsm(&pVCpu->cpum.s);
3202}
3203
3204#endif /* !IN_RC */
3205
3206/**
3207 * Checks if we activated the FPU/XMM state of the guest OS.
3208 * @returns true if we did.
3209 * @returns false if not.
3210 * @param pVCpu Pointer to the VMCPU.
3211 */
3212VMMDECL(bool) CPUMIsGuestFPUStateActive(PVMCPU pVCpu)
3213{
3214 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU);
3215}
3216
3217
3218/**
3219 * Deactivate the FPU/XMM state of the guest OS.
3220 * @param pVCpu Pointer to the VMCPU.
3221 *
3222 * @todo r=bird: Why is this needed? Looks like a workaround for mishandled
3223 * FPU state management.
3224 */
3225VMMDECL(void) CPUMDeactivateGuestFPUState(PVMCPU pVCpu)
3226{
3227 Assert(!(pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU));
3228 pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_FPU;
3229}
3230
3231
3232/**
3233 * Checks if the guest debug state is active.
3234 *
3235 * @returns boolean
3236 * @param pVM Pointer to the VMCPU.
3237 */
3238VMMDECL(bool) CPUMIsGuestDebugStateActive(PVMCPU pVCpu)
3239{
3240 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_GUEST);
3241}
3242
3243
3244/**
3245 * Checks if the guest debug state is to be made active during the world-switch
3246 * (currently only used for the 32->64 switcher case).
3247 *
3248 * @returns boolean
3249 * @param pVM Pointer to the VMCPU.
3250 */
3251VMMDECL(bool) CPUMIsGuestDebugStateActivePending(PVMCPU pVCpu)
3252{
3253 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_SYNC_DEBUG_REGS_GUEST);
3254}
3255
3256
3257/**
3258 * Checks if the hyper debug state is active.
3259 *
3260 * @returns boolean
3261 * @param pVM Pointer to the VM.
3262 */
3263VMMDECL(bool) CPUMIsHyperDebugStateActive(PVMCPU pVCpu)
3264{
3265 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HYPER);
3266}
3267
3268
3269/**
3270 * Checks if the hyper debug state is to be made active during the world-switch
3271 * (currently only used for the 32->64 switcher case).
3272 *
3273 * @returns boolean
3274 * @param pVM Pointer to the VMCPU.
3275 */
3276VMMDECL(bool) CPUMIsHyperDebugStateActivePending(PVMCPU pVCpu)
3277{
3278 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_SYNC_DEBUG_REGS_HYPER);
3279}
3280
3281
3282/**
3283 * Mark the guest's debug state as inactive.
3284 *
3285 * @returns boolean
3286 * @param pVM Pointer to the VM.
3287 * @todo This API doesn't make sense any more.
3288 */
3289VMMDECL(void) CPUMDeactivateGuestDebugState(PVMCPU pVCpu)
3290{
3291 Assert(!(pVCpu->cpum.s.fUseFlags & (CPUM_USED_DEBUG_REGS_GUEST | CPUM_USED_DEBUG_REGS_HYPER | CPUM_USED_DEBUG_REGS_HOST)));
3292}
3293
3294
3295/**
3296 * Get the current privilege level of the guest.
3297 *
3298 * @returns CPL
3299 * @param pVCpu Pointer to the current virtual CPU.
3300 */
3301VMMDECL(uint32_t) CPUMGetGuestCPL(PVMCPU pVCpu)
3302{
3303 /*
3304 * CPL can reliably be found in SS.DPL (hidden regs valid) or SS if not.
3305 *
3306 * Note! We used to check CS.DPL here, assuming it was always equal to
3307 * CPL even if a conforming segment was loaded. But this truned out to
3308 * only apply to older AMD-V. With VT-x we had an ACP2 regression
3309 * during install after a far call to ring 2 with VT-x. Then on newer
3310 * AMD-V CPUs we have to move the VMCB.guest.u8CPL into cs.Attr.n.u2Dpl
3311 * as well as ss.Attr.n.u2Dpl to make this (and other) code work right.
3312 *
3313 * So, forget CS.DPL, always use SS.DPL.
3314 *
3315 * Note! The SS RPL is always equal to the CPL, while the CS RPL
3316 * isn't necessarily equal if the segment is conforming.
3317 * See section 4.11.1 in the AMD manual.
3318 *
3319 * Update: Where the heck does it say CS.RPL can differ from CPL other than
3320 * right after real->prot mode switch and when in V8086 mode? That
3321 * section says the RPL specified in a direct transfere (call, jmp,
3322 * ret) is not the one loaded into CS. Besides, if CS.RPL != CPL
3323 * it would be impossible for an exception handle or the iret
3324 * instruction to figure out whether SS:ESP are part of the frame
3325 * or not. VBox or qemu bug must've lead to this misconception.
3326 *
3327 * Update2: On an AMD bulldozer system here, I've no trouble loading a null
3328 * selector into SS with an RPL other than the CPL when CPL != 3 and
3329 * we're in 64-bit mode. The intel dev box doesn't allow this, on
3330 * RPL = CPL. Weird.
3331 */
3332 uint32_t uCpl;
3333 if (pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE)
3334 {
3335 if (!pVCpu->cpum.s.Guest.eflags.Bits.u1VM)
3336 {
3337 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.s.Guest.ss))
3338 uCpl = pVCpu->cpum.s.Guest.ss.Attr.n.u2Dpl;
3339 else
3340 {
3341 uCpl = (pVCpu->cpum.s.Guest.ss.Sel & X86_SEL_RPL);
3342#ifdef VBOX_WITH_RAW_MODE_NOT_R0
3343# ifdef VBOX_WITH_RAW_RING1
3344 if (pVCpu->cpum.s.fRawEntered)
3345 {
3346 if ( uCpl == 2
3347 && EMIsRawRing1Enabled(pVCpu->CTX_SUFF(pVM)))
3348 uCpl = 1;
3349 else if (uCpl == 1)
3350 uCpl = 0;
3351 }
3352 Assert(uCpl != 2); /* ring 2 support not allowed anymore. */
3353# else
3354 if (uCpl == 1)
3355 uCpl = 0;
3356# endif
3357#endif
3358 }
3359 }
3360 else
3361 uCpl = 3; /* V86 has CPL=3; REM doesn't set DPL=3 in V8086 mode. See @bugref{5130}. */
3362 }
3363 else
3364 uCpl = 0; /* Real mode is zero; CPL set to 3 for VT-x real-mode emulation. */
3365 return uCpl;
3366}
3367
3368
3369/**
3370 * Gets the current guest CPU mode.
3371 *
3372 * If paging mode is what you need, check out PGMGetGuestMode().
3373 *
3374 * @returns The CPU mode.
3375 * @param pVCpu Pointer to the VMCPU.
3376 */
3377VMMDECL(CPUMMODE) CPUMGetGuestMode(PVMCPU pVCpu)
3378{
3379 CPUMMODE enmMode;
3380 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
3381 enmMode = CPUMMODE_REAL;
3382 else if (!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
3383 enmMode = CPUMMODE_PROTECTED;
3384 else
3385 enmMode = CPUMMODE_LONG;
3386
3387 return enmMode;
3388}
3389
3390
3391/**
3392 * Figure whether the CPU is currently executing 16, 32 or 64 bit code.
3393 *
3394 * @returns 16, 32 or 64.
3395 * @param pVCpu The current virtual CPU.
3396 */
3397VMMDECL(uint32_t) CPUMGetGuestCodeBits(PVMCPU pVCpu)
3398{
3399 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
3400 return 16;
3401
3402 if (pVCpu->cpum.s.Guest.eflags.Bits.u1VM)
3403 {
3404 Assert(!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA));
3405 return 16;
3406 }
3407
3408 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
3409 if ( pVCpu->cpum.s.Guest.cs.Attr.n.u1Long
3410 && (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
3411 return 64;
3412
3413 if (pVCpu->cpum.s.Guest.cs.Attr.n.u1DefBig)
3414 return 32;
3415
3416 return 16;
3417}
3418
3419
3420VMMDECL(DISCPUMODE) CPUMGetGuestDisMode(PVMCPU pVCpu)
3421{
3422 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
3423 return DISCPUMODE_16BIT;
3424
3425 if (pVCpu->cpum.s.Guest.eflags.Bits.u1VM)
3426 {
3427 Assert(!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA));
3428 return DISCPUMODE_16BIT;
3429 }
3430
3431 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
3432 if ( pVCpu->cpum.s.Guest.cs.Attr.n.u1Long
3433 && (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
3434 return DISCPUMODE_64BIT;
3435
3436 if (pVCpu->cpum.s.Guest.cs.Attr.n.u1DefBig)
3437 return DISCPUMODE_32BIT;
3438
3439 return DISCPUMODE_16BIT;
3440}
3441
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use