VirtualBox

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

Last change on this file since 52717 was 52717, checked in by vboxsync, 11 years ago

VMM/CPUM: Raise #GP(0) while writing to disallowed EFER bits.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 107.7 KB
Line 
1/* $Id: CPUMAllRegs.cpp 52717 2014-09-12 11:34:11Z vboxsync $ */
2/** @file
3 * CPUM - CPU Monitor(/Manager) - Getters and Setters.
4 */
5
6/*
7 * Copyright (C) 2006-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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 /* #GP(0) If anything outside the allowed bits is set. */
1431 if ((uValue | fMask) != fMask)
1432 {
1433 Log(("CPUM: Settings disallowed EFER bit. uValue=%#RX64 fAllowed=%#RX64 -> #GP(0)\n", uValue, fMask));
1434 return VERR_CPUM_RAISE_GP_0;
1435 }
1436
1437 /* Check for illegal MSR_K6_EFER_LME transitions: not allowed to change LME if
1438 paging is enabled. (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */
1439 if ( (uOldEFER & MSR_K6_EFER_LME) != (uValue & fMask & MSR_K6_EFER_LME)
1440 && (pVCpu->cpum.s.Guest.cr0 & X86_CR0_PG))
1441 {
1442 Log(("CPUM: Illegal MSR_K6_EFER_LME change: paging is enabled!!\n"));
1443 return VERR_CPUM_RAISE_GP_0;
1444 }
1445
1446 /* There are a few more: e.g. MSR_K6_EFER_LMSLE */
1447 AssertMsg(!(uValue & ~(MSR_K6_EFER_NXE | MSR_K6_EFER_LME | MSR_K6_EFER_LMA /* ignored anyway */ | MSR_K6_EFER_SCE | MSR_K6_EFER_FFXSR)),
1448 ("Unexpected value %RX64\n", uValue));
1449 pVCpu->cpum.s.Guest.msrEFER = (uOldEFER & ~fMask) | (uValue & fMask);
1450
1451 /* AMD64 Architecture Programmer's Manual: 15.15 TLB Control; flush the TLB
1452 if MSR_K6_EFER_NXE, MSR_K6_EFER_LME or MSR_K6_EFER_LMA are changed. */
1453 if ( (uOldEFER & (MSR_K6_EFER_NXE | MSR_K6_EFER_LME | MSR_K6_EFER_LMA))
1454 != (pVCpu->cpum.s.Guest.msrEFER & (MSR_K6_EFER_NXE | MSR_K6_EFER_LME | MSR_K6_EFER_LMA)))
1455 {
1456 /// @todo PGMFlushTLB(pVCpu, cr3, true /*fGlobal*/);
1457 HMFlushTLB(pVCpu);
1458
1459 /* Notify PGM about NXE changes. */
1460 if ( (uOldEFER & MSR_K6_EFER_NXE)
1461 != (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_NXE))
1462 PGMNotifyNxeChanged(pVCpu, !(uOldEFER & MSR_K6_EFER_NXE));
1463 }
1464 break;
1465 }
1466
1467 case MSR_K8_SF_MASK:
1468 pVCpu->cpum.s.Guest.msrSFMASK = uValue;
1469 break;
1470
1471 case MSR_K6_STAR:
1472 pVCpu->cpum.s.Guest.msrSTAR = uValue;
1473 break;
1474
1475 case MSR_K8_LSTAR:
1476 pVCpu->cpum.s.Guest.msrLSTAR = uValue;
1477 break;
1478
1479 case MSR_K8_CSTAR:
1480 pVCpu->cpum.s.Guest.msrCSTAR = uValue;
1481 break;
1482
1483 case MSR_K8_FS_BASE:
1484 pVCpu->cpum.s.Guest.fs.u64Base = uValue;
1485 break;
1486
1487 case MSR_K8_GS_BASE:
1488 pVCpu->cpum.s.Guest.gs.u64Base = uValue;
1489 break;
1490
1491 case MSR_K8_KERNEL_GS_BASE:
1492 pVCpu->cpum.s.Guest.msrKERNELGSBASE = uValue;
1493 break;
1494
1495 case MSR_K8_TSC_AUX:
1496 pVCpu->cpum.s.GuestMsrs.msr.TscAux = uValue;
1497 break;
1498
1499 case MSR_IA32_DEBUGCTL:
1500 /** @todo virtualize DEBUGCTL and relatives */
1501 break;
1502
1503 /*
1504 * Intel specifics MSRs:
1505 */
1506 /*case MSR_IA32_PLATFORM_ID: - read-only */
1507 case MSR_IA32_BIOS_SIGN_ID: /* fam/mod >= 6_01 */
1508 case MSR_IA32_BIOS_UPDT_TRIG: /* fam/mod >= 6_01 */
1509 /*case MSR_IA32_MCP_CAP: - read-only */
1510 /*case MSR_IA32_MCG_STATUS: - read-only */
1511 /*case MSR_IA32_MCG_CTRL: - indicated as not present in CAP */
1512 /*case MSR_IA32_MC0_CTL: - read-only? */
1513 /*case MSR_IA32_MC0_STATUS: - read-only? */
1514 case MSR_PKG_CST_CONFIG_CONTROL:
1515 if (CPUMGetGuestCpuVendor(pVCpu->CTX_SUFF(pVM)) != CPUMCPUVENDOR_INTEL)
1516 {
1517 Log(("CPUM: MSR %#x is Intel, the virtual CPU isn't an Intel one -> #GP\n", idMsr));
1518 return VERR_CPUM_RAISE_GP_0;
1519 }
1520
1521 switch (idMsr)
1522 {
1523 case MSR_PKG_CST_CONFIG_CONTROL:
1524 {
1525 if (pVCpu->cpum.s.GuestMsrs.msr.PkgCStateCfgCtrl & RT_BIT_64(15))
1526 {
1527 Log(("MSR_PKG_CST_CONFIG_CONTROL: Write protected -> #GP\n"));
1528 return VERR_CPUM_RAISE_GP_0;
1529 }
1530 static uint64_t s_fMask = UINT64_C(0x01f08407); /** @todo Only Nehalem has 24; Only Sandy has 27 and 28. */
1531 static uint64_t s_fGpInvalid = UINT64_C(0xffffffff00ff0000); /** @todo figure out exactly what's off limits. */
1532 if ((uValue & s_fGpInvalid) || (uValue & 7) >= 5)
1533 {
1534 Log(("MSR_PKG_CST_CONFIG_CONTROL: Invalid value %#llx -> #GP\n", uValue));
1535 return VERR_CPUM_RAISE_GP_0;
1536 }
1537 pVCpu->cpum.s.GuestMsrs.msr.PkgCStateCfgCtrl = uValue & s_fMask;
1538 break;
1539 }
1540
1541 }
1542 /* ignored */
1543 break;
1544
1545 /*
1546 * AMD specific MSRs:
1547 */
1548 case MSR_K8_SYSCFG: /** @todo can be written, but we ignore that for now. */
1549 case MSR_K8_INT_PENDING: /** @todo can be written, but we ignore that for now. */
1550 case MSR_K8_NB_CFG: /** @todo can be written; the apicid swapping might be used and would need saving, but probably unnecessary. */
1551 case 0xc0011029: /* quick fix for FreeBSd 9.1. */
1552 case 0xc0010042: /* quick fix for something. */
1553 case 0xc001102a: /* quick fix for w2k8 + opposition. */
1554 case 0xc0011004: /* quick fix for the opposition. */
1555 case 0xc0011005: /* quick fix for the opposition. */
1556 case MSR_K7_EVNTSEL0: /* quick fix for the opposition. */
1557 case MSR_K7_EVNTSEL1: /* quick fix for the opposition. */
1558 case MSR_K7_EVNTSEL2: /* quick fix for the opposition. */
1559 case MSR_K7_EVNTSEL3: /* quick fix for the opposition. */
1560 case MSR_K7_PERFCTR0: /* quick fix for the opposition. */
1561 case MSR_K7_PERFCTR1: /* quick fix for the opposition. */
1562 case MSR_K7_PERFCTR2: /* quick fix for the opposition. */
1563 case MSR_K7_PERFCTR3: /* quick fix for the opposition. */
1564 if (CPUMGetGuestCpuVendor(pVCpu->CTX_SUFF(pVM)) != CPUMCPUVENDOR_AMD)
1565 {
1566 Log(("CPUM: MSR %#x is AMD, the virtual CPU isn't an Intel one -> #GP\n", idMsr));
1567 return VERR_CPUM_RAISE_GP_0;
1568 }
1569 /* ignored */
1570 break;
1571
1572
1573 default:
1574 /*
1575 * Hand the X2APIC range to PDM and the APIC.
1576 */
1577 if ( idMsr >= MSR_IA32_X2APIC_START
1578 && idMsr <= MSR_IA32_X2APIC_END)
1579 {
1580 rc = PDMApicWriteMSR(pVCpu->CTX_SUFF(pVM), pVCpu->idCpu, idMsr, uValue);
1581 if (rc != VINF_SUCCESS)
1582 rc = VERR_CPUM_RAISE_GP_0;
1583 }
1584 else
1585 {
1586 /* We should actually trigger a #GP here, but don't as that might cause more trouble. */
1587 /** @todo rc = VERR_CPUM_RAISE_GP_0 */
1588 Log(("CPUMSetGuestMsr: Unknown MSR %#x attempted set to %#llx\n", idMsr, uValue));
1589 }
1590 break;
1591 }
1592 return rc;
1593}
1594
1595#endif /* !VBOX_WITH_NEW_MSR_CODE */
1596
1597
1598VMMDECL(RTGCPTR) CPUMGetGuestIDTR(PVMCPU pVCpu, uint16_t *pcbLimit)
1599{
1600 if (pcbLimit)
1601 *pcbLimit = pVCpu->cpum.s.Guest.idtr.cbIdt;
1602 return pVCpu->cpum.s.Guest.idtr.pIdt;
1603}
1604
1605
1606VMMDECL(RTSEL) CPUMGetGuestTR(PVMCPU pVCpu, PCPUMSELREGHID pHidden)
1607{
1608 if (pHidden)
1609 *pHidden = pVCpu->cpum.s.Guest.tr;
1610 return pVCpu->cpum.s.Guest.tr.Sel;
1611}
1612
1613
1614VMMDECL(RTSEL) CPUMGetGuestCS(PVMCPU pVCpu)
1615{
1616 return pVCpu->cpum.s.Guest.cs.Sel;
1617}
1618
1619
1620VMMDECL(RTSEL) CPUMGetGuestDS(PVMCPU pVCpu)
1621{
1622 return pVCpu->cpum.s.Guest.ds.Sel;
1623}
1624
1625
1626VMMDECL(RTSEL) CPUMGetGuestES(PVMCPU pVCpu)
1627{
1628 return pVCpu->cpum.s.Guest.es.Sel;
1629}
1630
1631
1632VMMDECL(RTSEL) CPUMGetGuestFS(PVMCPU pVCpu)
1633{
1634 return pVCpu->cpum.s.Guest.fs.Sel;
1635}
1636
1637
1638VMMDECL(RTSEL) CPUMGetGuestGS(PVMCPU pVCpu)
1639{
1640 return pVCpu->cpum.s.Guest.gs.Sel;
1641}
1642
1643
1644VMMDECL(RTSEL) CPUMGetGuestSS(PVMCPU pVCpu)
1645{
1646 return pVCpu->cpum.s.Guest.ss.Sel;
1647}
1648
1649
1650VMMDECL(RTSEL) CPUMGetGuestLDTR(PVMCPU pVCpu)
1651{
1652 return pVCpu->cpum.s.Guest.ldtr.Sel;
1653}
1654
1655
1656VMMDECL(RTSEL) CPUMGetGuestLdtrEx(PVMCPU pVCpu, uint64_t *pGCPtrBase, uint32_t *pcbLimit)
1657{
1658 *pGCPtrBase = pVCpu->cpum.s.Guest.ldtr.u64Base;
1659 *pcbLimit = pVCpu->cpum.s.Guest.ldtr.u32Limit;
1660 return pVCpu->cpum.s.Guest.ldtr.Sel;
1661}
1662
1663
1664VMMDECL(uint64_t) CPUMGetGuestCR0(PVMCPU pVCpu)
1665{
1666 return pVCpu->cpum.s.Guest.cr0;
1667}
1668
1669
1670VMMDECL(uint64_t) CPUMGetGuestCR2(PVMCPU pVCpu)
1671{
1672 return pVCpu->cpum.s.Guest.cr2;
1673}
1674
1675
1676VMMDECL(uint64_t) CPUMGetGuestCR3(PVMCPU pVCpu)
1677{
1678 return pVCpu->cpum.s.Guest.cr3;
1679}
1680
1681
1682VMMDECL(uint64_t) CPUMGetGuestCR4(PVMCPU pVCpu)
1683{
1684 return pVCpu->cpum.s.Guest.cr4;
1685}
1686
1687
1688VMMDECL(uint64_t) CPUMGetGuestCR8(PVMCPU pVCpu)
1689{
1690 uint64_t u64;
1691 int rc = CPUMGetGuestCRx(pVCpu, DISCREG_CR8, &u64);
1692 if (RT_FAILURE(rc))
1693 u64 = 0;
1694 return u64;
1695}
1696
1697
1698VMMDECL(void) CPUMGetGuestGDTR(PVMCPU pVCpu, PVBOXGDTR pGDTR)
1699{
1700 *pGDTR = pVCpu->cpum.s.Guest.gdtr;
1701}
1702
1703
1704VMMDECL(uint32_t) CPUMGetGuestEIP(PVMCPU pVCpu)
1705{
1706 return pVCpu->cpum.s.Guest.eip;
1707}
1708
1709
1710VMMDECL(uint64_t) CPUMGetGuestRIP(PVMCPU pVCpu)
1711{
1712 return pVCpu->cpum.s.Guest.rip;
1713}
1714
1715
1716VMMDECL(uint32_t) CPUMGetGuestEAX(PVMCPU pVCpu)
1717{
1718 return pVCpu->cpum.s.Guest.eax;
1719}
1720
1721
1722VMMDECL(uint32_t) CPUMGetGuestEBX(PVMCPU pVCpu)
1723{
1724 return pVCpu->cpum.s.Guest.ebx;
1725}
1726
1727
1728VMMDECL(uint32_t) CPUMGetGuestECX(PVMCPU pVCpu)
1729{
1730 return pVCpu->cpum.s.Guest.ecx;
1731}
1732
1733
1734VMMDECL(uint32_t) CPUMGetGuestEDX(PVMCPU pVCpu)
1735{
1736 return pVCpu->cpum.s.Guest.edx;
1737}
1738
1739
1740VMMDECL(uint32_t) CPUMGetGuestESI(PVMCPU pVCpu)
1741{
1742 return pVCpu->cpum.s.Guest.esi;
1743}
1744
1745
1746VMMDECL(uint32_t) CPUMGetGuestEDI(PVMCPU pVCpu)
1747{
1748 return pVCpu->cpum.s.Guest.edi;
1749}
1750
1751
1752VMMDECL(uint32_t) CPUMGetGuestESP(PVMCPU pVCpu)
1753{
1754 return pVCpu->cpum.s.Guest.esp;
1755}
1756
1757
1758VMMDECL(uint32_t) CPUMGetGuestEBP(PVMCPU pVCpu)
1759{
1760 return pVCpu->cpum.s.Guest.ebp;
1761}
1762
1763
1764VMMDECL(uint32_t) CPUMGetGuestEFlags(PVMCPU pVCpu)
1765{
1766 return pVCpu->cpum.s.Guest.eflags.u32;
1767}
1768
1769
1770VMMDECL(int) CPUMGetGuestCRx(PVMCPU pVCpu, unsigned iReg, uint64_t *pValue)
1771{
1772 switch (iReg)
1773 {
1774 case DISCREG_CR0:
1775 *pValue = pVCpu->cpum.s.Guest.cr0;
1776 break;
1777
1778 case DISCREG_CR2:
1779 *pValue = pVCpu->cpum.s.Guest.cr2;
1780 break;
1781
1782 case DISCREG_CR3:
1783 *pValue = pVCpu->cpum.s.Guest.cr3;
1784 break;
1785
1786 case DISCREG_CR4:
1787 *pValue = pVCpu->cpum.s.Guest.cr4;
1788 break;
1789
1790 case DISCREG_CR8:
1791 {
1792 uint8_t u8Tpr;
1793 int rc = PDMApicGetTPR(pVCpu, &u8Tpr, NULL /* pfPending */, NULL /* pu8PendingIrq */);
1794 if (RT_FAILURE(rc))
1795 {
1796 AssertMsg(rc == VERR_PDM_NO_APIC_INSTANCE, ("%Rrc\n", rc));
1797 *pValue = 0;
1798 return rc;
1799 }
1800 *pValue = u8Tpr >> 4; /* bits 7-4 contain the task priority that go in cr8, bits 3-0*/
1801 break;
1802 }
1803
1804 default:
1805 return VERR_INVALID_PARAMETER;
1806 }
1807 return VINF_SUCCESS;
1808}
1809
1810
1811VMMDECL(uint64_t) CPUMGetGuestDR0(PVMCPU pVCpu)
1812{
1813 return pVCpu->cpum.s.Guest.dr[0];
1814}
1815
1816
1817VMMDECL(uint64_t) CPUMGetGuestDR1(PVMCPU pVCpu)
1818{
1819 return pVCpu->cpum.s.Guest.dr[1];
1820}
1821
1822
1823VMMDECL(uint64_t) CPUMGetGuestDR2(PVMCPU pVCpu)
1824{
1825 return pVCpu->cpum.s.Guest.dr[2];
1826}
1827
1828
1829VMMDECL(uint64_t) CPUMGetGuestDR3(PVMCPU pVCpu)
1830{
1831 return pVCpu->cpum.s.Guest.dr[3];
1832}
1833
1834
1835VMMDECL(uint64_t) CPUMGetGuestDR6(PVMCPU pVCpu)
1836{
1837 return pVCpu->cpum.s.Guest.dr[6];
1838}
1839
1840
1841VMMDECL(uint64_t) CPUMGetGuestDR7(PVMCPU pVCpu)
1842{
1843 return pVCpu->cpum.s.Guest.dr[7];
1844}
1845
1846
1847VMMDECL(int) CPUMGetGuestDRx(PVMCPU pVCpu, uint32_t iReg, uint64_t *pValue)
1848{
1849 AssertReturn(iReg <= DISDREG_DR7, VERR_INVALID_PARAMETER);
1850 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
1851 if (iReg == 4 || iReg == 5)
1852 iReg += 2;
1853 *pValue = pVCpu->cpum.s.Guest.dr[iReg];
1854 return VINF_SUCCESS;
1855}
1856
1857
1858VMMDECL(uint64_t) CPUMGetGuestEFER(PVMCPU pVCpu)
1859{
1860 return pVCpu->cpum.s.Guest.msrEFER;
1861}
1862
1863
1864/**
1865 * Looks up a CPUID leaf in the CPUID leaf array.
1866 *
1867 * @returns Pointer to the leaf if found, NULL if not.
1868 *
1869 * @param pVM Pointer to the cross context VM structure.
1870 * @param uLeaf The leaf to get.
1871 * @param uSubLeaf The subleaf, if applicable. Just pass 0 if it
1872 * isn't.
1873 */
1874PCPUMCPUIDLEAF cpumCpuIdGetLeaf(PVM pVM, uint32_t uLeaf, uint32_t uSubLeaf)
1875{
1876 unsigned iEnd = pVM->cpum.s.GuestInfo.cCpuIdLeaves;
1877 if (iEnd)
1878 {
1879 unsigned iStart = 0;
1880 PCPUMCPUIDLEAF paLeaves = pVM->cpum.s.GuestInfo.CTX_SUFF(paCpuIdLeaves);
1881 for (;;)
1882 {
1883 unsigned i = iStart + (iEnd - iStart) / 2U;
1884 if (uLeaf < paLeaves[i].uLeaf)
1885 {
1886 if (i <= iStart)
1887 return NULL;
1888 iEnd = i;
1889 }
1890 else if (uLeaf > paLeaves[i].uLeaf)
1891 {
1892 i += 1;
1893 if (i >= iEnd)
1894 return NULL;
1895 iStart = i;
1896 }
1897 else
1898 {
1899 uSubLeaf &= paLeaves[i].fSubLeafMask;
1900 if (uSubLeaf != paLeaves[i].uSubLeaf)
1901 {
1902 /* Find the right subleaf. We return the last one before
1903 uSubLeaf if we don't find an exact match. */
1904 if (uSubLeaf < paLeaves[i].uSubLeaf)
1905 while ( i > 0
1906 && uLeaf == paLeaves[i].uLeaf
1907 && uSubLeaf < paLeaves[i].uSubLeaf)
1908 i--;
1909 else
1910 while ( i + 1 < pVM->cpum.s.GuestInfo.cCpuIdLeaves
1911 && uLeaf == paLeaves[i + 1].uLeaf
1912 && uSubLeaf >= paLeaves[i + 1].uSubLeaf)
1913 i++;
1914 }
1915 return &paLeaves[i];
1916 }
1917 }
1918 }
1919
1920 return NULL;
1921}
1922
1923
1924/**
1925 * Gets a CPUID leaf.
1926 *
1927 * @param pVCpu Pointer to the VMCPU.
1928 * @param iLeaf The CPUID leaf to get.
1929 * @param pEax Where to store the EAX value.
1930 * @param pEbx Where to store the EBX value.
1931 * @param pEcx Where to store the ECX value.
1932 * @param pEdx Where to store the EDX value.
1933 */
1934VMMDECL(void) CPUMGetGuestCpuId(PVMCPU pVCpu, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)
1935{
1936 PVM pVM = pVCpu->CTX_SUFF(pVM);
1937
1938 PCCPUMCPUID pCpuId;
1939 if (iLeaf < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd))
1940 pCpuId = &pVM->cpum.s.aGuestCpuIdStd[iLeaf];
1941 else if (iLeaf - UINT32_C(0x80000000) < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdExt))
1942 pCpuId = &pVM->cpum.s.aGuestCpuIdExt[iLeaf - UINT32_C(0x80000000)];
1943 else if ( iLeaf - UINT32_C(0x40000000) < 0x100 /** @todo Fix this later: Hyper-V says 0x400000FF is the last valid leaf. */
1944 && (pVCpu->CTX_SUFF(pVM)->cpum.s.aGuestCpuIdStd[1].ecx & X86_CPUID_FEATURE_ECX_HVP)) /* Only report if HVP bit set. */
1945 {
1946 PCPUMCPUIDLEAF pHyperLeaf = cpumCpuIdGetLeaf(pVM, iLeaf, 0 /* uSubLeaf */);
1947 if (RT_LIKELY(pHyperLeaf))
1948 {
1949 *pEax = pHyperLeaf->uEax;
1950 *pEbx = pHyperLeaf->uEbx;
1951 *pEcx = pHyperLeaf->uEcx;
1952 *pEdx = pHyperLeaf->uEdx;
1953 }
1954 else
1955 {
1956 *pEax = *pEbx = *pEcx = *pEdx = 0;
1957 }
1958 return;
1959 }
1960 else if (iLeaf - UINT32_C(0xc0000000) < RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdCentaur))
1961 pCpuId = &pVM->cpum.s.aGuestCpuIdCentaur[iLeaf - UINT32_C(0xc0000000)];
1962 else
1963 pCpuId = &pVM->cpum.s.GuestCpuIdDef;
1964
1965 uint32_t cCurrentCacheIndex = *pEcx;
1966
1967 *pEax = pCpuId->eax;
1968 *pEbx = pCpuId->ebx;
1969 *pEcx = pCpuId->ecx;
1970 *pEdx = pCpuId->edx;
1971
1972 if ( iLeaf == 1)
1973 {
1974 /* Bits 31-24: Initial APIC ID */
1975 Assert(pVCpu->idCpu <= 255);
1976 *pEbx |= (pVCpu->idCpu << 24);
1977 }
1978
1979 if ( iLeaf == 4
1980 && cCurrentCacheIndex < 3
1981 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_INTEL)
1982 {
1983 uint32_t type, level, sharing, linesize,
1984 partitions, associativity, sets, cores;
1985
1986 /* For type: 1 - data cache, 2 - i-cache, 3 - unified */
1987 partitions = 1;
1988 /* Those are only to shut up compiler, as they will always
1989 get overwritten, and compiler should be able to figure that out */
1990 sets = associativity = sharing = level = 1;
1991 cores = pVM->cCpus > 32 ? 32 : pVM->cCpus;
1992 switch (cCurrentCacheIndex)
1993 {
1994 case 0:
1995 type = 1;
1996 level = 1;
1997 sharing = 1;
1998 linesize = 64;
1999 associativity = 8;
2000 sets = 64;
2001 break;
2002 case 1:
2003 level = 1;
2004 type = 2;
2005 sharing = 1;
2006 linesize = 64;
2007 associativity = 8;
2008 sets = 64;
2009 break;
2010 default: /* shut up gcc.*/
2011 AssertFailed();
2012 case 2:
2013 level = 2;
2014 type = 3;
2015 sharing = cores; /* our L2 cache is modelled as shared between all cores */
2016 linesize = 64;
2017 associativity = 24;
2018 sets = 4096;
2019 break;
2020 }
2021
2022 NOREF(type);
2023 *pEax |= ((cores - 1) << 26) |
2024 ((sharing - 1) << 14) |
2025 (level << 5) |
2026 1;
2027 *pEbx = (linesize - 1) |
2028 ((partitions - 1) << 12) |
2029 ((associativity - 1) << 22); /* -1 encoding */
2030 *pEcx = sets - 1;
2031 }
2032
2033 Log2(("CPUMGetGuestCpuId: iLeaf=%#010x %RX32 %RX32 %RX32 %RX32\n", iLeaf, *pEax, *pEbx, *pEcx, *pEdx));
2034}
2035
2036/**
2037 * Gets a number of standard CPUID leafs.
2038 *
2039 * @returns Number of leafs.
2040 * @param pVM Pointer to the VM.
2041 * @remark Intended for PATM.
2042 */
2043VMMDECL(uint32_t) CPUMGetGuestCpuIdStdMax(PVM pVM)
2044{
2045 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd);
2046}
2047
2048
2049/**
2050 * Gets a number of extended CPUID leafs.
2051 *
2052 * @returns Number of leafs.
2053 * @param pVM Pointer to the VM.
2054 * @remark Intended for PATM.
2055 */
2056VMMDECL(uint32_t) CPUMGetGuestCpuIdExtMax(PVM pVM)
2057{
2058 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdExt);
2059}
2060
2061
2062/**
2063 * Gets a number of centaur CPUID leafs.
2064 *
2065 * @returns Number of leafs.
2066 * @param pVM Pointer to the VM.
2067 * @remark Intended for PATM.
2068 */
2069VMMDECL(uint32_t) CPUMGetGuestCpuIdCentaurMax(PVM pVM)
2070{
2071 return RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdCentaur);
2072}
2073
2074
2075/**
2076 * Sets a CPUID feature bit.
2077 *
2078 * @param pVM Pointer to the VM.
2079 * @param enmFeature The feature to set.
2080 */
2081VMMDECL(void) CPUMSetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
2082{
2083 PCPUMCPUIDLEAF pLeaf;
2084
2085 switch (enmFeature)
2086 {
2087 /*
2088 * Set the APIC bit in both feature masks.
2089 */
2090 case CPUMCPUIDFEATURE_APIC:
2091 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2092 if (pLeaf)
2093 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_APIC;
2094
2095 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2096 if ( pLeaf
2097 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2098 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_AMD_FEATURE_EDX_APIC;
2099
2100 pVM->cpum.s.GuestFeatures.fApic = 1;
2101 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled APIC\n"));
2102 break;
2103
2104 /*
2105 * Set the x2APIC bit in the standard feature mask.
2106 */
2107 case CPUMCPUIDFEATURE_X2APIC:
2108 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2109 if (pLeaf)
2110 pVM->cpum.s.aGuestCpuIdStd[1].ecx = pLeaf->uEcx |= X86_CPUID_FEATURE_ECX_X2APIC;
2111 pVM->cpum.s.GuestFeatures.fX2Apic = 1;
2112 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled x2APIC\n"));
2113 break;
2114
2115 /*
2116 * Set the sysenter/sysexit bit in the standard feature mask.
2117 * Assumes the caller knows what it's doing! (host must support these)
2118 */
2119 case CPUMCPUIDFEATURE_SEP:
2120 if (!pVM->cpum.s.HostFeatures.fSysEnter)
2121 {
2122 AssertMsgFailed(("ERROR: Can't turn on SEP when the host doesn't support it!!\n"));
2123 return;
2124 }
2125
2126 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2127 if (pLeaf)
2128 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_SEP;
2129 pVM->cpum.s.GuestFeatures.fSysEnter = 1;
2130 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled SYSENTER/EXIT\n"));
2131 break;
2132
2133 /*
2134 * Set the syscall/sysret bit in the extended feature mask.
2135 * Assumes the caller knows what it's doing! (host must support these)
2136 */
2137 case CPUMCPUIDFEATURE_SYSCALL:
2138 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2139 if ( !pLeaf
2140 || !pVM->cpum.s.HostFeatures.fSysCall)
2141 {
2142#if HC_ARCH_BITS == 32
2143 /* X86_CPUID_EXT_FEATURE_EDX_SYSCALL not set it seems in 32-bit
2144 mode by Intel, even when the cpu is capable of doing so in
2145 64-bit mode. Long mode requires syscall support. */
2146 if (!pVM->cpum.s.HostFeatures.fLongMode)
2147#endif
2148 {
2149 LogRel(("CPUM: WARNING! Can't turn on SYSCALL/SYSRET when the host doesn't support it!\n"));
2150 return;
2151 }
2152 }
2153
2154 /* Valid for both Intel and AMD CPUs, although only in 64 bits mode for Intel. */
2155 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_SYSCALL;
2156 pVM->cpum.s.GuestFeatures.fSysCall = 1;
2157 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled SYSCALL/RET\n"));
2158 break;
2159
2160 /*
2161 * Set the PAE bit in both feature masks.
2162 * Assumes the caller knows what it's doing! (host must support these)
2163 */
2164 case CPUMCPUIDFEATURE_PAE:
2165 if (!pVM->cpum.s.HostFeatures.fPae)
2166 {
2167 LogRel(("CPUM: WARNING! Can't turn on PAE when the host doesn't support it!\n"));
2168 return;
2169 }
2170
2171 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2172 if (pLeaf)
2173 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_PAE;
2174
2175 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2176 if ( pLeaf
2177 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2178 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_AMD_FEATURE_EDX_PAE;
2179
2180 pVM->cpum.s.GuestFeatures.fPae = 1;
2181 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled PAE\n"));
2182 break;
2183
2184 /*
2185 * Set the LONG MODE bit in the extended feature mask.
2186 * Assumes the caller knows what it's doing! (host must support these)
2187 */
2188 case CPUMCPUIDFEATURE_LONG_MODE:
2189 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2190 if ( !pLeaf
2191 || !pVM->cpum.s.HostFeatures.fLongMode)
2192 {
2193 LogRel(("CPUM: WARNING! Can't turn on LONG MODE when the host doesn't support it!\n"));
2194 return;
2195 }
2196
2197 /* Valid for both Intel and AMD. */
2198 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_LONG_MODE;
2199 pVM->cpum.s.GuestFeatures.fLongMode = 1;
2200 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled LONG MODE\n"));
2201 break;
2202
2203 /*
2204 * Set the NX/XD bit in the extended feature mask.
2205 * Assumes the caller knows what it's doing! (host must support these)
2206 */
2207 case CPUMCPUIDFEATURE_NX:
2208 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2209 if ( !pLeaf
2210 || !pVM->cpum.s.HostFeatures.fNoExecute)
2211 {
2212 LogRel(("CPUM: WARNING! Can't turn on NX/XD when the host doesn't support it!\n"));
2213 return;
2214 }
2215
2216 /* Valid for both Intel and AMD. */
2217 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_NX;
2218 pVM->cpum.s.GuestFeatures.fNoExecute = 1;
2219 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled NX\n"));
2220 break;
2221
2222
2223 /*
2224 * Set the LAHF/SAHF support in 64-bit mode.
2225 * Assumes the caller knows what it's doing! (host must support this)
2226 */
2227 case CPUMCPUIDFEATURE_LAHF:
2228 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2229 if ( !pLeaf
2230 || !pVM->cpum.s.HostFeatures.fLahfSahf)
2231 {
2232 LogRel(("CPUM: WARNING! Can't turn on LAHF/SAHF when the host doesn't support it!\n"));
2233 return;
2234 }
2235
2236 /* Valid for both Intel and AMD. */
2237 pVM->cpum.s.aGuestCpuIdExt[1].ecx = pLeaf->uEcx |= X86_CPUID_EXT_FEATURE_ECX_LAHF_SAHF;
2238 pVM->cpum.s.GuestFeatures.fLahfSahf = 1;
2239 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled LAHF/SAHF\n"));
2240 break;
2241
2242 /*
2243 * Set the page attribute table bit. This is alternative page level
2244 * cache control that doesn't much matter when everything is
2245 * virtualized, though it may when passing thru device memory.
2246 */
2247 case CPUMCPUIDFEATURE_PAT:
2248 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2249 if (pLeaf)
2250 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx |= X86_CPUID_FEATURE_EDX_PAT;
2251
2252 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2253 if ( pLeaf
2254 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2255 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_AMD_FEATURE_EDX_PAT;
2256
2257 pVM->cpum.s.GuestFeatures.fPat = 1;
2258 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled PAT\n"));
2259 break;
2260
2261 /*
2262 * Set the RDTSCP support bit.
2263 * Assumes the caller knows what it's doing! (host must support this)
2264 */
2265 case CPUMCPUIDFEATURE_RDTSCP:
2266 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2267 if ( !pLeaf
2268 || !pVM->cpum.s.HostFeatures.fRdTscP
2269 || pVM->cpum.s.u8PortableCpuIdLevel > 0)
2270 {
2271 if (!pVM->cpum.s.u8PortableCpuIdLevel)
2272 LogRel(("CPUM: WARNING! Can't turn on RDTSCP when the host doesn't support it!\n"));
2273 return;
2274 }
2275
2276 /* Valid for both Intel and AMD. */
2277 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx |= X86_CPUID_EXT_FEATURE_EDX_RDTSCP;
2278 pVM->cpum.s.HostFeatures.fRdTscP = 1;
2279 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled RDTSCP.\n"));
2280 break;
2281
2282 /*
2283 * Set the Hypervisor Present bit in the standard feature mask.
2284 */
2285 case CPUMCPUIDFEATURE_HVP:
2286 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2287 if (pLeaf)
2288 pVM->cpum.s.aGuestCpuIdStd[1].ecx = pLeaf->uEcx |= X86_CPUID_FEATURE_ECX_HVP;
2289 pVM->cpum.s.GuestFeatures.fHypervisorPresent = 1;
2290 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled Hypervisor Present bit\n"));
2291 break;
2292
2293 /*
2294 * Set the MWAIT Extensions Present bit in the MWAIT/MONITOR leaf.
2295 * This currently includes the Present bit and MWAITBREAK bit as well.
2296 */
2297 case CPUMCPUIDFEATURE_MWAIT_EXTS:
2298 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000005), 0);
2299 if ( !pLeaf
2300 || !pVM->cpum.s.HostFeatures.fMWaitExtensions)
2301 {
2302 LogRel(("CPUM: WARNING! Can't turn on MWAIT Extensions when the host doesn't support it!\n"));
2303 return;
2304 }
2305
2306 /* Valid for both Intel and AMD. */
2307 pVM->cpum.s.aGuestCpuIdStd[5].ecx = pLeaf->uEcx |= X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0;
2308 pVM->cpum.s.GuestFeatures.fMWaitExtensions = 1;
2309 LogRel(("CPUM: SetGuestCpuIdFeature: Enabled MWAIT Extensions.\n"));
2310 break;
2311
2312 default:
2313 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
2314 break;
2315 }
2316
2317 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2318 {
2319 PVMCPU pVCpu = &pVM->aCpus[i];
2320 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CPUID;
2321 }
2322}
2323
2324
2325/**
2326 * Queries a CPUID feature bit.
2327 *
2328 * @returns boolean for feature presence
2329 * @param pVM Pointer to the VM.
2330 * @param enmFeature The feature to query.
2331 */
2332VMMDECL(bool) CPUMGetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
2333{
2334 switch (enmFeature)
2335 {
2336 case CPUMCPUIDFEATURE_APIC: return pVM->cpum.s.GuestFeatures.fApic;
2337 case CPUMCPUIDFEATURE_X2APIC: return pVM->cpum.s.GuestFeatures.fX2Apic;
2338 case CPUMCPUIDFEATURE_SYSCALL: return pVM->cpum.s.GuestFeatures.fSysCall;
2339 case CPUMCPUIDFEATURE_SEP: return pVM->cpum.s.GuestFeatures.fSysEnter;
2340 case CPUMCPUIDFEATURE_PAE: return pVM->cpum.s.GuestFeatures.fPae;
2341 case CPUMCPUIDFEATURE_NX: return pVM->cpum.s.GuestFeatures.fNoExecute;
2342 case CPUMCPUIDFEATURE_LAHF: return pVM->cpum.s.GuestFeatures.fLahfSahf;
2343 case CPUMCPUIDFEATURE_LONG_MODE: return pVM->cpum.s.GuestFeatures.fLongMode;
2344 case CPUMCPUIDFEATURE_PAT: return pVM->cpum.s.GuestFeatures.fPat;
2345 case CPUMCPUIDFEATURE_RDTSCP: return pVM->cpum.s.GuestFeatures.fRdTscP;
2346 case CPUMCPUIDFEATURE_HVP: return pVM->cpum.s.GuestFeatures.fHypervisorPresent;
2347 case CPUMCPUIDFEATURE_MWAIT_EXTS: return pVM->cpum.s.GuestFeatures.fMWaitExtensions;
2348
2349 case CPUMCPUIDFEATURE_INVALID:
2350 case CPUMCPUIDFEATURE_32BIT_HACK:
2351 break;
2352 }
2353 AssertFailed();
2354 return false;
2355}
2356
2357
2358/**
2359 * Clears a CPUID feature bit.
2360 *
2361 * @param pVM Pointer to the VM.
2362 * @param enmFeature The feature to clear.
2363 */
2364VMMDECL(void) CPUMClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
2365{
2366 PCPUMCPUIDLEAF pLeaf;
2367 switch (enmFeature)
2368 {
2369 case CPUMCPUIDFEATURE_APIC:
2370 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2371 if (pLeaf)
2372 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx &= ~X86_CPUID_FEATURE_EDX_APIC;
2373
2374 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2375 if ( pLeaf
2376 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2377 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx &= ~X86_CPUID_AMD_FEATURE_EDX_APIC;
2378
2379 pVM->cpum.s.GuestFeatures.fApic = 0;
2380 Log(("CPUM: ClearGuestCpuIdFeature: Disabled APIC\n"));
2381 break;
2382
2383 case CPUMCPUIDFEATURE_X2APIC:
2384 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2385 if (pLeaf)
2386 pVM->cpum.s.aGuestCpuIdStd[1].ecx = pLeaf->uEcx &= ~X86_CPUID_FEATURE_ECX_X2APIC;
2387 pVM->cpum.s.GuestFeatures.fX2Apic = 0;
2388 Log(("CPUM: ClearGuestCpuIdFeature: Disabled x2APIC\n"));
2389 break;
2390
2391 case CPUMCPUIDFEATURE_PAE:
2392 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2393 if (pLeaf)
2394 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx &= ~X86_CPUID_FEATURE_EDX_PAE;
2395
2396 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2397 if ( pLeaf
2398 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2399 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx &= ~X86_CPUID_AMD_FEATURE_EDX_PAE;
2400
2401 pVM->cpum.s.GuestFeatures.fPae = 0;
2402 Log(("CPUM: ClearGuestCpuIdFeature: Disabled PAE!\n"));
2403 break;
2404
2405 case CPUMCPUIDFEATURE_PAT:
2406 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2407 if (pLeaf)
2408 pVM->cpum.s.aGuestCpuIdStd[1].edx = pLeaf->uEdx &= ~X86_CPUID_FEATURE_EDX_PAT;
2409
2410 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2411 if ( pLeaf
2412 && pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
2413 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx &= ~X86_CPUID_AMD_FEATURE_EDX_PAT;
2414
2415 pVM->cpum.s.GuestFeatures.fPat = 0;
2416 Log(("CPUM: ClearGuestCpuIdFeature: Disabled PAT!\n"));
2417 break;
2418
2419 case CPUMCPUIDFEATURE_LONG_MODE:
2420 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2421 if (pLeaf)
2422 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx &= ~X86_CPUID_EXT_FEATURE_EDX_LONG_MODE;
2423 pVM->cpum.s.GuestFeatures.fLongMode = 0;
2424 break;
2425
2426 case CPUMCPUIDFEATURE_LAHF:
2427 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2428 if (pLeaf)
2429 pVM->cpum.s.aGuestCpuIdExt[1].ecx = pLeaf->uEcx &= ~X86_CPUID_EXT_FEATURE_ECX_LAHF_SAHF;
2430 pVM->cpum.s.GuestFeatures.fLahfSahf = 0;
2431 break;
2432
2433 case CPUMCPUIDFEATURE_RDTSCP:
2434 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x80000001), 0);
2435 if (pLeaf)
2436 pVM->cpum.s.aGuestCpuIdExt[1].edx = pLeaf->uEdx &= ~X86_CPUID_EXT_FEATURE_EDX_RDTSCP;
2437 pVM->cpum.s.GuestFeatures.fRdTscP = 0;
2438 Log(("CPUM: ClearGuestCpuIdFeature: Disabled RDTSCP!\n"));
2439 break;
2440
2441 case CPUMCPUIDFEATURE_HVP:
2442 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000001), 0);
2443 if (pLeaf)
2444 pVM->cpum.s.aGuestCpuIdStd[1].ecx = pLeaf->uEcx &= ~X86_CPUID_FEATURE_ECX_HVP;
2445 pVM->cpum.s.GuestFeatures.fHypervisorPresent = 0;
2446 break;
2447
2448 case CPUMCPUIDFEATURE_MWAIT_EXTS:
2449 pLeaf = cpumCpuIdGetLeaf(pVM, UINT32_C(0x00000005), 0);
2450 if (pLeaf)
2451 pVM->cpum.s.aGuestCpuIdStd[5].ecx = pLeaf->uEcx &= ~(X86_CPUID_MWAIT_ECX_EXT | X86_CPUID_MWAIT_ECX_BREAKIRQIF0);
2452 pVM->cpum.s.GuestFeatures.fMWaitExtensions = 0;
2453 Log(("CPUM: ClearGuestCpuIdFeature: Disabled MWAIT Extensions!\n"));
2454 break;
2455
2456 default:
2457 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
2458 break;
2459 }
2460
2461 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2462 {
2463 PVMCPU pVCpu = &pVM->aCpus[i];
2464 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CPUID;
2465 }
2466}
2467
2468
2469/**
2470 * Gets the host CPU vendor.
2471 *
2472 * @returns CPU vendor.
2473 * @param pVM Pointer to the VM.
2474 */
2475VMMDECL(CPUMCPUVENDOR) CPUMGetHostCpuVendor(PVM pVM)
2476{
2477 return (CPUMCPUVENDOR)pVM->cpum.s.HostFeatures.enmCpuVendor;
2478}
2479
2480
2481/**
2482 * Gets the CPU vendor.
2483 *
2484 * @returns CPU vendor.
2485 * @param pVM Pointer to the VM.
2486 */
2487VMMDECL(CPUMCPUVENDOR) CPUMGetGuestCpuVendor(PVM pVM)
2488{
2489 return (CPUMCPUVENDOR)pVM->cpum.s.GuestFeatures.enmCpuVendor;
2490}
2491
2492
2493VMMDECL(int) CPUMSetGuestDR0(PVMCPU pVCpu, uint64_t uDr0)
2494{
2495 pVCpu->cpum.s.Guest.dr[0] = uDr0;
2496 return CPUMRecalcHyperDRx(pVCpu, 0, false);
2497}
2498
2499
2500VMMDECL(int) CPUMSetGuestDR1(PVMCPU pVCpu, uint64_t uDr1)
2501{
2502 pVCpu->cpum.s.Guest.dr[1] = uDr1;
2503 return CPUMRecalcHyperDRx(pVCpu, 1, false);
2504}
2505
2506
2507VMMDECL(int) CPUMSetGuestDR2(PVMCPU pVCpu, uint64_t uDr2)
2508{
2509 pVCpu->cpum.s.Guest.dr[2] = uDr2;
2510 return CPUMRecalcHyperDRx(pVCpu, 2, false);
2511}
2512
2513
2514VMMDECL(int) CPUMSetGuestDR3(PVMCPU pVCpu, uint64_t uDr3)
2515{
2516 pVCpu->cpum.s.Guest.dr[3] = uDr3;
2517 return CPUMRecalcHyperDRx(pVCpu, 3, false);
2518}
2519
2520
2521VMMDECL(int) CPUMSetGuestDR6(PVMCPU pVCpu, uint64_t uDr6)
2522{
2523 pVCpu->cpum.s.Guest.dr[6] = uDr6;
2524 return VINF_SUCCESS; /* No need to recalc. */
2525}
2526
2527
2528VMMDECL(int) CPUMSetGuestDR7(PVMCPU pVCpu, uint64_t uDr7)
2529{
2530 pVCpu->cpum.s.Guest.dr[7] = uDr7;
2531 return CPUMRecalcHyperDRx(pVCpu, 7, false);
2532}
2533
2534
2535VMMDECL(int) CPUMSetGuestDRx(PVMCPU pVCpu, uint32_t iReg, uint64_t Value)
2536{
2537 AssertReturn(iReg <= DISDREG_DR7, VERR_INVALID_PARAMETER);
2538 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
2539 if (iReg == 4 || iReg == 5)
2540 iReg += 2;
2541 pVCpu->cpum.s.Guest.dr[iReg] = Value;
2542 return CPUMRecalcHyperDRx(pVCpu, iReg, false);
2543}
2544
2545
2546/**
2547 * Recalculates the hypervisor DRx register values based on current guest
2548 * registers and DBGF breakpoints, updating changed registers depending on the
2549 * context.
2550 *
2551 * This is called whenever a guest DRx register is modified (any context) and
2552 * when DBGF sets a hardware breakpoint (ring-3 only, rendezvous).
2553 *
2554 * In raw-mode context this function will reload any (hyper) DRx registers which
2555 * comes out with a different value. It may also have to save the host debug
2556 * registers if that haven't been done already. In this context though, we'll
2557 * be intercepting and emulating all DRx accesses, so the hypervisor DRx values
2558 * are only important when breakpoints are actually enabled.
2559 *
2560 * In ring-0 (HM) context DR0-3 will be relocated by us, while DR7 will be
2561 * reloaded by the HM code if it changes. Further more, we will only use the
2562 * combined register set when the VBox debugger is actually using hardware BPs,
2563 * when it isn't we'll keep the guest DR0-3 + (maybe) DR6 loaded (DR6 doesn't
2564 * concern us here).
2565 *
2566 * In ring-3 we won't be loading anything, so well calculate hypervisor values
2567 * all the time.
2568 *
2569 * @returns VINF_SUCCESS.
2570 * @param pVCpu Pointer to the VMCPU.
2571 * @param iGstReg The guest debug register number that was modified.
2572 * UINT8_MAX if not guest register.
2573 * @param fForceHyper Used in HM to force hyper registers because of single
2574 * stepping.
2575 */
2576VMMDECL(int) CPUMRecalcHyperDRx(PVMCPU pVCpu, uint8_t iGstReg, bool fForceHyper)
2577{
2578 PVM pVM = pVCpu->CTX_SUFF(pVM);
2579
2580 /*
2581 * Compare the DR7s first.
2582 *
2583 * We only care about the enabled flags. GD is virtualized when we
2584 * dispatch the #DB, we never enable it. The DBGF DR7 value is will
2585 * always have the LE and GE bits set, so no need to check and disable
2586 * stuff if they're cleared like we have to for the guest DR7.
2587 */
2588 RTGCUINTREG uGstDr7 = CPUMGetGuestDR7(pVCpu);
2589 if (!(uGstDr7 & (X86_DR7_LE | X86_DR7_GE)))
2590 uGstDr7 = 0;
2591 else if (!(uGstDr7 & X86_DR7_LE))
2592 uGstDr7 &= ~X86_DR7_LE_ALL;
2593 else if (!(uGstDr7 & X86_DR7_GE))
2594 uGstDr7 &= ~X86_DR7_GE_ALL;
2595
2596 const RTGCUINTREG uDbgfDr7 = DBGFBpGetDR7(pVM);
2597
2598#ifdef IN_RING0
2599 if (!fForceHyper && (pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HYPER))
2600 fForceHyper = true;
2601#endif
2602 if (( HMIsEnabled(pVCpu->CTX_SUFF(pVM)) && !fForceHyper ? uDbgfDr7 : (uGstDr7 | uDbgfDr7)) & X86_DR7_ENABLED_MASK)
2603 {
2604 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
2605#ifdef IN_RC
2606 bool const fHmEnabled = false;
2607#elif defined(IN_RING3)
2608 bool const fHmEnabled = HMIsEnabled(pVM);
2609#endif
2610
2611 /*
2612 * Ok, something is enabled. Recalc each of the breakpoints, taking
2613 * the VM debugger ones of the guest ones. In raw-mode context we will
2614 * not allow breakpoints with values inside the hypervisor area.
2615 */
2616 RTGCUINTREG uNewDr7 = X86_DR7_GE | X86_DR7_LE | X86_DR7_RA1_MASK;
2617
2618 /* bp 0 */
2619 RTGCUINTREG uNewDr0;
2620 if (uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0))
2621 {
2622 uNewDr7 |= uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
2623 uNewDr0 = DBGFBpGetDR0(pVM);
2624 }
2625 else if (uGstDr7 & (X86_DR7_L0 | X86_DR7_G0))
2626 {
2627 uNewDr0 = CPUMGetGuestDR0(pVCpu);
2628#ifndef IN_RING0
2629 if (fHmEnabled && MMHyperIsInsideArea(pVM, uNewDr0))
2630 uNewDr0 = 0;
2631 else
2632#endif
2633 uNewDr7 |= uGstDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
2634 }
2635 else
2636 uNewDr0 = 0;
2637
2638 /* bp 1 */
2639 RTGCUINTREG uNewDr1;
2640 if (uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1))
2641 {
2642 uNewDr7 |= uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
2643 uNewDr1 = DBGFBpGetDR1(pVM);
2644 }
2645 else if (uGstDr7 & (X86_DR7_L1 | X86_DR7_G1))
2646 {
2647 uNewDr1 = CPUMGetGuestDR1(pVCpu);
2648#ifndef IN_RING0
2649 if (fHmEnabled && MMHyperIsInsideArea(pVM, uNewDr1))
2650 uNewDr1 = 0;
2651 else
2652#endif
2653 uNewDr7 |= uGstDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
2654 }
2655 else
2656 uNewDr1 = 0;
2657
2658 /* bp 2 */
2659 RTGCUINTREG uNewDr2;
2660 if (uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2))
2661 {
2662 uNewDr7 |= uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
2663 uNewDr2 = DBGFBpGetDR2(pVM);
2664 }
2665 else if (uGstDr7 & (X86_DR7_L2 | X86_DR7_G2))
2666 {
2667 uNewDr2 = CPUMGetGuestDR2(pVCpu);
2668#ifndef IN_RING0
2669 if (fHmEnabled && MMHyperIsInsideArea(pVM, uNewDr2))
2670 uNewDr2 = 0;
2671 else
2672#endif
2673 uNewDr7 |= uGstDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
2674 }
2675 else
2676 uNewDr2 = 0;
2677
2678 /* bp 3 */
2679 RTGCUINTREG uNewDr3;
2680 if (uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3))
2681 {
2682 uNewDr7 |= uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
2683 uNewDr3 = DBGFBpGetDR3(pVM);
2684 }
2685 else if (uGstDr7 & (X86_DR7_L3 | X86_DR7_G3))
2686 {
2687 uNewDr3 = CPUMGetGuestDR3(pVCpu);
2688#ifndef IN_RING0
2689 if (fHmEnabled && MMHyperIsInsideArea(pVM, uNewDr3))
2690 uNewDr3 = 0;
2691 else
2692#endif
2693 uNewDr7 |= uGstDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
2694 }
2695 else
2696 uNewDr3 = 0;
2697
2698 /*
2699 * Apply the updates.
2700 */
2701#ifdef IN_RC
2702 /* Make sure to save host registers first. */
2703 if (!(pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HOST))
2704 {
2705 if (!(pVCpu->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS_HOST))
2706 {
2707 pVCpu->cpum.s.Host.dr6 = ASMGetDR6();
2708 pVCpu->cpum.s.Host.dr7 = ASMGetDR7();
2709 }
2710 pVCpu->cpum.s.Host.dr0 = ASMGetDR0();
2711 pVCpu->cpum.s.Host.dr1 = ASMGetDR1();
2712 pVCpu->cpum.s.Host.dr2 = ASMGetDR2();
2713 pVCpu->cpum.s.Host.dr3 = ASMGetDR3();
2714 pVCpu->cpum.s.fUseFlags |= CPUM_USED_DEBUG_REGS_HOST | CPUM_USE_DEBUG_REGS_HYPER | CPUM_USED_DEBUG_REGS_HYPER;
2715
2716 /* We haven't loaded any hyper DRxes yet, so we'll have to load them all now. */
2717 pVCpu->cpum.s.Hyper.dr[0] = uNewDr0;
2718 ASMSetDR0(uNewDr0);
2719 pVCpu->cpum.s.Hyper.dr[1] = uNewDr1;
2720 ASMSetDR1(uNewDr1);
2721 pVCpu->cpum.s.Hyper.dr[2] = uNewDr2;
2722 ASMSetDR2(uNewDr2);
2723 pVCpu->cpum.s.Hyper.dr[3] = uNewDr3;
2724 ASMSetDR3(uNewDr3);
2725 ASMSetDR6(X86_DR6_INIT_VAL);
2726 pVCpu->cpum.s.Hyper.dr[7] = uNewDr7;
2727 ASMSetDR7(uNewDr7);
2728 }
2729 else
2730#endif
2731 {
2732 pVCpu->cpum.s.fUseFlags |= CPUM_USE_DEBUG_REGS_HYPER;
2733 if (uNewDr3 != pVCpu->cpum.s.Hyper.dr[3])
2734 CPUMSetHyperDR3(pVCpu, uNewDr3);
2735 if (uNewDr2 != pVCpu->cpum.s.Hyper.dr[2])
2736 CPUMSetHyperDR2(pVCpu, uNewDr2);
2737 if (uNewDr1 != pVCpu->cpum.s.Hyper.dr[1])
2738 CPUMSetHyperDR1(pVCpu, uNewDr1);
2739 if (uNewDr0 != pVCpu->cpum.s.Hyper.dr[0])
2740 CPUMSetHyperDR0(pVCpu, uNewDr0);
2741 if (uNewDr7 != pVCpu->cpum.s.Hyper.dr[7])
2742 CPUMSetHyperDR7(pVCpu, uNewDr7);
2743 }
2744 }
2745#ifdef IN_RING0
2746 else if (CPUMIsGuestDebugStateActive(pVCpu))
2747 {
2748 /*
2749 * Reload the register that was modified. Normally this won't happen
2750 * as we won't intercept DRx writes when not having the hyper debug
2751 * state loaded, but in case we do for some reason we'll simply deal
2752 * with it.
2753 */
2754 switch (iGstReg)
2755 {
2756 case 0: ASMSetDR0(CPUMGetGuestDR0(pVCpu)); break;
2757 case 1: ASMSetDR1(CPUMGetGuestDR1(pVCpu)); break;
2758 case 2: ASMSetDR2(CPUMGetGuestDR2(pVCpu)); break;
2759 case 3: ASMSetDR3(CPUMGetGuestDR3(pVCpu)); break;
2760 default:
2761 AssertReturn(iGstReg != UINT8_MAX, VERR_INTERNAL_ERROR_3);
2762 }
2763 }
2764#endif
2765 else
2766 {
2767 /*
2768 * No active debug state any more. In raw-mode this means we have to
2769 * make sure DR7 has everything disabled now, if we armed it already.
2770 * In ring-0 we might end up here when just single stepping.
2771 */
2772#if defined(IN_RC) || defined(IN_RING0)
2773 if (pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HYPER)
2774 {
2775# ifdef IN_RC
2776 ASMSetDR7(X86_DR7_INIT_VAL);
2777# endif
2778 if (pVCpu->cpum.s.Hyper.dr[0])
2779 ASMSetDR0(0);
2780 if (pVCpu->cpum.s.Hyper.dr[1])
2781 ASMSetDR1(0);
2782 if (pVCpu->cpum.s.Hyper.dr[2])
2783 ASMSetDR2(0);
2784 if (pVCpu->cpum.s.Hyper.dr[3])
2785 ASMSetDR3(0);
2786 pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_DEBUG_REGS_HYPER;
2787 }
2788#endif
2789 pVCpu->cpum.s.fUseFlags &= ~CPUM_USE_DEBUG_REGS_HYPER;
2790
2791 /* Clear all the registers. */
2792 pVCpu->cpum.s.Hyper.dr[7] = X86_DR7_RA1_MASK;
2793 pVCpu->cpum.s.Hyper.dr[3] = 0;
2794 pVCpu->cpum.s.Hyper.dr[2] = 0;
2795 pVCpu->cpum.s.Hyper.dr[1] = 0;
2796 pVCpu->cpum.s.Hyper.dr[0] = 0;
2797
2798 }
2799 Log2(("CPUMRecalcHyperDRx: fUseFlags=%#x %RGr %RGr %RGr %RGr %RGr %RGr\n",
2800 pVCpu->cpum.s.fUseFlags, pVCpu->cpum.s.Hyper.dr[0], pVCpu->cpum.s.Hyper.dr[1],
2801 pVCpu->cpum.s.Hyper.dr[2], pVCpu->cpum.s.Hyper.dr[3], pVCpu->cpum.s.Hyper.dr[6],
2802 pVCpu->cpum.s.Hyper.dr[7]));
2803
2804 return VINF_SUCCESS;
2805}
2806
2807
2808/**
2809 * Tests if the guest has No-Execute Page Protection Enabled (NXE).
2810 *
2811 * @returns true if in real mode, otherwise false.
2812 * @param pVCpu Pointer to the VMCPU.
2813 */
2814VMMDECL(bool) CPUMIsGuestNXEnabled(PVMCPU pVCpu)
2815{
2816 return !!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_NXE);
2817}
2818
2819
2820/**
2821 * Tests if the guest has the Page Size Extension enabled (PSE).
2822 *
2823 * @returns true if in real mode, otherwise false.
2824 * @param pVCpu Pointer to the VMCPU.
2825 */
2826VMMDECL(bool) CPUMIsGuestPageSizeExtEnabled(PVMCPU pVCpu)
2827{
2828 /* PAE or AMD64 implies support for big pages regardless of CR4.PSE */
2829 return !!(pVCpu->cpum.s.Guest.cr4 & (X86_CR4_PSE | X86_CR4_PAE));
2830}
2831
2832
2833/**
2834 * Tests if the guest has the paging enabled (PG).
2835 *
2836 * @returns true if in real mode, otherwise false.
2837 * @param pVCpu Pointer to the VMCPU.
2838 */
2839VMMDECL(bool) CPUMIsGuestPagingEnabled(PVMCPU pVCpu)
2840{
2841 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PG);
2842}
2843
2844
2845/**
2846 * Tests if the guest has the paging enabled (PG).
2847 *
2848 * @returns true if in real mode, otherwise false.
2849 * @param pVCpu Pointer to the VMCPU.
2850 */
2851VMMDECL(bool) CPUMIsGuestR0WriteProtEnabled(PVMCPU pVCpu)
2852{
2853 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_WP);
2854}
2855
2856
2857/**
2858 * Tests if the guest is running in real mode or not.
2859 *
2860 * @returns true if in real mode, otherwise false.
2861 * @param pVCpu Pointer to the VMCPU.
2862 */
2863VMMDECL(bool) CPUMIsGuestInRealMode(PVMCPU pVCpu)
2864{
2865 return !(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE);
2866}
2867
2868
2869/**
2870 * Tests if the guest is running in real or virtual 8086 mode.
2871 *
2872 * @returns @c true if it is, @c false if not.
2873 * @param pVCpu Pointer to the VMCPU.
2874 */
2875VMMDECL(bool) CPUMIsGuestInRealOrV86Mode(PVMCPU pVCpu)
2876{
2877 return !(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE)
2878 || pVCpu->cpum.s.Guest.eflags.Bits.u1VM; /** @todo verify that this cannot be set in long mode. */
2879}
2880
2881
2882/**
2883 * Tests if the guest is running in protected or not.
2884 *
2885 * @returns true if in protected mode, otherwise false.
2886 * @param pVCpu Pointer to the VMCPU.
2887 */
2888VMMDECL(bool) CPUMIsGuestInProtectedMode(PVMCPU pVCpu)
2889{
2890 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE);
2891}
2892
2893
2894/**
2895 * Tests if the guest is running in paged protected or not.
2896 *
2897 * @returns true if in paged protected mode, otherwise false.
2898 * @param pVCpu Pointer to the VMCPU.
2899 */
2900VMMDECL(bool) CPUMIsGuestInPagedProtectedMode(PVMCPU pVCpu)
2901{
2902 return (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG);
2903}
2904
2905
2906/**
2907 * Tests if the guest is running in long mode or not.
2908 *
2909 * @returns true if in long mode, otherwise false.
2910 * @param pVCpu Pointer to the VMCPU.
2911 */
2912VMMDECL(bool) CPUMIsGuestInLongMode(PVMCPU pVCpu)
2913{
2914 return (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA) == MSR_K6_EFER_LMA;
2915}
2916
2917
2918/**
2919 * Tests if the guest is running in PAE mode or not.
2920 *
2921 * @returns true if in PAE mode, otherwise false.
2922 * @param pVCpu Pointer to the VMCPU.
2923 */
2924VMMDECL(bool) CPUMIsGuestInPAEMode(PVMCPU pVCpu)
2925{
2926 /* Intel mentions EFER.LMA and EFER.LME in different parts of their spec. We shall use EFER.LMA rather
2927 than EFER.LME as it reflects if the CPU has entered paging with EFER.LME set. */
2928 return (pVCpu->cpum.s.Guest.cr4 & X86_CR4_PAE)
2929 && (pVCpu->cpum.s.Guest.cr0 & X86_CR0_PG)
2930 && !(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA);
2931}
2932
2933
2934/**
2935 * Tests if the guest is running in 64 bits mode or not.
2936 *
2937 * @returns true if in 64 bits protected mode, otherwise false.
2938 * @param pVCpu The current virtual CPU.
2939 */
2940VMMDECL(bool) CPUMIsGuestIn64BitCode(PVMCPU pVCpu)
2941{
2942 if (!CPUMIsGuestInLongMode(pVCpu))
2943 return false;
2944 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
2945 return pVCpu->cpum.s.Guest.cs.Attr.n.u1Long;
2946}
2947
2948
2949/**
2950 * Helper for CPUMIsGuestIn64BitCodeEx that handles lazy resolving of hidden CS
2951 * registers.
2952 *
2953 * @returns true if in 64 bits protected mode, otherwise false.
2954 * @param pCtx Pointer to the current guest CPU context.
2955 */
2956VMM_INT_DECL(bool) CPUMIsGuestIn64BitCodeSlow(PCPUMCTX pCtx)
2957{
2958 return CPUMIsGuestIn64BitCode(CPUM_GUEST_CTX_TO_VMCPU(pCtx));
2959}
2960
2961#ifdef VBOX_WITH_RAW_MODE_NOT_R0
2962
2963/**
2964 *
2965 * @returns @c true if we've entered raw-mode and selectors with RPL=1 are
2966 * really RPL=0, @c false if we've not (RPL=1 really is RPL=1).
2967 * @param pVCpu The current virtual CPU.
2968 */
2969VMM_INT_DECL(bool) CPUMIsGuestInRawMode(PVMCPU pVCpu)
2970{
2971 return pVCpu->cpum.s.fRawEntered;
2972}
2973
2974/**
2975 * Transforms the guest CPU state to raw-ring mode.
2976 *
2977 * This function will change the any of the cs and ss register with DPL=0 to DPL=1.
2978 *
2979 * @returns VBox status. (recompiler failure)
2980 * @param pVCpu Pointer to the VMCPU.
2981 * @param pCtxCore The context core (for trap usage).
2982 * @see @ref pg_raw
2983 */
2984VMM_INT_DECL(int) CPUMRawEnter(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
2985{
2986 PVM pVM = pVCpu->CTX_SUFF(pVM);
2987
2988 Assert(!pVCpu->cpum.s.fRawEntered);
2989 Assert(!pVCpu->cpum.s.fRemEntered);
2990 if (!pCtxCore)
2991 pCtxCore = CPUMCTX2CORE(&pVCpu->cpum.s.Guest);
2992
2993 /*
2994 * Are we in Ring-0?
2995 */
2996 if ( pCtxCore->ss.Sel
2997 && (pCtxCore->ss.Sel & X86_SEL_RPL) == 0
2998 && !pCtxCore->eflags.Bits.u1VM)
2999 {
3000 /*
3001 * Enter execution mode.
3002 */
3003 PATMRawEnter(pVM, pCtxCore);
3004
3005 /*
3006 * Set CPL to Ring-1.
3007 */
3008 pCtxCore->ss.Sel |= 1;
3009 if ( pCtxCore->cs.Sel
3010 && (pCtxCore->cs.Sel & X86_SEL_RPL) == 0)
3011 pCtxCore->cs.Sel |= 1;
3012 }
3013 else
3014 {
3015# ifdef VBOX_WITH_RAW_RING1
3016 if ( EMIsRawRing1Enabled(pVM)
3017 && !pCtxCore->eflags.Bits.u1VM
3018 && (pCtxCore->ss.Sel & X86_SEL_RPL) == 1)
3019 {
3020 /* Set CPL to Ring-2. */
3021 pCtxCore->ss.Sel = (pCtxCore->ss.Sel & ~X86_SEL_RPL) | 2;
3022 if (pCtxCore->cs.Sel && (pCtxCore->cs.Sel & X86_SEL_RPL) == 1)
3023 pCtxCore->cs.Sel = (pCtxCore->cs.Sel & ~X86_SEL_RPL) | 2;
3024 }
3025# else
3026 AssertMsg((pCtxCore->ss.Sel & X86_SEL_RPL) >= 2 || pCtxCore->eflags.Bits.u1VM,
3027 ("ring-1 code not supported\n"));
3028# endif
3029 /*
3030 * PATM takes care of IOPL and IF flags for Ring-3 and Ring-2 code as well.
3031 */
3032 PATMRawEnter(pVM, pCtxCore);
3033 }
3034
3035 /*
3036 * Assert sanity.
3037 */
3038 AssertMsg((pCtxCore->eflags.u32 & X86_EFL_IF), ("X86_EFL_IF is clear\n"));
3039 AssertReleaseMsg(pCtxCore->eflags.Bits.u2IOPL == 0,
3040 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss.Sel & X86_SEL_RPL));
3041 Assert((pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) == (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP));
3042
3043 pCtxCore->eflags.u32 |= X86_EFL_IF; /* paranoia */
3044
3045 pVCpu->cpum.s.fRawEntered = true;
3046 return VINF_SUCCESS;
3047}
3048
3049
3050/**
3051 * Transforms the guest CPU state from raw-ring mode to correct values.
3052 *
3053 * This function will change any selector registers with DPL=1 to DPL=0.
3054 *
3055 * @returns Adjusted rc.
3056 * @param pVCpu Pointer to the VMCPU.
3057 * @param rc Raw mode return code
3058 * @param pCtxCore The context core (for trap usage).
3059 * @see @ref pg_raw
3060 */
3061VMM_INT_DECL(int) CPUMRawLeave(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, int rc)
3062{
3063 PVM pVM = pVCpu->CTX_SUFF(pVM);
3064
3065 /*
3066 * Don't leave if we've already left (in RC).
3067 */
3068 Assert(!pVCpu->cpum.s.fRemEntered);
3069 if (!pVCpu->cpum.s.fRawEntered)
3070 return rc;
3071 pVCpu->cpum.s.fRawEntered = false;
3072
3073 PCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
3074 if (!pCtxCore)
3075 pCtxCore = CPUMCTX2CORE(pCtx);
3076 Assert(pCtxCore->eflags.Bits.u1VM || (pCtxCore->ss.Sel & X86_SEL_RPL));
3077 AssertMsg(pCtxCore->eflags.Bits.u1VM || pCtxCore->eflags.Bits.u2IOPL < (unsigned)(pCtxCore->ss.Sel & X86_SEL_RPL),
3078 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss.Sel & X86_SEL_RPL));
3079
3080 /*
3081 * Are we executing in raw ring-1?
3082 */
3083 if ( (pCtxCore->ss.Sel & X86_SEL_RPL) == 1
3084 && !pCtxCore->eflags.Bits.u1VM)
3085 {
3086 /*
3087 * Leave execution mode.
3088 */
3089 PATMRawLeave(pVM, pCtxCore, rc);
3090 /* Not quite sure if this is really required, but shouldn't harm (too much anyways). */
3091 /** @todo See what happens if we remove this. */
3092 if ((pCtxCore->ds.Sel & X86_SEL_RPL) == 1)
3093 pCtxCore->ds.Sel &= ~X86_SEL_RPL;
3094 if ((pCtxCore->es.Sel & X86_SEL_RPL) == 1)
3095 pCtxCore->es.Sel &= ~X86_SEL_RPL;
3096 if ((pCtxCore->fs.Sel & X86_SEL_RPL) == 1)
3097 pCtxCore->fs.Sel &= ~X86_SEL_RPL;
3098 if ((pCtxCore->gs.Sel & X86_SEL_RPL) == 1)
3099 pCtxCore->gs.Sel &= ~X86_SEL_RPL;
3100
3101 /*
3102 * Ring-1 selector => Ring-0.
3103 */
3104 pCtxCore->ss.Sel &= ~X86_SEL_RPL;
3105 if ((pCtxCore->cs.Sel & X86_SEL_RPL) == 1)
3106 pCtxCore->cs.Sel &= ~X86_SEL_RPL;
3107 }
3108 else
3109 {
3110 /*
3111 * PATM is taking care of the IOPL and IF flags for us.
3112 */
3113 PATMRawLeave(pVM, pCtxCore, rc);
3114 if (!pCtxCore->eflags.Bits.u1VM)
3115 {
3116# ifdef VBOX_WITH_RAW_RING1
3117 if ( EMIsRawRing1Enabled(pVM)
3118 && (pCtxCore->ss.Sel & X86_SEL_RPL) == 2)
3119 {
3120 /* Not quite sure if this is really required, but shouldn't harm (too much anyways). */
3121 /** @todo See what happens if we remove this. */
3122 if ((pCtxCore->ds.Sel & X86_SEL_RPL) == 2)
3123 pCtxCore->ds.Sel = (pCtxCore->ds.Sel & ~X86_SEL_RPL) | 1;
3124 if ((pCtxCore->es.Sel & X86_SEL_RPL) == 2)
3125 pCtxCore->es.Sel = (pCtxCore->es.Sel & ~X86_SEL_RPL) | 1;
3126 if ((pCtxCore->fs.Sel & X86_SEL_RPL) == 2)
3127 pCtxCore->fs.Sel = (pCtxCore->fs.Sel & ~X86_SEL_RPL) | 1;
3128 if ((pCtxCore->gs.Sel & X86_SEL_RPL) == 2)
3129 pCtxCore->gs.Sel = (pCtxCore->gs.Sel & ~X86_SEL_RPL) | 1;
3130
3131 /*
3132 * Ring-2 selector => Ring-1.
3133 */
3134 pCtxCore->ss.Sel = (pCtxCore->ss.Sel & ~X86_SEL_RPL) | 1;
3135 if ((pCtxCore->cs.Sel & X86_SEL_RPL) == 2)
3136 pCtxCore->cs.Sel = (pCtxCore->cs.Sel & ~X86_SEL_RPL) | 1;
3137 }
3138 else
3139 {
3140# endif
3141 /** @todo See what happens if we remove this. */
3142 if ((pCtxCore->ds.Sel & X86_SEL_RPL) == 1)
3143 pCtxCore->ds.Sel &= ~X86_SEL_RPL;
3144 if ((pCtxCore->es.Sel & X86_SEL_RPL) == 1)
3145 pCtxCore->es.Sel &= ~X86_SEL_RPL;
3146 if ((pCtxCore->fs.Sel & X86_SEL_RPL) == 1)
3147 pCtxCore->fs.Sel &= ~X86_SEL_RPL;
3148 if ((pCtxCore->gs.Sel & X86_SEL_RPL) == 1)
3149 pCtxCore->gs.Sel &= ~X86_SEL_RPL;
3150# ifdef VBOX_WITH_RAW_RING1
3151 }
3152# endif
3153 }
3154 }
3155
3156 return rc;
3157}
3158
3159#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
3160
3161/**
3162 * Updates the EFLAGS while we're in raw-mode.
3163 *
3164 * @param pVCpu Pointer to the VMCPU.
3165 * @param fEfl The new EFLAGS value.
3166 */
3167VMMDECL(void) CPUMRawSetEFlags(PVMCPU pVCpu, uint32_t fEfl)
3168{
3169#ifdef VBOX_WITH_RAW_MODE_NOT_R0
3170 if (pVCpu->cpum.s.fRawEntered)
3171 PATMRawSetEFlags(pVCpu->CTX_SUFF(pVM), CPUMCTX2CORE(&pVCpu->cpum.s.Guest), fEfl);
3172 else
3173#endif
3174 pVCpu->cpum.s.Guest.eflags.u32 = fEfl;
3175}
3176
3177
3178/**
3179 * Gets the EFLAGS while we're in raw-mode.
3180 *
3181 * @returns The eflags.
3182 * @param pVCpu Pointer to the current virtual CPU.
3183 */
3184VMMDECL(uint32_t) CPUMRawGetEFlags(PVMCPU pVCpu)
3185{
3186#ifdef VBOX_WITH_RAW_MODE_NOT_R0
3187 if (pVCpu->cpum.s.fRawEntered)
3188 return PATMRawGetEFlags(pVCpu->CTX_SUFF(pVM), CPUMCTX2CORE(&pVCpu->cpum.s.Guest));
3189#endif
3190 return pVCpu->cpum.s.Guest.eflags.u32;
3191}
3192
3193
3194/**
3195 * Sets the specified changed flags (CPUM_CHANGED_*).
3196 *
3197 * @param pVCpu Pointer to the current virtual CPU.
3198 */
3199VMMDECL(void) CPUMSetChangedFlags(PVMCPU pVCpu, uint32_t fChangedFlags)
3200{
3201 pVCpu->cpum.s.fChanged |= fChangedFlags;
3202}
3203
3204
3205/**
3206 * Checks if the CPU supports the FXSAVE and FXRSTOR instruction.
3207 * @returns true if supported.
3208 * @returns false if not supported.
3209 * @param pVM Pointer to the VM.
3210 */
3211VMMDECL(bool) CPUMSupportsFXSR(PVM pVM)
3212{
3213 return pVM->cpum.s.CPUFeatures.edx.u1FXSR != 0;
3214}
3215
3216
3217/**
3218 * Checks if the host OS uses the SYSENTER / SYSEXIT instructions.
3219 * @returns true if used.
3220 * @returns false if not used.
3221 * @param pVM Pointer to the VM.
3222 */
3223VMMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM)
3224{
3225 return RT_BOOL(pVM->cpum.s.fHostUseFlags & CPUM_USE_SYSENTER);
3226}
3227
3228
3229/**
3230 * Checks if the host OS uses the SYSCALL / SYSRET instructions.
3231 * @returns true if used.
3232 * @returns false if not used.
3233 * @param pVM Pointer to the VM.
3234 */
3235VMMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM)
3236{
3237 return RT_BOOL(pVM->cpum.s.fHostUseFlags & CPUM_USE_SYSCALL);
3238}
3239
3240#ifdef IN_RC
3241
3242/**
3243 * Lazily sync in the FPU/XMM state.
3244 *
3245 * @returns VBox status code.
3246 * @param pVCpu Pointer to the VMCPU.
3247 */
3248VMMDECL(int) CPUMHandleLazyFPU(PVMCPU pVCpu)
3249{
3250 return cpumHandleLazyFPUAsm(&pVCpu->cpum.s);
3251}
3252
3253#endif /* !IN_RC */
3254
3255/**
3256 * Checks if we activated the FPU/XMM state of the guest OS.
3257 * @returns true if we did.
3258 * @returns false if not.
3259 * @param pVCpu Pointer to the VMCPU.
3260 */
3261VMMDECL(bool) CPUMIsGuestFPUStateActive(PVMCPU pVCpu)
3262{
3263 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU);
3264}
3265
3266
3267/**
3268 * Deactivate the FPU/XMM state of the guest OS.
3269 * @param pVCpu Pointer to the VMCPU.
3270 *
3271 * @todo r=bird: Why is this needed? Looks like a workaround for mishandled
3272 * FPU state management.
3273 */
3274VMMDECL(void) CPUMDeactivateGuestFPUState(PVMCPU pVCpu)
3275{
3276 Assert(!(pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU));
3277 pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_FPU;
3278}
3279
3280
3281/**
3282 * Checks if the guest debug state is active.
3283 *
3284 * @returns boolean
3285 * @param pVM Pointer to the VMCPU.
3286 */
3287VMMDECL(bool) CPUMIsGuestDebugStateActive(PVMCPU pVCpu)
3288{
3289 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_GUEST);
3290}
3291
3292
3293/**
3294 * Checks if the guest debug state is to be made active during the world-switch
3295 * (currently only used for the 32->64 switcher case).
3296 *
3297 * @returns boolean
3298 * @param pVM Pointer to the VMCPU.
3299 */
3300VMMDECL(bool) CPUMIsGuestDebugStateActivePending(PVMCPU pVCpu)
3301{
3302 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_SYNC_DEBUG_REGS_GUEST);
3303}
3304
3305
3306/**
3307 * Checks if the hyper debug state is active.
3308 *
3309 * @returns boolean
3310 * @param pVM Pointer to the VM.
3311 */
3312VMMDECL(bool) CPUMIsHyperDebugStateActive(PVMCPU pVCpu)
3313{
3314 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HYPER);
3315}
3316
3317
3318/**
3319 * Checks if the hyper debug state is to be made active during the world-switch
3320 * (currently only used for the 32->64 switcher case).
3321 *
3322 * @returns boolean
3323 * @param pVM Pointer to the VMCPU.
3324 */
3325VMMDECL(bool) CPUMIsHyperDebugStateActivePending(PVMCPU pVCpu)
3326{
3327 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_SYNC_DEBUG_REGS_HYPER);
3328}
3329
3330
3331/**
3332 * Mark the guest's debug state as inactive.
3333 *
3334 * @returns boolean
3335 * @param pVM Pointer to the VM.
3336 * @todo This API doesn't make sense any more.
3337 */
3338VMMDECL(void) CPUMDeactivateGuestDebugState(PVMCPU pVCpu)
3339{
3340 Assert(!(pVCpu->cpum.s.fUseFlags & (CPUM_USED_DEBUG_REGS_GUEST | CPUM_USED_DEBUG_REGS_HYPER | CPUM_USED_DEBUG_REGS_HOST)));
3341}
3342
3343
3344/**
3345 * Get the current privilege level of the guest.
3346 *
3347 * @returns CPL
3348 * @param pVCpu Pointer to the current virtual CPU.
3349 */
3350VMMDECL(uint32_t) CPUMGetGuestCPL(PVMCPU pVCpu)
3351{
3352 /*
3353 * CPL can reliably be found in SS.DPL (hidden regs valid) or SS if not.
3354 *
3355 * Note! We used to check CS.DPL here, assuming it was always equal to
3356 * CPL even if a conforming segment was loaded. But this truned out to
3357 * only apply to older AMD-V. With VT-x we had an ACP2 regression
3358 * during install after a far call to ring 2 with VT-x. Then on newer
3359 * AMD-V CPUs we have to move the VMCB.guest.u8CPL into cs.Attr.n.u2Dpl
3360 * as well as ss.Attr.n.u2Dpl to make this (and other) code work right.
3361 *
3362 * So, forget CS.DPL, always use SS.DPL.
3363 *
3364 * Note! The SS RPL is always equal to the CPL, while the CS RPL
3365 * isn't necessarily equal if the segment is conforming.
3366 * See section 4.11.1 in the AMD manual.
3367 *
3368 * Update: Where the heck does it say CS.RPL can differ from CPL other than
3369 * right after real->prot mode switch and when in V8086 mode? That
3370 * section says the RPL specified in a direct transfere (call, jmp,
3371 * ret) is not the one loaded into CS. Besides, if CS.RPL != CPL
3372 * it would be impossible for an exception handle or the iret
3373 * instruction to figure out whether SS:ESP are part of the frame
3374 * or not. VBox or qemu bug must've lead to this misconception.
3375 *
3376 * Update2: On an AMD bulldozer system here, I've no trouble loading a null
3377 * selector into SS with an RPL other than the CPL when CPL != 3 and
3378 * we're in 64-bit mode. The intel dev box doesn't allow this, on
3379 * RPL = CPL. Weird.
3380 */
3381 uint32_t uCpl;
3382 if (pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE)
3383 {
3384 if (!pVCpu->cpum.s.Guest.eflags.Bits.u1VM)
3385 {
3386 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.s.Guest.ss))
3387 uCpl = pVCpu->cpum.s.Guest.ss.Attr.n.u2Dpl;
3388 else
3389 {
3390 uCpl = (pVCpu->cpum.s.Guest.ss.Sel & X86_SEL_RPL);
3391#ifdef VBOX_WITH_RAW_MODE_NOT_R0
3392# ifdef VBOX_WITH_RAW_RING1
3393 if (pVCpu->cpum.s.fRawEntered)
3394 {
3395 if ( uCpl == 2
3396 && EMIsRawRing1Enabled(pVCpu->CTX_SUFF(pVM)))
3397 uCpl = 1;
3398 else if (uCpl == 1)
3399 uCpl = 0;
3400 }
3401 Assert(uCpl != 2); /* ring 2 support not allowed anymore. */
3402# else
3403 if (uCpl == 1)
3404 uCpl = 0;
3405# endif
3406#endif
3407 }
3408 }
3409 else
3410 uCpl = 3; /* V86 has CPL=3; REM doesn't set DPL=3 in V8086 mode. See @bugref{5130}. */
3411 }
3412 else
3413 uCpl = 0; /* Real mode is zero; CPL set to 3 for VT-x real-mode emulation. */
3414 return uCpl;
3415}
3416
3417
3418/**
3419 * Gets the current guest CPU mode.
3420 *
3421 * If paging mode is what you need, check out PGMGetGuestMode().
3422 *
3423 * @returns The CPU mode.
3424 * @param pVCpu Pointer to the VMCPU.
3425 */
3426VMMDECL(CPUMMODE) CPUMGetGuestMode(PVMCPU pVCpu)
3427{
3428 CPUMMODE enmMode;
3429 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
3430 enmMode = CPUMMODE_REAL;
3431 else if (!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
3432 enmMode = CPUMMODE_PROTECTED;
3433 else
3434 enmMode = CPUMMODE_LONG;
3435
3436 return enmMode;
3437}
3438
3439
3440/**
3441 * Figure whether the CPU is currently executing 16, 32 or 64 bit code.
3442 *
3443 * @returns 16, 32 or 64.
3444 * @param pVCpu The current virtual CPU.
3445 */
3446VMMDECL(uint32_t) CPUMGetGuestCodeBits(PVMCPU pVCpu)
3447{
3448 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
3449 return 16;
3450
3451 if (pVCpu->cpum.s.Guest.eflags.Bits.u1VM)
3452 {
3453 Assert(!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA));
3454 return 16;
3455 }
3456
3457 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
3458 if ( pVCpu->cpum.s.Guest.cs.Attr.n.u1Long
3459 && (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
3460 return 64;
3461
3462 if (pVCpu->cpum.s.Guest.cs.Attr.n.u1DefBig)
3463 return 32;
3464
3465 return 16;
3466}
3467
3468
3469VMMDECL(DISCPUMODE) CPUMGetGuestDisMode(PVMCPU pVCpu)
3470{
3471 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
3472 return DISCPUMODE_16BIT;
3473
3474 if (pVCpu->cpum.s.Guest.eflags.Bits.u1VM)
3475 {
3476 Assert(!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA));
3477 return DISCPUMODE_16BIT;
3478 }
3479
3480 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
3481 if ( pVCpu->cpum.s.Guest.cs.Attr.n.u1Long
3482 && (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
3483 return DISCPUMODE_64BIT;
3484
3485 if (pVCpu->cpum.s.Guest.cs.Attr.n.u1DefBig)
3486 return DISCPUMODE_32BIT;
3487
3488 return DISCPUMODE_16BIT;
3489}
3490
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette