VirtualBox

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

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

VMM: Retire aGuestCpuIdHyper legacy array.

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