VirtualBox

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

Last change on this file since 92918 was 92541, checked in by vboxsync, 3 years ago

VMM: Nested VMX: bugref:10092 Allow forcing mapping/unmapping of CR3 even when the paging mode deosn't actually change. This is required for VMX/SVM guest transitions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 99.1 KB
Line 
1/* $Id: CPUMAllRegs.cpp 92541 2021-11-22 06:35:38Z vboxsync $ */
2/** @file
3 * CPUM - CPU Monitor(/Manager) - Getters and Setters.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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/dbgf.h>
25#include <VBox/vmm/apic.h>
26#include <VBox/vmm/pgm.h>
27#include <VBox/vmm/mm.h>
28#include <VBox/vmm/em.h>
29#include <VBox/vmm/nem.h>
30#include <VBox/vmm/hm.h>
31#include "CPUMInternal.h"
32#include <VBox/vmm/vmcc.h>
33#include <VBox/err.h>
34#include <VBox/dis.h>
35#include <VBox/log.h>
36#include <VBox/vmm/hm.h>
37#include <VBox/vmm/tm.h>
38#include <iprt/assert.h>
39#include <iprt/asm.h>
40#include <iprt/asm-amd64-x86.h>
41#ifdef IN_RING3
42# include <iprt/thread.h>
43#endif
44
45/** Disable stack frame pointer generation here. */
46#if defined(_MSC_VER) && !defined(DEBUG) && defined(RT_ARCH_X86)
47# pragma optimize("y", off)
48#endif
49
50AssertCompile2MemberOffsets(VM, cpum.s.HostFeatures, cpum.ro.HostFeatures);
51AssertCompile2MemberOffsets(VM, cpum.s.GuestFeatures, cpum.ro.GuestFeatures);
52
53
54/*********************************************************************************************************************************
55* Defined Constants And Macros *
56*********************************************************************************************************************************/
57/**
58 * Converts a CPUMCPU::Guest pointer into a VMCPU pointer.
59 *
60 * @returns Pointer to the Virtual CPU.
61 * @param a_pGuestCtx Pointer to the guest context.
62 */
63#define CPUM_GUEST_CTX_TO_VMCPU(a_pGuestCtx) RT_FROM_MEMBER(a_pGuestCtx, VMCPU, cpum.s.Guest)
64
65/**
66 * Lazily loads the hidden parts of a selector register when using raw-mode.
67 */
68#define CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(a_pVCpu, a_pSReg) \
69 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(a_pVCpu, a_pSReg))
70
71/** @def CPUM_INT_ASSERT_NOT_EXTRN
72 * Macro for asserting that @a a_fNotExtrn are present.
73 *
74 * @param a_pVCpu The cross context virtual CPU structure of the calling EMT.
75 * @param a_fNotExtrn Mask of CPUMCTX_EXTRN_XXX bits to check.
76 */
77#define CPUM_INT_ASSERT_NOT_EXTRN(a_pVCpu, a_fNotExtrn) \
78 AssertMsg(!((a_pVCpu)->cpum.s.Guest.fExtrn & (a_fNotExtrn)), \
79 ("%#RX64; a_fNotExtrn=%#RX64\n", (a_pVCpu)->cpum.s.Guest.fExtrn, (a_fNotExtrn)))
80
81
82VMMDECL(void) CPUMSetHyperCR3(PVMCPU pVCpu, uint32_t cr3)
83{
84 pVCpu->cpum.s.Hyper.cr3 = cr3;
85}
86
87VMMDECL(uint32_t) CPUMGetHyperCR3(PVMCPU pVCpu)
88{
89 return pVCpu->cpum.s.Hyper.cr3;
90}
91
92
93/** @def MAYBE_LOAD_DRx
94 * Macro for updating DRx values in raw-mode and ring-0 contexts.
95 */
96#ifdef IN_RING0
97# define MAYBE_LOAD_DRx(a_pVCpu, a_fnLoad, a_uValue) do { a_fnLoad(a_uValue); } while (0)
98#else
99# define MAYBE_LOAD_DRx(a_pVCpu, a_fnLoad, a_uValue) do { } while (0)
100#endif
101
102VMMDECL(void) CPUMSetHyperDR0(PVMCPU pVCpu, RTGCUINTREG uDr0)
103{
104 pVCpu->cpum.s.Hyper.dr[0] = uDr0;
105 MAYBE_LOAD_DRx(pVCpu, ASMSetDR0, uDr0);
106}
107
108
109VMMDECL(void) CPUMSetHyperDR1(PVMCPU pVCpu, RTGCUINTREG uDr1)
110{
111 pVCpu->cpum.s.Hyper.dr[1] = uDr1;
112 MAYBE_LOAD_DRx(pVCpu, ASMSetDR1, uDr1);
113}
114
115
116VMMDECL(void) CPUMSetHyperDR2(PVMCPU pVCpu, RTGCUINTREG uDr2)
117{
118 pVCpu->cpum.s.Hyper.dr[2] = uDr2;
119 MAYBE_LOAD_DRx(pVCpu, ASMSetDR2, uDr2);
120}
121
122
123VMMDECL(void) CPUMSetHyperDR3(PVMCPU pVCpu, RTGCUINTREG uDr3)
124{
125 pVCpu->cpum.s.Hyper.dr[3] = uDr3;
126 MAYBE_LOAD_DRx(pVCpu, ASMSetDR3, uDr3);
127}
128
129
130VMMDECL(void) CPUMSetHyperDR6(PVMCPU pVCpu, RTGCUINTREG uDr6)
131{
132 pVCpu->cpum.s.Hyper.dr[6] = uDr6;
133}
134
135
136VMMDECL(void) CPUMSetHyperDR7(PVMCPU pVCpu, RTGCUINTREG uDr7)
137{
138 pVCpu->cpum.s.Hyper.dr[7] = uDr7;
139}
140
141
142VMMDECL(RTGCUINTREG) CPUMGetHyperDR0(PVMCPU pVCpu)
143{
144 return pVCpu->cpum.s.Hyper.dr[0];
145}
146
147
148VMMDECL(RTGCUINTREG) CPUMGetHyperDR1(PVMCPU pVCpu)
149{
150 return pVCpu->cpum.s.Hyper.dr[1];
151}
152
153
154VMMDECL(RTGCUINTREG) CPUMGetHyperDR2(PVMCPU pVCpu)
155{
156 return pVCpu->cpum.s.Hyper.dr[2];
157}
158
159
160VMMDECL(RTGCUINTREG) CPUMGetHyperDR3(PVMCPU pVCpu)
161{
162 return pVCpu->cpum.s.Hyper.dr[3];
163}
164
165
166VMMDECL(RTGCUINTREG) CPUMGetHyperDR6(PVMCPU pVCpu)
167{
168 return pVCpu->cpum.s.Hyper.dr[6];
169}
170
171
172VMMDECL(RTGCUINTREG) CPUMGetHyperDR7(PVMCPU pVCpu)
173{
174 return pVCpu->cpum.s.Hyper.dr[7];
175}
176
177
178/**
179 * Gets the pointer to the internal CPUMCTXCORE structure.
180 * This is only for reading in order to save a few calls.
181 *
182 * @param pVCpu The cross context virtual CPU structure.
183 */
184VMMDECL(PCCPUMCTXCORE) CPUMGetGuestCtxCore(PVMCPU pVCpu)
185{
186 return CPUMCTX2CORE(&pVCpu->cpum.s.Guest);
187}
188
189
190/**
191 * Queries the pointer to the internal CPUMCTX structure.
192 *
193 * @returns The CPUMCTX pointer.
194 * @param pVCpu The cross context virtual CPU structure.
195 */
196VMMDECL(PCPUMCTX) CPUMQueryGuestCtxPtr(PVMCPU pVCpu)
197{
198 return &pVCpu->cpum.s.Guest;
199}
200
201
202/**
203 * Queries the pointer to the internal CPUMCTXMSRS structure.
204 *
205 * This is for NEM only.
206 *
207 * @returns The CPUMCTX pointer.
208 * @param pVCpu The cross context virtual CPU structure.
209 */
210VMM_INT_DECL(PCPUMCTXMSRS) CPUMQueryGuestCtxMsrsPtr(PVMCPU pVCpu)
211{
212 return &pVCpu->cpum.s.GuestMsrs;
213}
214
215
216VMMDECL(int) CPUMSetGuestGDTR(PVMCPU pVCpu, uint64_t GCPtrBase, uint16_t cbLimit)
217{
218 pVCpu->cpum.s.Guest.gdtr.cbGdt = cbLimit;
219 pVCpu->cpum.s.Guest.gdtr.pGdt = GCPtrBase;
220 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_GDTR;
221 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_GDTR;
222 return VINF_SUCCESS; /* formality, consider it void. */
223}
224
225
226VMMDECL(int) CPUMSetGuestIDTR(PVMCPU pVCpu, uint64_t GCPtrBase, uint16_t cbLimit)
227{
228 pVCpu->cpum.s.Guest.idtr.cbIdt = cbLimit;
229 pVCpu->cpum.s.Guest.idtr.pIdt = GCPtrBase;
230 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_IDTR;
231 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_IDTR;
232 return VINF_SUCCESS; /* formality, consider it void. */
233}
234
235
236VMMDECL(int) CPUMSetGuestTR(PVMCPU pVCpu, uint16_t tr)
237{
238 pVCpu->cpum.s.Guest.tr.Sel = tr;
239 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_TR;
240 return VINF_SUCCESS; /* formality, consider it void. */
241}
242
243
244VMMDECL(int) CPUMSetGuestLDTR(PVMCPU pVCpu, uint16_t ldtr)
245{
246 pVCpu->cpum.s.Guest.ldtr.Sel = ldtr;
247 /* The caller will set more hidden bits if it has them. */
248 pVCpu->cpum.s.Guest.ldtr.ValidSel = 0;
249 pVCpu->cpum.s.Guest.ldtr.fFlags = 0;
250 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_LDTR;
251 return VINF_SUCCESS; /* formality, consider it void. */
252}
253
254
255/**
256 * Set the guest CR0.
257 *
258 * When called in GC, the hyper CR0 may be updated if that is
259 * required. The caller only has to take special action if AM,
260 * WP, PG or PE changes.
261 *
262 * @returns VINF_SUCCESS (consider it void).
263 * @param pVCpu The cross context virtual CPU structure.
264 * @param cr0 The new CR0 value.
265 */
266VMMDECL(int) CPUMSetGuestCR0(PVMCPUCC pVCpu, uint64_t cr0)
267{
268 /*
269 * Check for changes causing TLB flushes (for REM).
270 * The caller is responsible for calling PGM when appropriate.
271 */
272 if ( (cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
273 != (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)))
274 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_GLOBAL_TLB_FLUSH;
275 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CR0;
276
277 /*
278 * Let PGM know if the WP goes from 0 to 1 (netware WP0+RO+US hack)
279 */
280 if (((cr0 ^ pVCpu->cpum.s.Guest.cr0) & X86_CR0_WP) && (cr0 & X86_CR0_WP))
281 PGMCr0WpEnabled(pVCpu);
282
283 /* The ET flag is settable on a 386 and hardwired on 486+. */
284 if ( !(cr0 & X86_CR0_ET)
285 && pVCpu->CTX_SUFF(pVM)->cpum.s.GuestFeatures.enmMicroarch != kCpumMicroarch_Intel_80386)
286 cr0 |= X86_CR0_ET;
287
288 pVCpu->cpum.s.Guest.cr0 = cr0;
289 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_CR0;
290 return VINF_SUCCESS;
291}
292
293
294VMMDECL(int) CPUMSetGuestCR2(PVMCPU pVCpu, uint64_t cr2)
295{
296 pVCpu->cpum.s.Guest.cr2 = cr2;
297 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_CR2;
298 return VINF_SUCCESS;
299}
300
301
302VMMDECL(int) CPUMSetGuestCR3(PVMCPU pVCpu, uint64_t cr3)
303{
304 pVCpu->cpum.s.Guest.cr3 = cr3;
305 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CR3;
306 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_CR3;
307 return VINF_SUCCESS;
308}
309
310
311VMMDECL(int) CPUMSetGuestCR4(PVMCPU pVCpu, uint64_t cr4)
312{
313 /* Note! We don't bother with OSXSAVE and legacy CPUID patches. */
314
315 if ( (cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE))
316 != (pVCpu->cpum.s.Guest.cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE)))
317 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_GLOBAL_TLB_FLUSH;
318
319 pVCpu->cpum.s.fChanged |= CPUM_CHANGED_CR4;
320 pVCpu->cpum.s.Guest.cr4 = cr4;
321 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_CR4;
322 return VINF_SUCCESS;
323}
324
325
326VMMDECL(int) CPUMSetGuestEFlags(PVMCPU pVCpu, uint32_t eflags)
327{
328 pVCpu->cpum.s.Guest.eflags.u32 = eflags;
329 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
330 return VINF_SUCCESS;
331}
332
333
334VMMDECL(int) CPUMSetGuestEIP(PVMCPU pVCpu, uint32_t eip)
335{
336 pVCpu->cpum.s.Guest.eip = eip;
337 return VINF_SUCCESS;
338}
339
340
341VMMDECL(int) CPUMSetGuestEAX(PVMCPU pVCpu, uint32_t eax)
342{
343 pVCpu->cpum.s.Guest.eax = eax;
344 return VINF_SUCCESS;
345}
346
347
348VMMDECL(int) CPUMSetGuestEBX(PVMCPU pVCpu, uint32_t ebx)
349{
350 pVCpu->cpum.s.Guest.ebx = ebx;
351 return VINF_SUCCESS;
352}
353
354
355VMMDECL(int) CPUMSetGuestECX(PVMCPU pVCpu, uint32_t ecx)
356{
357 pVCpu->cpum.s.Guest.ecx = ecx;
358 return VINF_SUCCESS;
359}
360
361
362VMMDECL(int) CPUMSetGuestEDX(PVMCPU pVCpu, uint32_t edx)
363{
364 pVCpu->cpum.s.Guest.edx = edx;
365 return VINF_SUCCESS;
366}
367
368
369VMMDECL(int) CPUMSetGuestESP(PVMCPU pVCpu, uint32_t esp)
370{
371 pVCpu->cpum.s.Guest.esp = esp;
372 return VINF_SUCCESS;
373}
374
375
376VMMDECL(int) CPUMSetGuestEBP(PVMCPU pVCpu, uint32_t ebp)
377{
378 pVCpu->cpum.s.Guest.ebp = ebp;
379 return VINF_SUCCESS;
380}
381
382
383VMMDECL(int) CPUMSetGuestESI(PVMCPU pVCpu, uint32_t esi)
384{
385 pVCpu->cpum.s.Guest.esi = esi;
386 return VINF_SUCCESS;
387}
388
389
390VMMDECL(int) CPUMSetGuestEDI(PVMCPU pVCpu, uint32_t edi)
391{
392 pVCpu->cpum.s.Guest.edi = edi;
393 return VINF_SUCCESS;
394}
395
396
397VMMDECL(int) CPUMSetGuestSS(PVMCPU pVCpu, uint16_t ss)
398{
399 pVCpu->cpum.s.Guest.ss.Sel = ss;
400 return VINF_SUCCESS;
401}
402
403
404VMMDECL(int) CPUMSetGuestCS(PVMCPU pVCpu, uint16_t cs)
405{
406 pVCpu->cpum.s.Guest.cs.Sel = cs;
407 return VINF_SUCCESS;
408}
409
410
411VMMDECL(int) CPUMSetGuestDS(PVMCPU pVCpu, uint16_t ds)
412{
413 pVCpu->cpum.s.Guest.ds.Sel = ds;
414 return VINF_SUCCESS;
415}
416
417
418VMMDECL(int) CPUMSetGuestES(PVMCPU pVCpu, uint16_t es)
419{
420 pVCpu->cpum.s.Guest.es.Sel = es;
421 return VINF_SUCCESS;
422}
423
424
425VMMDECL(int) CPUMSetGuestFS(PVMCPU pVCpu, uint16_t fs)
426{
427 pVCpu->cpum.s.Guest.fs.Sel = fs;
428 return VINF_SUCCESS;
429}
430
431
432VMMDECL(int) CPUMSetGuestGS(PVMCPU pVCpu, uint16_t gs)
433{
434 pVCpu->cpum.s.Guest.gs.Sel = gs;
435 return VINF_SUCCESS;
436}
437
438
439VMMDECL(void) CPUMSetGuestEFER(PVMCPU pVCpu, uint64_t val)
440{
441 pVCpu->cpum.s.Guest.msrEFER = val;
442 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_EFER;
443}
444
445
446VMMDECL(RTGCPTR) CPUMGetGuestIDTR(PCVMCPU pVCpu, uint16_t *pcbLimit)
447{
448 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_IDTR);
449 if (pcbLimit)
450 *pcbLimit = pVCpu->cpum.s.Guest.idtr.cbIdt;
451 return pVCpu->cpum.s.Guest.idtr.pIdt;
452}
453
454
455VMMDECL(RTSEL) CPUMGetGuestTR(PCVMCPU pVCpu, PCPUMSELREGHID pHidden)
456{
457 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_TR);
458 if (pHidden)
459 *pHidden = pVCpu->cpum.s.Guest.tr;
460 return pVCpu->cpum.s.Guest.tr.Sel;
461}
462
463
464VMMDECL(RTSEL) CPUMGetGuestCS(PCVMCPU pVCpu)
465{
466 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CS);
467 return pVCpu->cpum.s.Guest.cs.Sel;
468}
469
470
471VMMDECL(RTSEL) CPUMGetGuestDS(PCVMCPU pVCpu)
472{
473 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_DS);
474 return pVCpu->cpum.s.Guest.ds.Sel;
475}
476
477
478VMMDECL(RTSEL) CPUMGetGuestES(PCVMCPU pVCpu)
479{
480 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_ES);
481 return pVCpu->cpum.s.Guest.es.Sel;
482}
483
484
485VMMDECL(RTSEL) CPUMGetGuestFS(PCVMCPU pVCpu)
486{
487 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_FS);
488 return pVCpu->cpum.s.Guest.fs.Sel;
489}
490
491
492VMMDECL(RTSEL) CPUMGetGuestGS(PCVMCPU pVCpu)
493{
494 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_GS);
495 return pVCpu->cpum.s.Guest.gs.Sel;
496}
497
498
499VMMDECL(RTSEL) CPUMGetGuestSS(PCVMCPU pVCpu)
500{
501 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_SS);
502 return pVCpu->cpum.s.Guest.ss.Sel;
503}
504
505
506VMMDECL(uint64_t) CPUMGetGuestFlatPC(PVMCPU pVCpu)
507{
508 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
509 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
510 if ( !CPUMIsGuestInLongMode(pVCpu)
511 || !pVCpu->cpum.s.Guest.cs.Attr.n.u1Long)
512 return pVCpu->cpum.s.Guest.eip + (uint32_t)pVCpu->cpum.s.Guest.cs.u64Base;
513 return pVCpu->cpum.s.Guest.rip + pVCpu->cpum.s.Guest.cs.u64Base;
514}
515
516
517VMMDECL(uint64_t) CPUMGetGuestFlatSP(PVMCPU pVCpu)
518{
519 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
520 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.ss);
521 if ( !CPUMIsGuestInLongMode(pVCpu)
522 || !pVCpu->cpum.s.Guest.cs.Attr.n.u1Long)
523 return pVCpu->cpum.s.Guest.eip + (uint32_t)pVCpu->cpum.s.Guest.ss.u64Base;
524 return pVCpu->cpum.s.Guest.rip + pVCpu->cpum.s.Guest.ss.u64Base;
525}
526
527
528VMMDECL(RTSEL) CPUMGetGuestLDTR(PCVMCPU pVCpu)
529{
530 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_LDTR);
531 return pVCpu->cpum.s.Guest.ldtr.Sel;
532}
533
534
535VMMDECL(RTSEL) CPUMGetGuestLdtrEx(PCVMCPU pVCpu, uint64_t *pGCPtrBase, uint32_t *pcbLimit)
536{
537 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_LDTR);
538 *pGCPtrBase = pVCpu->cpum.s.Guest.ldtr.u64Base;
539 *pcbLimit = pVCpu->cpum.s.Guest.ldtr.u32Limit;
540 return pVCpu->cpum.s.Guest.ldtr.Sel;
541}
542
543
544VMMDECL(uint64_t) CPUMGetGuestCR0(PCVMCPU pVCpu)
545{
546 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0);
547 return pVCpu->cpum.s.Guest.cr0;
548}
549
550
551VMMDECL(uint64_t) CPUMGetGuestCR2(PCVMCPU pVCpu)
552{
553 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR2);
554 return pVCpu->cpum.s.Guest.cr2;
555}
556
557
558VMMDECL(uint64_t) CPUMGetGuestCR3(PCVMCPU pVCpu)
559{
560 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR3);
561 return pVCpu->cpum.s.Guest.cr3;
562}
563
564
565VMMDECL(uint64_t) CPUMGetGuestCR4(PCVMCPU pVCpu)
566{
567 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR4);
568 return pVCpu->cpum.s.Guest.cr4;
569}
570
571
572VMMDECL(uint64_t) CPUMGetGuestCR8(PCVMCPUCC pVCpu)
573{
574 uint64_t u64;
575 int rc = CPUMGetGuestCRx(pVCpu, DISCREG_CR8, &u64);
576 if (RT_FAILURE(rc))
577 u64 = 0;
578 return u64;
579}
580
581
582VMMDECL(void) CPUMGetGuestGDTR(PCVMCPU pVCpu, PVBOXGDTR pGDTR)
583{
584 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_GDTR);
585 *pGDTR = pVCpu->cpum.s.Guest.gdtr;
586}
587
588
589VMMDECL(uint32_t) CPUMGetGuestEIP(PCVMCPU pVCpu)
590{
591 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RIP);
592 return pVCpu->cpum.s.Guest.eip;
593}
594
595
596VMMDECL(uint64_t) CPUMGetGuestRIP(PCVMCPU pVCpu)
597{
598 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RIP);
599 return pVCpu->cpum.s.Guest.rip;
600}
601
602
603VMMDECL(uint32_t) CPUMGetGuestEAX(PCVMCPU pVCpu)
604{
605 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RAX);
606 return pVCpu->cpum.s.Guest.eax;
607}
608
609
610VMMDECL(uint32_t) CPUMGetGuestEBX(PCVMCPU pVCpu)
611{
612 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RBX);
613 return pVCpu->cpum.s.Guest.ebx;
614}
615
616
617VMMDECL(uint32_t) CPUMGetGuestECX(PCVMCPU pVCpu)
618{
619 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RCX);
620 return pVCpu->cpum.s.Guest.ecx;
621}
622
623
624VMMDECL(uint32_t) CPUMGetGuestEDX(PCVMCPU pVCpu)
625{
626 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RDX);
627 return pVCpu->cpum.s.Guest.edx;
628}
629
630
631VMMDECL(uint32_t) CPUMGetGuestESI(PCVMCPU pVCpu)
632{
633 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RSI);
634 return pVCpu->cpum.s.Guest.esi;
635}
636
637
638VMMDECL(uint32_t) CPUMGetGuestEDI(PCVMCPU pVCpu)
639{
640 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RDI);
641 return pVCpu->cpum.s.Guest.edi;
642}
643
644
645VMMDECL(uint32_t) CPUMGetGuestESP(PCVMCPU pVCpu)
646{
647 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RSP);
648 return pVCpu->cpum.s.Guest.esp;
649}
650
651
652VMMDECL(uint32_t) CPUMGetGuestEBP(PCVMCPU pVCpu)
653{
654 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RBP);
655 return pVCpu->cpum.s.Guest.ebp;
656}
657
658
659VMMDECL(uint32_t) CPUMGetGuestEFlags(PCVMCPU pVCpu)
660{
661 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_RFLAGS);
662 return pVCpu->cpum.s.Guest.eflags.u32;
663}
664
665
666VMMDECL(int) CPUMGetGuestCRx(PCVMCPUCC pVCpu, unsigned iReg, uint64_t *pValue)
667{
668 switch (iReg)
669 {
670 case DISCREG_CR0:
671 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0);
672 *pValue = pVCpu->cpum.s.Guest.cr0;
673 break;
674
675 case DISCREG_CR2:
676 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR2);
677 *pValue = pVCpu->cpum.s.Guest.cr2;
678 break;
679
680 case DISCREG_CR3:
681 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR3);
682 *pValue = pVCpu->cpum.s.Guest.cr3;
683 break;
684
685 case DISCREG_CR4:
686 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR4);
687 *pValue = pVCpu->cpum.s.Guest.cr4;
688 break;
689
690 case DISCREG_CR8:
691 {
692 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
693 uint8_t u8Tpr;
694 int rc = APICGetTpr(pVCpu, &u8Tpr, NULL /* pfPending */, NULL /* pu8PendingIrq */);
695 if (RT_FAILURE(rc))
696 {
697 AssertMsg(rc == VERR_PDM_NO_APIC_INSTANCE, ("%Rrc\n", rc));
698 *pValue = 0;
699 return rc;
700 }
701 *pValue = u8Tpr >> 4; /* bits 7-4 contain the task priority that go in cr8, bits 3-0 */
702 break;
703 }
704
705 default:
706 return VERR_INVALID_PARAMETER;
707 }
708 return VINF_SUCCESS;
709}
710
711
712VMMDECL(uint64_t) CPUMGetGuestDR0(PCVMCPU pVCpu)
713{
714 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
715 return pVCpu->cpum.s.Guest.dr[0];
716}
717
718
719VMMDECL(uint64_t) CPUMGetGuestDR1(PCVMCPU pVCpu)
720{
721 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
722 return pVCpu->cpum.s.Guest.dr[1];
723}
724
725
726VMMDECL(uint64_t) CPUMGetGuestDR2(PCVMCPU pVCpu)
727{
728 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
729 return pVCpu->cpum.s.Guest.dr[2];
730}
731
732
733VMMDECL(uint64_t) CPUMGetGuestDR3(PCVMCPU pVCpu)
734{
735 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_DR0_DR3);
736 return pVCpu->cpum.s.Guest.dr[3];
737}
738
739
740VMMDECL(uint64_t) CPUMGetGuestDR6(PCVMCPU pVCpu)
741{
742 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_DR6);
743 return pVCpu->cpum.s.Guest.dr[6];
744}
745
746
747VMMDECL(uint64_t) CPUMGetGuestDR7(PCVMCPU pVCpu)
748{
749 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_DR7);
750 return pVCpu->cpum.s.Guest.dr[7];
751}
752
753
754VMMDECL(int) CPUMGetGuestDRx(PCVMCPU pVCpu, uint32_t iReg, uint64_t *pValue)
755{
756 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_DR_MASK);
757 AssertReturn(iReg <= DISDREG_DR7, VERR_INVALID_PARAMETER);
758 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
759 if (iReg == 4 || iReg == 5)
760 iReg += 2;
761 *pValue = pVCpu->cpum.s.Guest.dr[iReg];
762 return VINF_SUCCESS;
763}
764
765
766VMMDECL(uint64_t) CPUMGetGuestEFER(PCVMCPU pVCpu)
767{
768 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_EFER);
769 return pVCpu->cpum.s.Guest.msrEFER;
770}
771
772
773/**
774 * Looks up a CPUID leaf in the CPUID leaf array, no subleaf.
775 *
776 * @returns Pointer to the leaf if found, NULL if not.
777 *
778 * @param pVM The cross context VM structure.
779 * @param uLeaf The leaf to get.
780 */
781PCPUMCPUIDLEAF cpumCpuIdGetLeaf(PVM pVM, uint32_t uLeaf)
782{
783 unsigned iEnd = RT_MIN(pVM->cpum.s.GuestInfo.cCpuIdLeaves, RT_ELEMENTS(pVM->cpum.s.GuestInfo.aCpuIdLeaves));
784 if (iEnd)
785 {
786 unsigned iStart = 0;
787 PCPUMCPUIDLEAF paLeaves = pVM->cpum.s.GuestInfo.aCpuIdLeaves;
788 for (;;)
789 {
790 unsigned i = iStart + (iEnd - iStart) / 2U;
791 if (uLeaf < paLeaves[i].uLeaf)
792 {
793 if (i <= iStart)
794 return NULL;
795 iEnd = i;
796 }
797 else if (uLeaf > paLeaves[i].uLeaf)
798 {
799 i += 1;
800 if (i >= iEnd)
801 return NULL;
802 iStart = i;
803 }
804 else
805 {
806 if (RT_LIKELY(paLeaves[i].fSubLeafMask == 0 && paLeaves[i].uSubLeaf == 0))
807 return &paLeaves[i];
808
809 /* This shouldn't normally happen. But in case the it does due
810 to user configuration overrids or something, just return the
811 first sub-leaf. */
812 AssertMsgFailed(("uLeaf=%#x fSubLeafMask=%#x uSubLeaf=%#x\n",
813 uLeaf, paLeaves[i].fSubLeafMask, paLeaves[i].uSubLeaf));
814 while ( paLeaves[i].uSubLeaf != 0
815 && i > 0
816 && uLeaf == paLeaves[i - 1].uLeaf)
817 i--;
818 return &paLeaves[i];
819 }
820 }
821 }
822
823 return NULL;
824}
825
826
827/**
828 * Looks up a CPUID leaf in the CPUID leaf array.
829 *
830 * @returns Pointer to the leaf if found, NULL if not.
831 *
832 * @param pVM The cross context VM structure.
833 * @param uLeaf The leaf to get.
834 * @param uSubLeaf The subleaf, if applicable. Just pass 0 if it
835 * isn't.
836 * @param pfExactSubLeafHit Whether we've got an exact subleaf hit or not.
837 */
838PCPUMCPUIDLEAF cpumCpuIdGetLeafEx(PVM pVM, uint32_t uLeaf, uint32_t uSubLeaf, bool *pfExactSubLeafHit)
839{
840 unsigned iEnd = RT_MIN(pVM->cpum.s.GuestInfo.cCpuIdLeaves, RT_ELEMENTS(pVM->cpum.s.GuestInfo.aCpuIdLeaves));
841 if (iEnd)
842 {
843 unsigned iStart = 0;
844 PCPUMCPUIDLEAF paLeaves = pVM->cpum.s.GuestInfo.aCpuIdLeaves;
845 for (;;)
846 {
847 unsigned i = iStart + (iEnd - iStart) / 2U;
848 if (uLeaf < paLeaves[i].uLeaf)
849 {
850 if (i <= iStart)
851 return NULL;
852 iEnd = i;
853 }
854 else if (uLeaf > paLeaves[i].uLeaf)
855 {
856 i += 1;
857 if (i >= iEnd)
858 return NULL;
859 iStart = i;
860 }
861 else
862 {
863 uSubLeaf &= paLeaves[i].fSubLeafMask;
864 if (uSubLeaf == paLeaves[i].uSubLeaf)
865 *pfExactSubLeafHit = true;
866 else
867 {
868 /* Find the right subleaf. We return the last one before
869 uSubLeaf if we don't find an exact match. */
870 if (uSubLeaf < paLeaves[i].uSubLeaf)
871 while ( i > 0
872 && uLeaf == paLeaves[i - 1].uLeaf
873 && uSubLeaf <= paLeaves[i - 1].uSubLeaf)
874 i--;
875 else
876 while ( i + 1 < pVM->cpum.s.GuestInfo.cCpuIdLeaves
877 && uLeaf == paLeaves[i + 1].uLeaf
878 && uSubLeaf >= paLeaves[i + 1].uSubLeaf)
879 i++;
880 *pfExactSubLeafHit = uSubLeaf == paLeaves[i].uSubLeaf;
881 }
882 return &paLeaves[i];
883 }
884 }
885 }
886
887 *pfExactSubLeafHit = false;
888 return NULL;
889}
890
891
892/**
893 * Gets a CPUID leaf.
894 *
895 * @param pVCpu The cross context virtual CPU structure.
896 * @param uLeaf The CPUID leaf to get.
897 * @param uSubLeaf The CPUID sub-leaf to get, if applicable.
898 * @param pEax Where to store the EAX value.
899 * @param pEbx Where to store the EBX value.
900 * @param pEcx Where to store the ECX value.
901 * @param pEdx Where to store the EDX value.
902 */
903VMMDECL(void) CPUMGetGuestCpuId(PVMCPUCC pVCpu, uint32_t uLeaf, uint32_t uSubLeaf,
904 uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)
905{
906 bool fExactSubLeafHit;
907 PVM pVM = pVCpu->CTX_SUFF(pVM);
908 PCCPUMCPUIDLEAF pLeaf = cpumCpuIdGetLeafEx(pVM, uLeaf, uSubLeaf, &fExactSubLeafHit);
909 if (pLeaf)
910 {
911 AssertMsg(pLeaf->uLeaf == uLeaf, ("%#x %#x\n", pLeaf->uLeaf, uLeaf));
912 if (fExactSubLeafHit)
913 {
914 *pEax = pLeaf->uEax;
915 *pEbx = pLeaf->uEbx;
916 *pEcx = pLeaf->uEcx;
917 *pEdx = pLeaf->uEdx;
918
919 /*
920 * Deal with CPU specific information.
921 */
922 if (pLeaf->fFlags & ( CPUMCPUIDLEAF_F_CONTAINS_APIC_ID
923 | CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE
924 | CPUMCPUIDLEAF_F_CONTAINS_APIC ))
925 {
926 if (uLeaf == 1)
927 {
928 /* EBX: Bits 31-24: Initial APIC ID. */
929 Assert(pVCpu->idCpu <= 255);
930 AssertMsg((pLeaf->uEbx >> 24) == 0, ("%#x\n", pLeaf->uEbx)); /* raw-mode assumption */
931 *pEbx = (pLeaf->uEbx & UINT32_C(0x00ffffff)) | (pVCpu->idCpu << 24);
932
933 /* EDX: Bit 9: AND with APICBASE.EN. */
934 if (!pVCpu->cpum.s.fCpuIdApicFeatureVisible && (pLeaf->fFlags & CPUMCPUIDLEAF_F_CONTAINS_APIC))
935 *pEdx &= ~X86_CPUID_FEATURE_EDX_APIC;
936
937 /* ECX: Bit 27: CR4.OSXSAVE mirror. */
938 *pEcx = (pLeaf->uEcx & ~X86_CPUID_FEATURE_ECX_OSXSAVE)
939 | (pVCpu->cpum.s.Guest.cr4 & X86_CR4_OSXSAVE ? X86_CPUID_FEATURE_ECX_OSXSAVE : 0);
940 }
941 else if (uLeaf == 0xb)
942 {
943 /* EDX: Initial extended APIC ID. */
944 AssertMsg(pLeaf->uEdx == 0, ("%#x\n", pLeaf->uEdx)); /* raw-mode assumption */
945 *pEdx = pVCpu->idCpu;
946 Assert(!(pLeaf->fFlags & ~(CPUMCPUIDLEAF_F_CONTAINS_APIC_ID | CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES)));
947 }
948 else if (uLeaf == UINT32_C(0x8000001e))
949 {
950 /* EAX: Initial extended APIC ID. */
951 AssertMsg(pLeaf->uEax == 0, ("%#x\n", pLeaf->uEax)); /* raw-mode assumption */
952 *pEax = pVCpu->idCpu;
953 Assert(!(pLeaf->fFlags & ~CPUMCPUIDLEAF_F_CONTAINS_APIC_ID));
954 }
955 else if (uLeaf == UINT32_C(0x80000001))
956 {
957 /* EDX: Bit 9: AND with APICBASE.EN. */
958 if (!pVCpu->cpum.s.fCpuIdApicFeatureVisible)
959 *pEdx &= ~X86_CPUID_AMD_FEATURE_EDX_APIC;
960 Assert(!(pLeaf->fFlags & ~CPUMCPUIDLEAF_F_CONTAINS_APIC));
961 }
962 else
963 AssertMsgFailed(("uLeaf=%#x\n", uLeaf));
964 }
965 }
966 /*
967 * Out of range sub-leaves aren't quite as easy and pretty as we emulate
968 * them here, but we do the best we can here...
969 */
970 else
971 {
972 *pEax = *pEbx = *pEcx = *pEdx = 0;
973 if (pLeaf->fFlags & CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES)
974 {
975 *pEcx = uSubLeaf & 0xff;
976 *pEdx = pVCpu->idCpu;
977 }
978 }
979 }
980 else
981 {
982 /*
983 * Different CPUs have different ways of dealing with unknown CPUID leaves.
984 */
985 switch (pVM->cpum.s.GuestInfo.enmUnknownCpuIdMethod)
986 {
987 default:
988 AssertFailed();
989 RT_FALL_THRU();
990 case CPUMUNKNOWNCPUID_DEFAULTS:
991 case CPUMUNKNOWNCPUID_LAST_STD_LEAF: /* ASSUME this is executed */
992 case CPUMUNKNOWNCPUID_LAST_STD_LEAF_WITH_ECX: /** @todo Implement CPUMUNKNOWNCPUID_LAST_STD_LEAF_WITH_ECX */
993 *pEax = pVM->cpum.s.GuestInfo.DefCpuId.uEax;
994 *pEbx = pVM->cpum.s.GuestInfo.DefCpuId.uEbx;
995 *pEcx = pVM->cpum.s.GuestInfo.DefCpuId.uEcx;
996 *pEdx = pVM->cpum.s.GuestInfo.DefCpuId.uEdx;
997 break;
998 case CPUMUNKNOWNCPUID_PASSTHRU:
999 *pEax = uLeaf;
1000 *pEbx = 0;
1001 *pEcx = uSubLeaf;
1002 *pEdx = 0;
1003 break;
1004 }
1005 }
1006 Log2(("CPUMGetGuestCpuId: uLeaf=%#010x/%#010x %RX32 %RX32 %RX32 %RX32\n", uLeaf, uSubLeaf, *pEax, *pEbx, *pEcx, *pEdx));
1007}
1008
1009
1010/**
1011 * Sets the visibility of the X86_CPUID_FEATURE_EDX_APIC and
1012 * X86_CPUID_AMD_FEATURE_EDX_APIC CPUID bits.
1013 *
1014 * @returns Previous value.
1015 * @param pVCpu The cross context virtual CPU structure to make the
1016 * change on. Usually the calling EMT.
1017 * @param fVisible Whether to make it visible (true) or hide it (false).
1018 *
1019 * @remarks This is "VMMDECL" so that it still links with
1020 * the old APIC code which is in VBoxDD2 and not in
1021 * the VMM module.
1022 */
1023VMMDECL(bool) CPUMSetGuestCpuIdPerCpuApicFeature(PVMCPU pVCpu, bool fVisible)
1024{
1025 bool fOld = pVCpu->cpum.s.fCpuIdApicFeatureVisible;
1026 pVCpu->cpum.s.fCpuIdApicFeatureVisible = fVisible;
1027 return fOld;
1028}
1029
1030
1031/**
1032 * Gets the host CPU vendor.
1033 *
1034 * @returns CPU vendor.
1035 * @param pVM The cross context VM structure.
1036 */
1037VMMDECL(CPUMCPUVENDOR) CPUMGetHostCpuVendor(PVM pVM)
1038{
1039 return (CPUMCPUVENDOR)pVM->cpum.s.HostFeatures.enmCpuVendor;
1040}
1041
1042
1043/**
1044 * Gets the host CPU microarchitecture.
1045 *
1046 * @returns CPU microarchitecture.
1047 * @param pVM The cross context VM structure.
1048 */
1049VMMDECL(CPUMMICROARCH) CPUMGetHostMicroarch(PCVM pVM)
1050{
1051 return pVM->cpum.s.HostFeatures.enmMicroarch;
1052}
1053
1054
1055/**
1056 * Gets the guest CPU vendor.
1057 *
1058 * @returns CPU vendor.
1059 * @param pVM The cross context VM structure.
1060 */
1061VMMDECL(CPUMCPUVENDOR) CPUMGetGuestCpuVendor(PVM pVM)
1062{
1063 return (CPUMCPUVENDOR)pVM->cpum.s.GuestFeatures.enmCpuVendor;
1064}
1065
1066
1067/**
1068 * Gets the guest CPU microarchitecture.
1069 *
1070 * @returns CPU microarchitecture.
1071 * @param pVM The cross context VM structure.
1072 */
1073VMMDECL(CPUMMICROARCH) CPUMGetGuestMicroarch(PCVM pVM)
1074{
1075 return pVM->cpum.s.GuestFeatures.enmMicroarch;
1076}
1077
1078
1079/**
1080 * Gets the maximum number of physical and linear address bits supported by the
1081 * guest.
1082 *
1083 * @param pVM The cross context VM structure.
1084 * @param pcPhysAddrWidth Where to store the physical address width.
1085 * @param pcLinearAddrWidth Where to store the linear address width.
1086 */
1087VMMDECL(void) CPUMGetGuestAddrWidths(PCVM pVM, uint8_t *pcPhysAddrWidth, uint8_t *pcLinearAddrWidth)
1088{
1089 AssertPtr(pVM);
1090 AssertReturnVoid(pcPhysAddrWidth);
1091 AssertReturnVoid(pcLinearAddrWidth);
1092 *pcPhysAddrWidth = pVM->cpum.s.GuestFeatures.cMaxPhysAddrWidth;
1093 *pcLinearAddrWidth = pVM->cpum.s.GuestFeatures.cMaxLinearAddrWidth;
1094}
1095
1096
1097VMMDECL(int) CPUMSetGuestDR0(PVMCPUCC pVCpu, uint64_t uDr0)
1098{
1099 pVCpu->cpum.s.Guest.dr[0] = uDr0;
1100 return CPUMRecalcHyperDRx(pVCpu, 0);
1101}
1102
1103
1104VMMDECL(int) CPUMSetGuestDR1(PVMCPUCC pVCpu, uint64_t uDr1)
1105{
1106 pVCpu->cpum.s.Guest.dr[1] = uDr1;
1107 return CPUMRecalcHyperDRx(pVCpu, 1);
1108}
1109
1110
1111VMMDECL(int) CPUMSetGuestDR2(PVMCPUCC pVCpu, uint64_t uDr2)
1112{
1113 pVCpu->cpum.s.Guest.dr[2] = uDr2;
1114 return CPUMRecalcHyperDRx(pVCpu, 2);
1115}
1116
1117
1118VMMDECL(int) CPUMSetGuestDR3(PVMCPUCC pVCpu, uint64_t uDr3)
1119{
1120 pVCpu->cpum.s.Guest.dr[3] = uDr3;
1121 return CPUMRecalcHyperDRx(pVCpu, 3);
1122}
1123
1124
1125VMMDECL(int) CPUMSetGuestDR6(PVMCPU pVCpu, uint64_t uDr6)
1126{
1127 pVCpu->cpum.s.Guest.dr[6] = uDr6;
1128 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_DR6;
1129 return VINF_SUCCESS; /* No need to recalc. */
1130}
1131
1132
1133VMMDECL(int) CPUMSetGuestDR7(PVMCPUCC pVCpu, uint64_t uDr7)
1134{
1135 pVCpu->cpum.s.Guest.dr[7] = uDr7;
1136 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_DR7;
1137 return CPUMRecalcHyperDRx(pVCpu, 7);
1138}
1139
1140
1141VMMDECL(int) CPUMSetGuestDRx(PVMCPUCC pVCpu, uint32_t iReg, uint64_t Value)
1142{
1143 AssertReturn(iReg <= DISDREG_DR7, VERR_INVALID_PARAMETER);
1144 /* DR4 is an alias for DR6, and DR5 is an alias for DR7. */
1145 if (iReg == 4 || iReg == 5)
1146 iReg += 2;
1147 pVCpu->cpum.s.Guest.dr[iReg] = Value;
1148 return CPUMRecalcHyperDRx(pVCpu, iReg);
1149}
1150
1151
1152/**
1153 * Recalculates the hypervisor DRx register values based on current guest
1154 * registers and DBGF breakpoints, updating changed registers depending on the
1155 * context.
1156 *
1157 * This is called whenever a guest DRx register is modified (any context) and
1158 * when DBGF sets a hardware breakpoint (ring-3 only, rendezvous).
1159 *
1160 * In raw-mode context this function will reload any (hyper) DRx registers which
1161 * comes out with a different value. It may also have to save the host debug
1162 * registers if that haven't been done already. In this context though, we'll
1163 * be intercepting and emulating all DRx accesses, so the hypervisor DRx values
1164 * are only important when breakpoints are actually enabled.
1165 *
1166 * In ring-0 (HM) context DR0-3 will be relocated by us, while DR7 will be
1167 * reloaded by the HM code if it changes. Further more, we will only use the
1168 * combined register set when the VBox debugger is actually using hardware BPs,
1169 * when it isn't we'll keep the guest DR0-3 + (maybe) DR6 loaded (DR6 doesn't
1170 * concern us here).
1171 *
1172 * In ring-3 we won't be loading anything, so well calculate hypervisor values
1173 * all the time.
1174 *
1175 * @returns VINF_SUCCESS.
1176 * @param pVCpu The cross context virtual CPU structure.
1177 * @param iGstReg The guest debug register number that was modified.
1178 * UINT8_MAX if not guest register.
1179 */
1180VMMDECL(int) CPUMRecalcHyperDRx(PVMCPUCC pVCpu, uint8_t iGstReg)
1181{
1182 PVM pVM = pVCpu->CTX_SUFF(pVM);
1183#ifndef IN_RING0
1184 RT_NOREF_PV(iGstReg);
1185#endif
1186
1187 /*
1188 * Compare the DR7s first.
1189 *
1190 * We only care about the enabled flags. GD is virtualized when we
1191 * dispatch the #DB, we never enable it. The DBGF DR7 value is will
1192 * always have the LE and GE bits set, so no need to check and disable
1193 * stuff if they're cleared like we have to for the guest DR7.
1194 */
1195 RTGCUINTREG uGstDr7 = CPUMGetGuestDR7(pVCpu);
1196 /** @todo This isn't correct. BPs work without setting LE and GE under AMD-V. They are also documented as unsupported by P6+. */
1197 if (!(uGstDr7 & (X86_DR7_LE | X86_DR7_GE)))
1198 uGstDr7 = 0;
1199 else if (!(uGstDr7 & X86_DR7_LE))
1200 uGstDr7 &= ~X86_DR7_LE_ALL;
1201 else if (!(uGstDr7 & X86_DR7_GE))
1202 uGstDr7 &= ~X86_DR7_GE_ALL;
1203
1204 const RTGCUINTREG uDbgfDr7 = DBGFBpGetDR7(pVM);
1205 if ((uGstDr7 | uDbgfDr7) & X86_DR7_ENABLED_MASK)
1206 {
1207 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
1208
1209 /*
1210 * Ok, something is enabled. Recalc each of the breakpoints, taking
1211 * the VM debugger ones of the guest ones. In raw-mode context we will
1212 * not allow breakpoints with values inside the hypervisor area.
1213 */
1214 RTGCUINTREG uNewDr7 = X86_DR7_GE | X86_DR7_LE | X86_DR7_RA1_MASK;
1215
1216 /* bp 0 */
1217 RTGCUINTREG uNewDr0;
1218 if (uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0))
1219 {
1220 uNewDr7 |= uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
1221 uNewDr0 = DBGFBpGetDR0(pVM);
1222 }
1223 else if (uGstDr7 & (X86_DR7_L0 | X86_DR7_G0))
1224 {
1225 uNewDr0 = CPUMGetGuestDR0(pVCpu);
1226 uNewDr7 |= uGstDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
1227 }
1228 else
1229 uNewDr0 = 0;
1230
1231 /* bp 1 */
1232 RTGCUINTREG uNewDr1;
1233 if (uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1))
1234 {
1235 uNewDr7 |= uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
1236 uNewDr1 = DBGFBpGetDR1(pVM);
1237 }
1238 else if (uGstDr7 & (X86_DR7_L1 | X86_DR7_G1))
1239 {
1240 uNewDr1 = CPUMGetGuestDR1(pVCpu);
1241 uNewDr7 |= uGstDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
1242 }
1243 else
1244 uNewDr1 = 0;
1245
1246 /* bp 2 */
1247 RTGCUINTREG uNewDr2;
1248 if (uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2))
1249 {
1250 uNewDr7 |= uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
1251 uNewDr2 = DBGFBpGetDR2(pVM);
1252 }
1253 else if (uGstDr7 & (X86_DR7_L2 | X86_DR7_G2))
1254 {
1255 uNewDr2 = CPUMGetGuestDR2(pVCpu);
1256 uNewDr7 |= uGstDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
1257 }
1258 else
1259 uNewDr2 = 0;
1260
1261 /* bp 3 */
1262 RTGCUINTREG uNewDr3;
1263 if (uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3))
1264 {
1265 uNewDr7 |= uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
1266 uNewDr3 = DBGFBpGetDR3(pVM);
1267 }
1268 else if (uGstDr7 & (X86_DR7_L3 | X86_DR7_G3))
1269 {
1270 uNewDr3 = CPUMGetGuestDR3(pVCpu);
1271 uNewDr7 |= uGstDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
1272 }
1273 else
1274 uNewDr3 = 0;
1275
1276 /*
1277 * Apply the updates.
1278 */
1279 pVCpu->cpum.s.fUseFlags |= CPUM_USE_DEBUG_REGS_HYPER;
1280 if (uNewDr3 != pVCpu->cpum.s.Hyper.dr[3])
1281 CPUMSetHyperDR3(pVCpu, uNewDr3);
1282 if (uNewDr2 != pVCpu->cpum.s.Hyper.dr[2])
1283 CPUMSetHyperDR2(pVCpu, uNewDr2);
1284 if (uNewDr1 != pVCpu->cpum.s.Hyper.dr[1])
1285 CPUMSetHyperDR1(pVCpu, uNewDr1);
1286 if (uNewDr0 != pVCpu->cpum.s.Hyper.dr[0])
1287 CPUMSetHyperDR0(pVCpu, uNewDr0);
1288 if (uNewDr7 != pVCpu->cpum.s.Hyper.dr[7])
1289 CPUMSetHyperDR7(pVCpu, uNewDr7);
1290 }
1291#ifdef IN_RING0
1292 else if (CPUMIsGuestDebugStateActive(pVCpu))
1293 {
1294 /*
1295 * Reload the register that was modified. Normally this won't happen
1296 * as we won't intercept DRx writes when not having the hyper debug
1297 * state loaded, but in case we do for some reason we'll simply deal
1298 * with it.
1299 */
1300 switch (iGstReg)
1301 {
1302 case 0: ASMSetDR0(CPUMGetGuestDR0(pVCpu)); break;
1303 case 1: ASMSetDR1(CPUMGetGuestDR1(pVCpu)); break;
1304 case 2: ASMSetDR2(CPUMGetGuestDR2(pVCpu)); break;
1305 case 3: ASMSetDR3(CPUMGetGuestDR3(pVCpu)); break;
1306 default:
1307 AssertReturn(iGstReg != UINT8_MAX, VERR_INTERNAL_ERROR_3);
1308 }
1309 }
1310#endif
1311 else
1312 {
1313 /*
1314 * No active debug state any more. In raw-mode this means we have to
1315 * make sure DR7 has everything disabled now, if we armed it already.
1316 * In ring-0 we might end up here when just single stepping.
1317 */
1318#ifdef IN_RING0
1319 if (pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HYPER)
1320 {
1321 if (pVCpu->cpum.s.Hyper.dr[0])
1322 ASMSetDR0(0);
1323 if (pVCpu->cpum.s.Hyper.dr[1])
1324 ASMSetDR1(0);
1325 if (pVCpu->cpum.s.Hyper.dr[2])
1326 ASMSetDR2(0);
1327 if (pVCpu->cpum.s.Hyper.dr[3])
1328 ASMSetDR3(0);
1329 pVCpu->cpum.s.fUseFlags &= ~CPUM_USED_DEBUG_REGS_HYPER;
1330 }
1331#endif
1332 pVCpu->cpum.s.fUseFlags &= ~CPUM_USE_DEBUG_REGS_HYPER;
1333
1334 /* Clear all the registers. */
1335 pVCpu->cpum.s.Hyper.dr[7] = X86_DR7_RA1_MASK;
1336 pVCpu->cpum.s.Hyper.dr[3] = 0;
1337 pVCpu->cpum.s.Hyper.dr[2] = 0;
1338 pVCpu->cpum.s.Hyper.dr[1] = 0;
1339 pVCpu->cpum.s.Hyper.dr[0] = 0;
1340
1341 }
1342 Log2(("CPUMRecalcHyperDRx: fUseFlags=%#x %RGr %RGr %RGr %RGr %RGr %RGr\n",
1343 pVCpu->cpum.s.fUseFlags, pVCpu->cpum.s.Hyper.dr[0], pVCpu->cpum.s.Hyper.dr[1],
1344 pVCpu->cpum.s.Hyper.dr[2], pVCpu->cpum.s.Hyper.dr[3], pVCpu->cpum.s.Hyper.dr[6],
1345 pVCpu->cpum.s.Hyper.dr[7]));
1346
1347 return VINF_SUCCESS;
1348}
1349
1350
1351/**
1352 * Set the guest XCR0 register.
1353 *
1354 * Will load additional state if the FPU state is already loaded (in ring-0 &
1355 * raw-mode context).
1356 *
1357 * @returns VINF_SUCCESS on success, VERR_CPUM_RAISE_GP_0 on invalid input
1358 * value.
1359 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1360 * @param uNewValue The new value.
1361 * @thread EMT(pVCpu)
1362 */
1363VMM_INT_DECL(int) CPUMSetGuestXcr0(PVMCPUCC pVCpu, uint64_t uNewValue)
1364{
1365 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_XCRx);
1366 if ( (uNewValue & ~pVCpu->CTX_SUFF(pVM)->cpum.s.fXStateGuestMask) == 0
1367 /* The X87 bit cannot be cleared. */
1368 && (uNewValue & XSAVE_C_X87)
1369 /* AVX requires SSE. */
1370 && (uNewValue & (XSAVE_C_SSE | XSAVE_C_YMM)) != XSAVE_C_YMM
1371 /* AVX-512 requires YMM, SSE and all of its three components to be enabled. */
1372 && ( (uNewValue & (XSAVE_C_OPMASK | XSAVE_C_ZMM_HI256 | XSAVE_C_ZMM_16HI)) == 0
1373 || (uNewValue & (XSAVE_C_SSE | XSAVE_C_YMM | XSAVE_C_OPMASK | XSAVE_C_ZMM_HI256 | XSAVE_C_ZMM_16HI))
1374 == (XSAVE_C_SSE | XSAVE_C_YMM | XSAVE_C_OPMASK | XSAVE_C_ZMM_HI256 | XSAVE_C_ZMM_16HI) )
1375 )
1376 {
1377 pVCpu->cpum.s.Guest.aXcr[0] = uNewValue;
1378
1379 /* If more state components are enabled, we need to take care to load
1380 them if the FPU/SSE state is already loaded. May otherwise leak
1381 host state to the guest. */
1382 uint64_t fNewComponents = ~pVCpu->cpum.s.Guest.fXStateMask & uNewValue;
1383 if (fNewComponents)
1384 {
1385#ifdef IN_RING0
1386 if (pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU_GUEST)
1387 {
1388 if (pVCpu->cpum.s.Guest.fXStateMask != 0)
1389 /* Adding more components. */
1390 ASMXRstor(&pVCpu->cpum.s.Guest.XState, fNewComponents);
1391 else
1392 {
1393 /* We're switching from FXSAVE/FXRSTOR to XSAVE/XRSTOR. */
1394 pVCpu->cpum.s.Guest.fXStateMask |= XSAVE_C_X87 | XSAVE_C_SSE;
1395 if (uNewValue & ~(XSAVE_C_X87 | XSAVE_C_SSE))
1396 ASMXRstor(&pVCpu->cpum.s.Guest.XState, uNewValue & ~(XSAVE_C_X87 | XSAVE_C_SSE));
1397 }
1398 }
1399#endif
1400 pVCpu->cpum.s.Guest.fXStateMask |= uNewValue;
1401 }
1402 return VINF_SUCCESS;
1403 }
1404 return VERR_CPUM_RAISE_GP_0;
1405}
1406
1407
1408/**
1409 * Tests if the guest has No-Execute Page Protection Enabled (NXE).
1410 *
1411 * @returns true if in real mode, otherwise false.
1412 * @param pVCpu The cross context virtual CPU structure.
1413 */
1414VMMDECL(bool) CPUMIsGuestNXEnabled(PCVMCPU pVCpu)
1415{
1416 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_EFER);
1417 return !!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_NXE);
1418}
1419
1420
1421/**
1422 * Tests if the guest has the Page Size Extension enabled (PSE).
1423 *
1424 * @returns true if in real mode, otherwise false.
1425 * @param pVCpu The cross context virtual CPU structure.
1426 */
1427VMMDECL(bool) CPUMIsGuestPageSizeExtEnabled(PCVMCPU pVCpu)
1428{
1429 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR4);
1430 /* PAE or AMD64 implies support for big pages regardless of CR4.PSE */
1431 return !!(pVCpu->cpum.s.Guest.cr4 & (X86_CR4_PSE | X86_CR4_PAE));
1432}
1433
1434
1435/**
1436 * Tests if the guest has the paging enabled (PG).
1437 *
1438 * @returns true if in real mode, otherwise false.
1439 * @param pVCpu The cross context virtual CPU structure.
1440 */
1441VMMDECL(bool) CPUMIsGuestPagingEnabled(PCVMCPU pVCpu)
1442{
1443 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0);
1444 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PG);
1445}
1446
1447
1448/**
1449 * Tests if the guest has the paging enabled (PG).
1450 *
1451 * @returns true if in real mode, otherwise false.
1452 * @param pVCpu The cross context virtual CPU structure.
1453 */
1454VMMDECL(bool) CPUMIsGuestR0WriteProtEnabled(PCVMCPU pVCpu)
1455{
1456 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0);
1457 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_WP);
1458}
1459
1460
1461/**
1462 * Tests if the guest is running in real mode or not.
1463 *
1464 * @returns true if in real mode, otherwise false.
1465 * @param pVCpu The cross context virtual CPU structure.
1466 */
1467VMMDECL(bool) CPUMIsGuestInRealMode(PCVMCPU pVCpu)
1468{
1469 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0);
1470 return !(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE);
1471}
1472
1473
1474/**
1475 * Tests if the guest is running in real or virtual 8086 mode.
1476 *
1477 * @returns @c true if it is, @c false if not.
1478 * @param pVCpu The cross context virtual CPU structure.
1479 */
1480VMMDECL(bool) CPUMIsGuestInRealOrV86Mode(PCVMCPU pVCpu)
1481{
1482 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS);
1483 return !(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE)
1484 || pVCpu->cpum.s.Guest.eflags.Bits.u1VM; /** @todo verify that this cannot be set in long mode. */
1485}
1486
1487
1488/**
1489 * Tests if the guest is running in protected or not.
1490 *
1491 * @returns true if in protected mode, otherwise false.
1492 * @param pVCpu The cross context virtual CPU structure.
1493 */
1494VMMDECL(bool) CPUMIsGuestInProtectedMode(PCVMCPU pVCpu)
1495{
1496 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0);
1497 return !!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE);
1498}
1499
1500
1501/**
1502 * Tests if the guest is running in paged protected or not.
1503 *
1504 * @returns true if in paged protected mode, otherwise false.
1505 * @param pVCpu The cross context virtual CPU structure.
1506 */
1507VMMDECL(bool) CPUMIsGuestInPagedProtectedMode(PCVMCPU pVCpu)
1508{
1509 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0);
1510 return (pVCpu->cpum.s.Guest.cr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG);
1511}
1512
1513
1514/**
1515 * Tests if the guest is running in long mode or not.
1516 *
1517 * @returns true if in long mode, otherwise false.
1518 * @param pVCpu The cross context virtual CPU structure.
1519 */
1520VMMDECL(bool) CPUMIsGuestInLongMode(PCVMCPU pVCpu)
1521{
1522 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_EFER);
1523 return (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA) == MSR_K6_EFER_LMA;
1524}
1525
1526
1527/**
1528 * Tests if the guest is running in PAE mode or not.
1529 *
1530 * @returns true if in PAE mode, otherwise false.
1531 * @param pVCpu The cross context virtual CPU structure.
1532 */
1533VMMDECL(bool) CPUMIsGuestInPAEMode(PCVMCPU pVCpu)
1534{
1535 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_EFER);
1536 /* Intel mentions EFER.LMA and EFER.LME in different parts of their spec. We shall use EFER.LMA rather
1537 than EFER.LME as it reflects if the CPU has entered paging with EFER.LME set. */
1538 return (pVCpu->cpum.s.Guest.cr4 & X86_CR4_PAE)
1539 && (pVCpu->cpum.s.Guest.cr0 & X86_CR0_PG)
1540 && !(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA);
1541}
1542
1543
1544/**
1545 * Tests if the guest is running in 64 bits mode or not.
1546 *
1547 * @returns true if in 64 bits protected mode, otherwise false.
1548 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1549 */
1550VMMDECL(bool) CPUMIsGuestIn64BitCode(PVMCPU pVCpu)
1551{
1552 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
1553 if (!CPUMIsGuestInLongMode(pVCpu))
1554 return false;
1555 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
1556 return pVCpu->cpum.s.Guest.cs.Attr.n.u1Long;
1557}
1558
1559
1560/**
1561 * Helper for CPUMIsGuestIn64BitCodeEx that handles lazy resolving of hidden CS
1562 * registers.
1563 *
1564 * @returns true if in 64 bits protected mode, otherwise false.
1565 * @param pCtx Pointer to the current guest CPU context.
1566 */
1567VMM_INT_DECL(bool) CPUMIsGuestIn64BitCodeSlow(PCPUMCTX pCtx)
1568{
1569 return CPUMIsGuestIn64BitCode(CPUM_GUEST_CTX_TO_VMCPU(pCtx));
1570}
1571
1572
1573/**
1574 * Sets the specified changed flags (CPUM_CHANGED_*).
1575 *
1576 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1577 * @param fChangedAdd The changed flags to add.
1578 */
1579VMMDECL(void) CPUMSetChangedFlags(PVMCPU pVCpu, uint32_t fChangedAdd)
1580{
1581 pVCpu->cpum.s.fChanged |= fChangedAdd;
1582}
1583
1584
1585/**
1586 * Checks if the CPU supports the XSAVE and XRSTOR instruction.
1587 *
1588 * @returns true if supported.
1589 * @returns false if not supported.
1590 * @param pVM The cross context VM structure.
1591 */
1592VMMDECL(bool) CPUMSupportsXSave(PVM pVM)
1593{
1594 return pVM->cpum.s.HostFeatures.fXSaveRstor != 0;
1595}
1596
1597
1598/**
1599 * Checks if the host OS uses the SYSENTER / SYSEXIT instructions.
1600 * @returns true if used.
1601 * @returns false if not used.
1602 * @param pVM The cross context VM structure.
1603 */
1604VMMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM)
1605{
1606 return RT_BOOL(pVM->cpum.s.fHostUseFlags & CPUM_USE_SYSENTER);
1607}
1608
1609
1610/**
1611 * Checks if the host OS uses the SYSCALL / SYSRET instructions.
1612 * @returns true if used.
1613 * @returns false if not used.
1614 * @param pVM The cross context VM structure.
1615 */
1616VMMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM)
1617{
1618 return RT_BOOL(pVM->cpum.s.fHostUseFlags & CPUM_USE_SYSCALL);
1619}
1620
1621
1622/**
1623 * Checks if we activated the FPU/XMM state of the guest OS.
1624 *
1625 * Obsolete: This differs from CPUMIsGuestFPUStateLoaded() in that it refers to
1626 * the next time we'll be executing guest code, so it may return true for
1627 * 64-on-32 when we still haven't actually loaded the FPU status, just scheduled
1628 * it to be loaded the next time we go thru the world switcher
1629 * (CPUM_SYNC_FPU_STATE).
1630 *
1631 * @returns true / false.
1632 * @param pVCpu The cross context virtual CPU structure.
1633 */
1634VMMDECL(bool) CPUMIsGuestFPUStateActive(PVMCPU pVCpu)
1635{
1636 bool fRet = RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU_GUEST);
1637 AssertMsg(fRet == pVCpu->cpum.s.Guest.fUsedFpuGuest, ("fRet=%d\n", fRet));
1638 return fRet;
1639}
1640
1641
1642/**
1643 * Checks if we've really loaded the FPU/XMM state of the guest OS.
1644 *
1645 * @returns true / false.
1646 * @param pVCpu The cross context virtual CPU structure.
1647 */
1648VMMDECL(bool) CPUMIsGuestFPUStateLoaded(PVMCPU pVCpu)
1649{
1650 bool fRet = RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU_GUEST);
1651 AssertMsg(fRet == pVCpu->cpum.s.Guest.fUsedFpuGuest, ("fRet=%d\n", fRet));
1652 return fRet;
1653}
1654
1655
1656/**
1657 * Checks if we saved the FPU/XMM state of the host OS.
1658 *
1659 * @returns true / false.
1660 * @param pVCpu The cross context virtual CPU structure.
1661 */
1662VMMDECL(bool) CPUMIsHostFPUStateSaved(PVMCPU pVCpu)
1663{
1664 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU_HOST);
1665}
1666
1667
1668/**
1669 * Checks if the guest debug state is active.
1670 *
1671 * @returns boolean
1672 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1673 */
1674VMMDECL(bool) CPUMIsGuestDebugStateActive(PVMCPU pVCpu)
1675{
1676 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_GUEST);
1677}
1678
1679
1680/**
1681 * Checks if the hyper debug state is active.
1682 *
1683 * @returns boolean
1684 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1685 */
1686VMMDECL(bool) CPUMIsHyperDebugStateActive(PVMCPU pVCpu)
1687{
1688 return RT_BOOL(pVCpu->cpum.s.fUseFlags & CPUM_USED_DEBUG_REGS_HYPER);
1689}
1690
1691
1692/**
1693 * Mark the guest's debug state as inactive.
1694 *
1695 * @returns boolean
1696 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1697 * @todo This API doesn't make sense any more.
1698 */
1699VMMDECL(void) CPUMDeactivateGuestDebugState(PVMCPU pVCpu)
1700{
1701 Assert(!(pVCpu->cpum.s.fUseFlags & (CPUM_USED_DEBUG_REGS_GUEST | CPUM_USED_DEBUG_REGS_HYPER | CPUM_USED_DEBUG_REGS_HOST)));
1702 NOREF(pVCpu);
1703}
1704
1705
1706/**
1707 * Get the current privilege level of the guest.
1708 *
1709 * @returns CPL
1710 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1711 */
1712VMMDECL(uint32_t) CPUMGetGuestCPL(PVMCPU pVCpu)
1713{
1714 /*
1715 * CPL can reliably be found in SS.DPL (hidden regs valid) or SS if not.
1716 *
1717 * Note! We used to check CS.DPL here, assuming it was always equal to
1718 * CPL even if a conforming segment was loaded. But this turned out to
1719 * only apply to older AMD-V. With VT-x we had an ACP2 regression
1720 * during install after a far call to ring 2 with VT-x. Then on newer
1721 * AMD-V CPUs we have to move the VMCB.guest.u8CPL into cs.Attr.n.u2Dpl
1722 * as well as ss.Attr.n.u2Dpl to make this (and other) code work right.
1723 *
1724 * So, forget CS.DPL, always use SS.DPL.
1725 *
1726 * Note! The SS RPL is always equal to the CPL, while the CS RPL
1727 * isn't necessarily equal if the segment is conforming.
1728 * See section 4.11.1 in the AMD manual.
1729 *
1730 * Update: Where the heck does it say CS.RPL can differ from CPL other than
1731 * right after real->prot mode switch and when in V8086 mode? That
1732 * section says the RPL specified in a direct transfere (call, jmp,
1733 * ret) is not the one loaded into CS. Besides, if CS.RPL != CPL
1734 * it would be impossible for an exception handle or the iret
1735 * instruction to figure out whether SS:ESP are part of the frame
1736 * or not. VBox or qemu bug must've lead to this misconception.
1737 *
1738 * Update2: On an AMD bulldozer system here, I've no trouble loading a null
1739 * selector into SS with an RPL other than the CPL when CPL != 3 and
1740 * we're in 64-bit mode. The intel dev box doesn't allow this, on
1741 * RPL = CPL. Weird.
1742 */
1743 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
1744 uint32_t uCpl;
1745 if (pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE)
1746 {
1747 if (!pVCpu->cpum.s.Guest.eflags.Bits.u1VM)
1748 {
1749 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.s.Guest.ss))
1750 uCpl = pVCpu->cpum.s.Guest.ss.Attr.n.u2Dpl;
1751 else
1752 uCpl = (pVCpu->cpum.s.Guest.ss.Sel & X86_SEL_RPL);
1753 }
1754 else
1755 uCpl = 3; /* V86 has CPL=3; REM doesn't set DPL=3 in V8086 mode. See @bugref{5130}. */
1756 }
1757 else
1758 uCpl = 0; /* Real mode is zero; CPL set to 3 for VT-x real-mode emulation. */
1759 return uCpl;
1760}
1761
1762
1763/**
1764 * Gets the current guest CPU mode.
1765 *
1766 * If paging mode is what you need, check out PGMGetGuestMode().
1767 *
1768 * @returns The CPU mode.
1769 * @param pVCpu The cross context virtual CPU structure.
1770 */
1771VMMDECL(CPUMMODE) CPUMGetGuestMode(PVMCPU pVCpu)
1772{
1773 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_EFER);
1774 CPUMMODE enmMode;
1775 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
1776 enmMode = CPUMMODE_REAL;
1777 else if (!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
1778 enmMode = CPUMMODE_PROTECTED;
1779 else
1780 enmMode = CPUMMODE_LONG;
1781
1782 return enmMode;
1783}
1784
1785
1786/**
1787 * Figure whether the CPU is currently executing 16, 32 or 64 bit code.
1788 *
1789 * @returns 16, 32 or 64.
1790 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1791 */
1792VMMDECL(uint32_t) CPUMGetGuestCodeBits(PVMCPU pVCpu)
1793{
1794 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_EFER | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CS);
1795
1796 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
1797 return 16;
1798
1799 if (pVCpu->cpum.s.Guest.eflags.Bits.u1VM)
1800 {
1801 Assert(!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA));
1802 return 16;
1803 }
1804
1805 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
1806 if ( pVCpu->cpum.s.Guest.cs.Attr.n.u1Long
1807 && (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
1808 return 64;
1809
1810 if (pVCpu->cpum.s.Guest.cs.Attr.n.u1DefBig)
1811 return 32;
1812
1813 return 16;
1814}
1815
1816
1817VMMDECL(DISCPUMODE) CPUMGetGuestDisMode(PVMCPU pVCpu)
1818{
1819 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_EFER | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CS);
1820
1821 if (!(pVCpu->cpum.s.Guest.cr0 & X86_CR0_PE))
1822 return DISCPUMODE_16BIT;
1823
1824 if (pVCpu->cpum.s.Guest.eflags.Bits.u1VM)
1825 {
1826 Assert(!(pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA));
1827 return DISCPUMODE_16BIT;
1828 }
1829
1830 CPUMSELREG_LAZY_LOAD_HIDDEN_PARTS(pVCpu, &pVCpu->cpum.s.Guest.cs);
1831 if ( pVCpu->cpum.s.Guest.cs.Attr.n.u1Long
1832 && (pVCpu->cpum.s.Guest.msrEFER & MSR_K6_EFER_LMA))
1833 return DISCPUMODE_64BIT;
1834
1835 if (pVCpu->cpum.s.Guest.cs.Attr.n.u1DefBig)
1836 return DISCPUMODE_32BIT;
1837
1838 return DISCPUMODE_16BIT;
1839}
1840
1841
1842/**
1843 * Gets the guest MXCSR_MASK value.
1844 *
1845 * This does not access the x87 state, but the value we determined at VM
1846 * initialization.
1847 *
1848 * @returns MXCSR mask.
1849 * @param pVM The cross context VM structure.
1850 */
1851VMMDECL(uint32_t) CPUMGetGuestMxCsrMask(PVM pVM)
1852{
1853 return pVM->cpum.s.GuestInfo.fMxCsrMask;
1854}
1855
1856
1857/**
1858 * Returns whether the guest has physical interrupts enabled.
1859 *
1860 * @returns @c true if interrupts are enabled, @c false otherwise.
1861 * @param pVCpu The cross context virtual CPU structure.
1862 *
1863 * @remarks Warning! This function does -not- take into account the global-interrupt
1864 * flag (GIF).
1865 */
1866VMM_INT_DECL(bool) CPUMIsGuestPhysIntrEnabled(PVMCPU pVCpu)
1867{
1868 if (!CPUMIsGuestInNestedHwvirtMode(&pVCpu->cpum.s.Guest))
1869 {
1870 uint32_t const fEFlags = pVCpu->cpum.s.Guest.eflags.u;
1871 return RT_BOOL(fEFlags & X86_EFL_IF);
1872 }
1873
1874 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.s.Guest))
1875 return CPUMIsGuestVmxPhysIntrEnabled(&pVCpu->cpum.s.Guest);
1876
1877 Assert(CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.s.Guest));
1878 return CPUMIsGuestSvmPhysIntrEnabled(pVCpu, &pVCpu->cpum.s.Guest);
1879}
1880
1881
1882/**
1883 * Returns whether the nested-guest has virtual interrupts enabled.
1884 *
1885 * @returns @c true if interrupts are enabled, @c false otherwise.
1886 * @param pVCpu The cross context virtual CPU structure.
1887 *
1888 * @remarks Warning! This function does -not- take into account the global-interrupt
1889 * flag (GIF).
1890 */
1891VMM_INT_DECL(bool) CPUMIsGuestVirtIntrEnabled(PVMCPU pVCpu)
1892{
1893 PCCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
1894 Assert(CPUMIsGuestInNestedHwvirtMode(pCtx));
1895
1896 if (CPUMIsGuestInVmxNonRootMode(pCtx))
1897 return CPUMIsGuestVmxVirtIntrEnabled(pCtx);
1898
1899 Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
1900 return CPUMIsGuestSvmVirtIntrEnabled(pVCpu, pCtx);
1901}
1902
1903
1904/**
1905 * Calculates the interruptiblity of the guest.
1906 *
1907 * @returns Interruptibility level.
1908 * @param pVCpu The cross context virtual CPU structure.
1909 */
1910VMM_INT_DECL(CPUMINTERRUPTIBILITY) CPUMGetGuestInterruptibility(PVMCPU pVCpu)
1911{
1912#if 1
1913 /* Global-interrupt flag blocks pretty much everything we care about here. */
1914 if (CPUMGetGuestGif(&pVCpu->cpum.s.Guest))
1915 {
1916 /*
1917 * Physical interrupts are primarily blocked using EFLAGS. However, we cannot access
1918 * it directly here. If and how EFLAGS are used depends on the context (nested-guest
1919 * or raw-mode). Hence we use the function below which handles the details.
1920 */
1921 if ( CPUMIsGuestPhysIntrEnabled(pVCpu)
1922 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_BLOCK_NMIS | VMCPU_FF_INHIBIT_INTERRUPTS))
1923 {
1924 if ( !CPUMIsGuestInNestedHwvirtMode(&pVCpu->cpum.s.Guest)
1925 || CPUMIsGuestVirtIntrEnabled(pVCpu))
1926 return CPUMINTERRUPTIBILITY_UNRESTRAINED;
1927
1928 /* Physical interrupts are enabled, but nested-guest virtual interrupts are disabled. */
1929 return CPUMINTERRUPTIBILITY_VIRT_INT_DISABLED;
1930 }
1931
1932 /*
1933 * Blocking the delivery of NMIs during an interrupt shadow is CPU implementation
1934 * specific. Therefore, in practice, we can't deliver an NMI in an interrupt shadow.
1935 * However, there is some uncertainity regarding the converse, i.e. whether
1936 * NMI-blocking until IRET blocks delivery of physical interrupts.
1937 *
1938 * See Intel spec. 25.4.1 "Event Blocking".
1939 */
1940 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
1941 return CPUMINTERRUPTIBILITY_NMI_INHIBIT;
1942
1943 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
1944 return CPUMINTERRUPTIBILITY_INT_INHIBITED;
1945
1946 return CPUMINTERRUPTIBILITY_INT_DISABLED;
1947 }
1948 return CPUMINTERRUPTIBILITY_GLOBAL_INHIBIT;
1949#else
1950 if (pVCpu->cpum.s.Guest.rflags.Bits.u1IF)
1951 {
1952 if (pVCpu->cpum.s.Guest.hwvirt.fGif)
1953 {
1954 if (!VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_BLOCK_NMIS | VMCPU_FF_INHIBIT_INTERRUPTS))
1955 return CPUMINTERRUPTIBILITY_UNRESTRAINED;
1956
1957 /** @todo does blocking NMIs mean interrupts are also inhibited? */
1958 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
1959 {
1960 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
1961 return CPUMINTERRUPTIBILITY_INT_INHIBITED;
1962 return CPUMINTERRUPTIBILITY_NMI_INHIBIT;
1963 }
1964 AssertFailed();
1965 return CPUMINTERRUPTIBILITY_NMI_INHIBIT;
1966 }
1967 return CPUMINTERRUPTIBILITY_GLOBAL_INHIBIT;
1968 }
1969 else
1970 {
1971 if (pVCpu->cpum.s.Guest.hwvirt.fGif)
1972 {
1973 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
1974 return CPUMINTERRUPTIBILITY_NMI_INHIBIT;
1975 return CPUMINTERRUPTIBILITY_INT_DISABLED;
1976 }
1977 return CPUMINTERRUPTIBILITY_GLOBAL_INHIBIT;
1978 }
1979#endif
1980}
1981
1982
1983/**
1984 * Gets whether the guest (or nested-guest) is currently blocking delivery of NMIs.
1985 *
1986 * @returns @c true if NMIs are blocked, @c false otherwise.
1987 * @param pVCpu The cross context virtual CPU structure.
1988 */
1989VMM_INT_DECL(bool) CPUMIsGuestNmiBlocking(PCVMCPU pVCpu)
1990{
1991 /*
1992 * Return the state of guest-NMI blocking in any of the following cases:
1993 * - We're not executing a nested-guest.
1994 * - We're executing an SVM nested-guest[1].
1995 * - We're executing a VMX nested-guest without virtual-NMIs enabled.
1996 *
1997 * [1] -- SVM does not support virtual-NMIs or virtual-NMI blocking.
1998 * SVM hypervisors must track NMI blocking themselves by intercepting
1999 * the IRET instruction after injection of an NMI.
2000 */
2001 PCCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
2002 if ( !CPUMIsGuestInNestedHwvirtMode(pCtx)
2003 || CPUMIsGuestInSvmNestedHwVirtMode(pCtx)
2004 || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI))
2005 return VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
2006
2007 /*
2008 * Return the state of virtual-NMI blocking, if we are executing a
2009 * VMX nested-guest with virtual-NMIs enabled.
2010 */
2011 return CPUMIsGuestVmxVirtNmiBlocking(pCtx);
2012}
2013
2014
2015/**
2016 * Sets blocking delivery of NMIs to the guest.
2017 *
2018 * @param pVCpu The cross context virtual CPU structure.
2019 * @param fBlock Whether NMIs are blocked or not.
2020 */
2021VMM_INT_DECL(void) CPUMSetGuestNmiBlocking(PVMCPU pVCpu, bool fBlock)
2022{
2023 /*
2024 * Set the state of guest-NMI blocking in any of the following cases:
2025 * - We're not executing a nested-guest.
2026 * - We're executing an SVM nested-guest[1].
2027 * - We're executing a VMX nested-guest without virtual-NMIs enabled.
2028 *
2029 * [1] -- SVM does not support virtual-NMIs or virtual-NMI blocking.
2030 * SVM hypervisors must track NMI blocking themselves by intercepting
2031 * the IRET instruction after injection of an NMI.
2032 */
2033 PCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
2034 if ( !CPUMIsGuestInNestedHwvirtMode(pCtx)
2035 || CPUMIsGuestInSvmNestedHwVirtMode(pCtx)
2036 || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI))
2037 {
2038 if (fBlock)
2039 {
2040 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
2041 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
2042 }
2043 else
2044 {
2045 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
2046 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
2047 }
2048 return;
2049 }
2050
2051 /*
2052 * Set the state of virtual-NMI blocking, if we are executing a
2053 * VMX nested-guest with virtual-NMIs enabled.
2054 */
2055 return CPUMSetGuestVmxVirtNmiBlocking(pCtx, fBlock);
2056}
2057
2058
2059/**
2060 * Checks whether the SVM nested-guest has physical interrupts enabled.
2061 *
2062 * @returns true if interrupts are enabled, false otherwise.
2063 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2064 * @param pCtx The guest-CPU context.
2065 *
2066 * @remarks This does -not- take into account the global-interrupt flag.
2067 */
2068VMM_INT_DECL(bool) CPUMIsGuestSvmPhysIntrEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx)
2069{
2070 /** @todo Optimization: Avoid this function call and use a pointer to the
2071 * relevant eflags instead (setup during VMRUN instruction emulation). */
2072 Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
2073
2074 X86EFLAGS fEFlags;
2075 if (CPUMIsGuestSvmVirtIntrMasking(pVCpu, pCtx))
2076 fEFlags.u = pCtx->hwvirt.svm.HostState.rflags.u;
2077 else
2078 fEFlags.u = pCtx->eflags.u;
2079
2080 return fEFlags.Bits.u1IF;
2081}
2082
2083
2084/**
2085 * Checks whether the SVM nested-guest is in a state to receive virtual (setup
2086 * for injection by VMRUN instruction) interrupts.
2087 *
2088 * @returns VBox status code.
2089 * @retval true if it's ready, false otherwise.
2090 *
2091 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2092 * @param pCtx The guest-CPU context.
2093 */
2094VMM_INT_DECL(bool) CPUMIsGuestSvmVirtIntrEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx)
2095{
2096 RT_NOREF(pVCpu);
2097 Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
2098
2099 PCSVMVMCBCTRL pVmcbCtrl = &pCtx->hwvirt.svm.Vmcb.ctrl;
2100 PCSVMINTCTRL pVmcbIntCtrl = &pVmcbCtrl->IntCtrl;
2101 Assert(!pVmcbIntCtrl->n.u1VGifEnable); /* We don't support passing virtual-GIF feature to the guest yet. */
2102 if ( !pVmcbIntCtrl->n.u1IgnoreTPR
2103 && pVmcbIntCtrl->n.u4VIntrPrio <= pVmcbIntCtrl->n.u8VTPR)
2104 return false;
2105
2106 return RT_BOOL(pCtx->eflags.u & X86_EFL_IF);
2107}
2108
2109
2110/**
2111 * Gets the pending SVM nested-guest interruptvector.
2112 *
2113 * @returns The nested-guest interrupt to inject.
2114 * @param pCtx The guest-CPU context.
2115 */
2116VMM_INT_DECL(uint8_t) CPUMGetGuestSvmVirtIntrVector(PCCPUMCTX pCtx)
2117{
2118 return pCtx->hwvirt.svm.Vmcb.ctrl.IntCtrl.n.u8VIntrVector;
2119}
2120
2121
2122/**
2123 * Restores the host-state from the host-state save area as part of a \#VMEXIT.
2124 *
2125 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2126 * @param pCtx The guest-CPU context.
2127 */
2128VMM_INT_DECL(void) CPUMSvmVmExitRestoreHostState(PVMCPUCC pVCpu, PCPUMCTX pCtx)
2129{
2130 /*
2131 * Reload the guest's "host state".
2132 */
2133 PSVMHOSTSTATE pHostState = &pCtx->hwvirt.svm.HostState;
2134 pCtx->es = pHostState->es;
2135 pCtx->cs = pHostState->cs;
2136 pCtx->ss = pHostState->ss;
2137 pCtx->ds = pHostState->ds;
2138 pCtx->gdtr = pHostState->gdtr;
2139 pCtx->idtr = pHostState->idtr;
2140 CPUMSetGuestEferMsrNoChecks(pVCpu, pCtx->msrEFER, pHostState->uEferMsr);
2141 CPUMSetGuestCR0(pVCpu, pHostState->uCr0 | X86_CR0_PE);
2142 pCtx->cr3 = pHostState->uCr3;
2143 CPUMSetGuestCR4(pVCpu, pHostState->uCr4);
2144 pCtx->rflags = pHostState->rflags;
2145 pCtx->rflags.Bits.u1VM = 0;
2146 pCtx->rip = pHostState->uRip;
2147 pCtx->rsp = pHostState->uRsp;
2148 pCtx->rax = pHostState->uRax;
2149 pCtx->dr[7] &= ~(X86_DR7_ENABLED_MASK | X86_DR7_RAZ_MASK | X86_DR7_MBZ_MASK);
2150 pCtx->dr[7] |= X86_DR7_RA1_MASK;
2151 Assert(pCtx->ss.Attr.n.u2Dpl == 0);
2152
2153 /** @todo if RIP is not canonical or outside the CS segment limit, we need to
2154 * raise \#GP(0) in the guest. */
2155
2156 /** @todo check the loaded host-state for consistency. Figure out what
2157 * exactly this involves? */
2158}
2159
2160
2161/**
2162 * Saves the host-state to the host-state save area as part of a VMRUN.
2163 *
2164 * @param pCtx The guest-CPU context.
2165 * @param cbInstr The length of the VMRUN instruction in bytes.
2166 */
2167VMM_INT_DECL(void) CPUMSvmVmRunSaveHostState(PCPUMCTX pCtx, uint8_t cbInstr)
2168{
2169 PSVMHOSTSTATE pHostState = &pCtx->hwvirt.svm.HostState;
2170 pHostState->es = pCtx->es;
2171 pHostState->cs = pCtx->cs;
2172 pHostState->ss = pCtx->ss;
2173 pHostState->ds = pCtx->ds;
2174 pHostState->gdtr = pCtx->gdtr;
2175 pHostState->idtr = pCtx->idtr;
2176 pHostState->uEferMsr = pCtx->msrEFER;
2177 pHostState->uCr0 = pCtx->cr0;
2178 pHostState->uCr3 = pCtx->cr3;
2179 pHostState->uCr4 = pCtx->cr4;
2180 pHostState->rflags = pCtx->rflags;
2181 pHostState->uRip = pCtx->rip + cbInstr;
2182 pHostState->uRsp = pCtx->rsp;
2183 pHostState->uRax = pCtx->rax;
2184}
2185
2186
2187/**
2188 * Applies the TSC offset of a nested-guest if any and returns the TSC value for the
2189 * nested-guest.
2190 *
2191 * @returns The TSC offset after applying any nested-guest TSC offset.
2192 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2193 * @param uTscValue The guest TSC.
2194 *
2195 * @sa CPUMRemoveNestedGuestTscOffset.
2196 */
2197VMM_INT_DECL(uint64_t) CPUMApplyNestedGuestTscOffset(PCVMCPU pVCpu, uint64_t uTscValue)
2198{
2199 PCCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
2200 if (CPUMIsGuestInVmxNonRootMode(pCtx))
2201 {
2202 if (CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_USE_TSC_OFFSETTING))
2203 return uTscValue + pCtx->hwvirt.vmx.Vmcs.u64TscOffset.u;
2204 return uTscValue;
2205 }
2206
2207 if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
2208 {
2209 uint64_t offTsc;
2210 if (!HMGetGuestSvmTscOffset(pVCpu, &offTsc))
2211 offTsc = pCtx->hwvirt.svm.Vmcb.ctrl.u64TSCOffset;
2212 return uTscValue + offTsc;
2213 }
2214 return uTscValue;
2215}
2216
2217
2218/**
2219 * Removes the TSC offset of a nested-guest if any and returns the TSC value for the
2220 * guest.
2221 *
2222 * @returns The TSC offset after removing any nested-guest TSC offset.
2223 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2224 * @param uTscValue The nested-guest TSC.
2225 *
2226 * @sa CPUMApplyNestedGuestTscOffset.
2227 */
2228VMM_INT_DECL(uint64_t) CPUMRemoveNestedGuestTscOffset(PCVMCPU pVCpu, uint64_t uTscValue)
2229{
2230 PCCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
2231 if (CPUMIsGuestInVmxNonRootMode(pCtx))
2232 {
2233 if (CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_USE_TSC_OFFSETTING))
2234 return uTscValue - pCtx->hwvirt.vmx.Vmcs.u64TscOffset.u;
2235 return uTscValue;
2236 }
2237
2238 if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
2239 {
2240 uint64_t offTsc;
2241 if (!HMGetGuestSvmTscOffset(pVCpu, &offTsc))
2242 offTsc = pCtx->hwvirt.svm.Vmcb.ctrl.u64TSCOffset;
2243 return uTscValue - offTsc;
2244 }
2245 return uTscValue;
2246}
2247
2248
2249/**
2250 * Used to dynamically imports state residing in NEM or HM.
2251 *
2252 * This is a worker for the CPUM_IMPORT_EXTRN_RET() macro and various IEM ones.
2253 *
2254 * @returns VBox status code.
2255 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2256 * @param fExtrnImport The fields to import.
2257 * @thread EMT(pVCpu)
2258 */
2259VMM_INT_DECL(int) CPUMImportGuestStateOnDemand(PVMCPUCC pVCpu, uint64_t fExtrnImport)
2260{
2261 VMCPU_ASSERT_EMT(pVCpu);
2262 if (pVCpu->cpum.s.Guest.fExtrn & fExtrnImport)
2263 {
2264 switch (pVCpu->cpum.s.Guest.fExtrn & CPUMCTX_EXTRN_KEEPER_MASK)
2265 {
2266 case CPUMCTX_EXTRN_KEEPER_NEM:
2267 {
2268 int rc = NEMImportStateOnDemand(pVCpu, fExtrnImport);
2269 Assert(rc == VINF_SUCCESS || RT_FAILURE_NP(rc));
2270 return rc;
2271 }
2272
2273 case CPUMCTX_EXTRN_KEEPER_HM:
2274 {
2275#ifdef IN_RING0
2276 int rc = HMR0ImportStateOnDemand(pVCpu, fExtrnImport);
2277 Assert(rc == VINF_SUCCESS || RT_FAILURE_NP(rc));
2278 return rc;
2279#else
2280 AssertLogRelMsgFailed(("TODO Fetch HM state: %#RX64 vs %#RX64\n", pVCpu->cpum.s.Guest.fExtrn, fExtrnImport));
2281 return VINF_SUCCESS;
2282#endif
2283 }
2284 default:
2285 AssertLogRelMsgFailedReturn(("%#RX64 vs %#RX64\n", pVCpu->cpum.s.Guest.fExtrn, fExtrnImport), VERR_CPUM_IPE_2);
2286 }
2287 }
2288 return VINF_SUCCESS;
2289}
2290
2291
2292/**
2293 * Gets valid CR4 bits for the guest.
2294 *
2295 * @returns Valid CR4 bits.
2296 * @param pVM The cross context VM structure.
2297 */
2298VMM_INT_DECL(uint64_t) CPUMGetGuestCR4ValidMask(PVM pVM)
2299{
2300 PCCPUMFEATURES pGuestFeatures = &pVM->cpum.s.GuestFeatures;
2301 uint64_t fMask = X86_CR4_VME | X86_CR4_PVI
2302 | X86_CR4_TSD | X86_CR4_DE
2303 | X86_CR4_MCE | X86_CR4_PCE;
2304 if (pGuestFeatures->fPae)
2305 fMask |= X86_CR4_PAE;
2306 if (pGuestFeatures->fPge)
2307 fMask |= X86_CR4_PGE;
2308 if (pGuestFeatures->fPse)
2309 fMask |= X86_CR4_PSE;
2310 if (pGuestFeatures->fFxSaveRstor)
2311 fMask |= X86_CR4_OSFXSR;
2312 if (pGuestFeatures->fVmx)
2313 fMask |= X86_CR4_VMXE;
2314 if (pGuestFeatures->fXSaveRstor)
2315 fMask |= X86_CR4_OSXSAVE;
2316 if (pGuestFeatures->fPcid)
2317 fMask |= X86_CR4_PCIDE;
2318 if (pGuestFeatures->fFsGsBase)
2319 fMask |= X86_CR4_FSGSBASE;
2320 if (pGuestFeatures->fSse)
2321 fMask |= X86_CR4_OSXMMEEXCPT;
2322 return fMask;
2323}
2324
2325
2326/**
2327 * Sets the PAE PDPEs for the guest.
2328 *
2329 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2330 * @param paPaePdpes The PAE PDPEs to set.
2331 */
2332VMM_INT_DECL(void) CPUMSetGuestPaePdpes(PVMCPU pVCpu, PCX86PDPE paPaePdpes)
2333{
2334 Assert(paPaePdpes);
2335 for (unsigned i = 0; i < RT_ELEMENTS(pVCpu->cpum.s.Guest.aPaePdpes); i++)
2336 pVCpu->cpum.s.Guest.aPaePdpes[i].u = paPaePdpes[i].u;
2337 pVCpu->cpum.s.Guest.fExtrn &= ~CPUMCTX_EXTRN_CR3;
2338}
2339
2340
2341/**
2342 * Gets the PAE PDPTEs for the guest.
2343 *
2344 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2345 * @param paPaePdpes Where to store the PAE PDPEs.
2346 */
2347VMM_INT_DECL(void) CPUMGetGuestPaePdpes(PVMCPU pVCpu, PX86PDPE paPaePdpes)
2348{
2349 Assert(paPaePdpes);
2350 CPUM_INT_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_CR3);
2351 for (unsigned i = 0; i < RT_ELEMENTS(pVCpu->cpum.s.Guest.aPaePdpes); i++)
2352 paPaePdpes[i].u = pVCpu->cpum.s.Guest.aPaePdpes[i].u;
2353}
2354
2355
2356/**
2357 * Starts a VMX-preemption timer to expire as specified by the nested hypervisor.
2358 *
2359 * @returns VBox status code.
2360 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2361 * @param uTimer The VMCS preemption timer value.
2362 * @param cShift The VMX-preemption timer shift (usually based on guest
2363 * VMX MSR rate).
2364 * @param pu64EntryTick Where to store the current tick when the timer is
2365 * programmed.
2366 * @thread EMT(pVCpu)
2367 */
2368VMM_INT_DECL(int) CPUMStartGuestVmxPremptTimer(PVMCPUCC pVCpu, uint32_t uTimer, uint8_t cShift, uint64_t *pu64EntryTick)
2369{
2370 Assert(uTimer);
2371 Assert(cShift <= 31);
2372 Assert(pu64EntryTick);
2373 VMCPU_ASSERT_EMT(pVCpu);
2374 uint64_t const cTicksToNext = uTimer << cShift;
2375 return TMTimerSetRelative(pVCpu->CTX_SUFF(pVM), pVCpu->cpum.s.hNestedVmxPreemptTimer, cTicksToNext, pu64EntryTick);
2376}
2377
2378
2379/**
2380 * Stops the VMX-preemption timer from firing.
2381 *
2382 * @returns VBox status code.
2383 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2384 * @thread EMT.
2385 *
2386 * @remarks This can be called during VM reset, so we cannot assume it will be on
2387 * the EMT corresponding to @c pVCpu.
2388 */
2389VMM_INT_DECL(int) CPUMStopGuestVmxPremptTimer(PVMCPUCC pVCpu)
2390{
2391 /*
2392 * CPUM gets initialized before TM, so we defer creation of timers till CPUMR3InitCompleted().
2393 * However, we still get called during CPUMR3Init() and hence we need to check if we have
2394 * a valid timer object before trying to stop it.
2395 */
2396 int rc;
2397 TMTIMERHANDLE hTimer = pVCpu->cpum.s.hNestedVmxPreemptTimer;
2398 if (hTimer != NIL_TMTIMERHANDLE)
2399 {
2400 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2401 rc = TMTimerLock(pVM, hTimer, VERR_IGNORED);
2402 if (rc == VINF_SUCCESS)
2403 {
2404 if (TMTimerIsActive(pVM, hTimer))
2405 TMTimerStop(pVM, hTimer);
2406 TMTimerUnlock(pVM, hTimer);
2407 }
2408 }
2409 else
2410 rc = VERR_NOT_FOUND;
2411 return rc;
2412}
2413
2414
2415/**
2416 * Gets the read and write permission bits for an MSR in an MSR bitmap.
2417 *
2418 * @returns VMXMSRPM_XXX - the MSR permission.
2419 * @param pvMsrBitmap Pointer to the MSR bitmap.
2420 * @param idMsr The MSR to get permissions for.
2421 *
2422 * @sa hmR0VmxSetMsrPermission.
2423 */
2424VMM_INT_DECL(uint32_t) CPUMGetVmxMsrPermission(void const *pvMsrBitmap, uint32_t idMsr)
2425{
2426 AssertPtrReturn(pvMsrBitmap, VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR);
2427
2428 uint8_t const * const pbMsrBitmap = (uint8_t const * const)pvMsrBitmap;
2429
2430 /*
2431 * MSR Layout:
2432 * Byte index MSR range Interpreted as
2433 * 0x000 - 0x3ff 0x00000000 - 0x00001fff Low MSR read bits.
2434 * 0x400 - 0x7ff 0xc0000000 - 0xc0001fff High MSR read bits.
2435 * 0x800 - 0xbff 0x00000000 - 0x00001fff Low MSR write bits.
2436 * 0xc00 - 0xfff 0xc0000000 - 0xc0001fff High MSR write bits.
2437 *
2438 * A bit corresponding to an MSR within the above range causes a VM-exit
2439 * if the bit is 1 on executions of RDMSR/WRMSR. If an MSR falls out of
2440 * the MSR range, it always cause a VM-exit.
2441 *
2442 * See Intel spec. 24.6.9 "MSR-Bitmap Address".
2443 */
2444 uint32_t const offBitmapRead = 0;
2445 uint32_t const offBitmapWrite = 0x800;
2446 uint32_t offMsr;
2447 uint32_t iBit;
2448 if (idMsr <= UINT32_C(0x00001fff))
2449 {
2450 offMsr = 0;
2451 iBit = idMsr;
2452 }
2453 else if (idMsr - UINT32_C(0xc0000000) <= UINT32_C(0x00001fff))
2454 {
2455 offMsr = 0x400;
2456 iBit = idMsr - UINT32_C(0xc0000000);
2457 }
2458 else
2459 {
2460 LogFunc(("Warning! Out of range MSR %#RX32\n", idMsr));
2461 return VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR;
2462 }
2463
2464 /*
2465 * Get the MSR read permissions.
2466 */
2467 uint32_t fRet;
2468 uint32_t const offMsrRead = offBitmapRead + offMsr;
2469 Assert(offMsrRead + (iBit >> 3) < offBitmapWrite);
2470 if (ASMBitTest(pbMsrBitmap + offMsrRead, iBit))
2471 fRet = VMXMSRPM_EXIT_RD;
2472 else
2473 fRet = VMXMSRPM_ALLOW_RD;
2474
2475 /*
2476 * Get the MSR write permissions.
2477 */
2478 uint32_t const offMsrWrite = offBitmapWrite + offMsr;
2479 Assert(offMsrWrite + (iBit >> 3) < X86_PAGE_4K_SIZE);
2480 if (ASMBitTest(pbMsrBitmap + offMsrWrite, iBit))
2481 fRet |= VMXMSRPM_EXIT_WR;
2482 else
2483 fRet |= VMXMSRPM_ALLOW_WR;
2484
2485 Assert(VMXMSRPM_IS_FLAG_VALID(fRet));
2486 return fRet;
2487}
2488
2489
2490/**
2491 * Checks the permission bits for the specified I/O port from the given I/O bitmap
2492 * to see if causes a VM-exit.
2493 *
2494 * @returns @c true if the I/O port access must cause a VM-exit, @c false otherwise.
2495 * @param pbIoBitmap Pointer to I/O bitmap.
2496 * @param uPort The I/O port being accessed.
2497 * @param cbAccess e size of the I/O access in bytes (1, 2 or 4 bytes).
2498 */
2499static bool cpumGetVmxIoBitmapPermission(uint8_t const *pbIoBitmap, uint16_t uPort, uint8_t cbAccess)
2500{
2501 Assert(cbAccess == 1 || cbAccess == 2 || cbAccess == 4);
2502
2503 /*
2504 * If the I/O port access wraps around the 16-bit port I/O space, we must cause a
2505 * VM-exit.
2506 *
2507 * Reading 1, 2, 4 bytes at ports 0xffff, 0xfffe and 0xfffc are valid and do not
2508 * constitute a wrap around. However, reading 2 bytes at port 0xffff or 4 bytes
2509 * from port 0xffff/0xfffe/0xfffd constitute a wrap around. In other words, any
2510 * access to -both- ports 0xffff and port 0 is a wrap around.
2511 *
2512 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
2513 */
2514 uint32_t const uPortLast = uPort + cbAccess;
2515 if (uPortLast > 0x10000)
2516 return true;
2517
2518 /*
2519 * If any bit corresponding to the I/O access is set, we must cause a VM-exit.
2520 */
2521 uint16_t const offPerm = uPort >> 3; /* Byte offset of the port. */
2522 uint16_t const idxPermBit = uPort - (offPerm << 3); /* Bit offset within byte. */
2523 Assert(idxPermBit < 8);
2524 static const uint8_t s_afMask[] = { 0x0, 0x1, 0x3, 0x7, 0xf }; /* Bit-mask for all access sizes. */
2525 uint16_t const fMask = s_afMask[cbAccess] << idxPermBit; /* Bit-mask of the access. */
2526
2527 /* Fetch 8 or 16-bits depending on whether the access spans 8-bit boundary. */
2528 RTUINT16U uPerm;
2529 uPerm.s.Lo = pbIoBitmap[offPerm];
2530 if (idxPermBit + cbAccess > 8)
2531 uPerm.s.Hi = pbIoBitmap[offPerm + 1];
2532 else
2533 uPerm.s.Hi = 0;
2534
2535 /* If any bit for the access is 1, we must cause a VM-exit. */
2536 if (uPerm.u & fMask)
2537 return true;
2538
2539 return false;
2540}
2541
2542
2543/**
2544 * Returns whether the given VMCS field is valid and supported for the guest.
2545 *
2546 * @param pVM The cross context VM structure.
2547 * @param u64VmcsField The VMCS field.
2548 *
2549 * @remarks This takes into account the CPU features exposed to the guest.
2550 */
2551VMM_INT_DECL(bool) CPUMIsGuestVmxVmcsFieldValid(PVMCC pVM, uint64_t u64VmcsField)
2552{
2553 uint32_t const uFieldEncHi = RT_HI_U32(u64VmcsField);
2554 uint32_t const uFieldEncLo = RT_LO_U32(u64VmcsField);
2555 if (!uFieldEncHi)
2556 { /* likely */ }
2557 else
2558 return false;
2559
2560 PCCPUMFEATURES pFeat = &pVM->cpum.s.GuestFeatures;
2561 switch (uFieldEncLo)
2562 {
2563 /*
2564 * 16-bit fields.
2565 */
2566 /* Control fields. */
2567 case VMX_VMCS16_VPID: return pFeat->fVmxVpid;
2568 case VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR: return pFeat->fVmxPostedInt;
2569 case VMX_VMCS16_EPTP_INDEX: return pFeat->fVmxEptXcptVe;
2570
2571 /* Guest-state fields. */
2572 case VMX_VMCS16_GUEST_ES_SEL:
2573 case VMX_VMCS16_GUEST_CS_SEL:
2574 case VMX_VMCS16_GUEST_SS_SEL:
2575 case VMX_VMCS16_GUEST_DS_SEL:
2576 case VMX_VMCS16_GUEST_FS_SEL:
2577 case VMX_VMCS16_GUEST_GS_SEL:
2578 case VMX_VMCS16_GUEST_LDTR_SEL:
2579 case VMX_VMCS16_GUEST_TR_SEL: return true;
2580 case VMX_VMCS16_GUEST_INTR_STATUS: return pFeat->fVmxVirtIntDelivery;
2581 case VMX_VMCS16_GUEST_PML_INDEX: return pFeat->fVmxPml;
2582
2583 /* Host-state fields. */
2584 case VMX_VMCS16_HOST_ES_SEL:
2585 case VMX_VMCS16_HOST_CS_SEL:
2586 case VMX_VMCS16_HOST_SS_SEL:
2587 case VMX_VMCS16_HOST_DS_SEL:
2588 case VMX_VMCS16_HOST_FS_SEL:
2589 case VMX_VMCS16_HOST_GS_SEL:
2590 case VMX_VMCS16_HOST_TR_SEL: return true;
2591
2592 /*
2593 * 64-bit fields.
2594 */
2595 /* Control fields. */
2596 case VMX_VMCS64_CTRL_IO_BITMAP_A_FULL:
2597 case VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH:
2598 case VMX_VMCS64_CTRL_IO_BITMAP_B_FULL:
2599 case VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH: return pFeat->fVmxUseIoBitmaps;
2600 case VMX_VMCS64_CTRL_MSR_BITMAP_FULL:
2601 case VMX_VMCS64_CTRL_MSR_BITMAP_HIGH: return pFeat->fVmxUseMsrBitmaps;
2602 case VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL:
2603 case VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH:
2604 case VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL:
2605 case VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH:
2606 case VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL:
2607 case VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH:
2608 case VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL:
2609 case VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH: return true;
2610 case VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL:
2611 case VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH: return pFeat->fVmxPml;
2612 case VMX_VMCS64_CTRL_TSC_OFFSET_FULL:
2613 case VMX_VMCS64_CTRL_TSC_OFFSET_HIGH: return true;
2614 case VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL:
2615 case VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH: return pFeat->fVmxUseTprShadow;
2616 case VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL:
2617 case VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH: return pFeat->fVmxVirtApicAccess;
2618 case VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL:
2619 case VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH: return pFeat->fVmxPostedInt;
2620 case VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL:
2621 case VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH: return pFeat->fVmxVmFunc;
2622 case VMX_VMCS64_CTRL_EPTP_FULL:
2623 case VMX_VMCS64_CTRL_EPTP_HIGH: return pFeat->fVmxEpt;
2624 case VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL:
2625 case VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH:
2626 case VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL:
2627 case VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH:
2628 case VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL:
2629 case VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH:
2630 case VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL:
2631 case VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH: return pFeat->fVmxVirtIntDelivery;
2632 case VMX_VMCS64_CTRL_EPTP_LIST_FULL:
2633 case VMX_VMCS64_CTRL_EPTP_LIST_HIGH:
2634 {
2635 PCVMCPU pVCpu = pVM->CTX_SUFF(apCpus)[0];
2636 uint64_t const uVmFuncMsr = pVCpu->cpum.s.Guest.hwvirt.vmx.Msrs.u64VmFunc;
2637 return RT_BOOL(RT_BF_GET(uVmFuncMsr, VMX_BF_VMFUNC_EPTP_SWITCHING));
2638 }
2639 case VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL:
2640 case VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH:
2641 case VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL:
2642 case VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH: return pFeat->fVmxVmcsShadowing;
2643 case VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_FULL:
2644 case VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_HIGH: return pFeat->fVmxEptXcptVe;
2645 case VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL:
2646 case VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH: return pFeat->fVmxXsavesXrstors;
2647 case VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL:
2648 case VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH: return pFeat->fVmxUseTscScaling;
2649 case VMX_VMCS64_CTRL_PROC_EXEC3_FULL:
2650 case VMX_VMCS64_CTRL_PROC_EXEC3_HIGH: return pFeat->fVmxTertiaryExecCtls;
2651
2652 /* Read-only data fields. */
2653 case VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL:
2654 case VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH: return pFeat->fVmxEpt;
2655
2656 /* Guest-state fields. */
2657 case VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL:
2658 case VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH:
2659 case VMX_VMCS64_GUEST_DEBUGCTL_FULL:
2660 case VMX_VMCS64_GUEST_DEBUGCTL_HIGH: return true;
2661 case VMX_VMCS64_GUEST_PAT_FULL:
2662 case VMX_VMCS64_GUEST_PAT_HIGH: return pFeat->fVmxEntryLoadPatMsr || pFeat->fVmxExitSavePatMsr;
2663 case VMX_VMCS64_GUEST_EFER_FULL:
2664 case VMX_VMCS64_GUEST_EFER_HIGH: return pFeat->fVmxEntryLoadEferMsr || pFeat->fVmxExitSaveEferMsr;
2665 case VMX_VMCS64_GUEST_PDPTE0_FULL:
2666 case VMX_VMCS64_GUEST_PDPTE0_HIGH:
2667 case VMX_VMCS64_GUEST_PDPTE1_FULL:
2668 case VMX_VMCS64_GUEST_PDPTE1_HIGH:
2669 case VMX_VMCS64_GUEST_PDPTE2_FULL:
2670 case VMX_VMCS64_GUEST_PDPTE2_HIGH:
2671 case VMX_VMCS64_GUEST_PDPTE3_FULL:
2672 case VMX_VMCS64_GUEST_PDPTE3_HIGH: return pFeat->fVmxEpt;
2673
2674 /* Host-state fields. */
2675 case VMX_VMCS64_HOST_PAT_FULL:
2676 case VMX_VMCS64_HOST_PAT_HIGH: return pFeat->fVmxExitLoadPatMsr;
2677 case VMX_VMCS64_HOST_EFER_FULL:
2678 case VMX_VMCS64_HOST_EFER_HIGH: return pFeat->fVmxExitLoadEferMsr;
2679
2680 /*
2681 * 32-bit fields.
2682 */
2683 /* Control fields. */
2684 case VMX_VMCS32_CTRL_PIN_EXEC:
2685 case VMX_VMCS32_CTRL_PROC_EXEC:
2686 case VMX_VMCS32_CTRL_EXCEPTION_BITMAP:
2687 case VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK:
2688 case VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH:
2689 case VMX_VMCS32_CTRL_CR3_TARGET_COUNT:
2690 case VMX_VMCS32_CTRL_EXIT:
2691 case VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT:
2692 case VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT:
2693 case VMX_VMCS32_CTRL_ENTRY:
2694 case VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT:
2695 case VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO:
2696 case VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE:
2697 case VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH: return true;
2698 case VMX_VMCS32_CTRL_TPR_THRESHOLD: return pFeat->fVmxUseTprShadow;
2699 case VMX_VMCS32_CTRL_PROC_EXEC2: return pFeat->fVmxSecondaryExecCtls;
2700 case VMX_VMCS32_CTRL_PLE_GAP:
2701 case VMX_VMCS32_CTRL_PLE_WINDOW: return pFeat->fVmxPauseLoopExit;
2702
2703 /* Read-only data fields. */
2704 case VMX_VMCS32_RO_VM_INSTR_ERROR:
2705 case VMX_VMCS32_RO_EXIT_REASON:
2706 case VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO:
2707 case VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE:
2708 case VMX_VMCS32_RO_IDT_VECTORING_INFO:
2709 case VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE:
2710 case VMX_VMCS32_RO_EXIT_INSTR_LENGTH:
2711 case VMX_VMCS32_RO_EXIT_INSTR_INFO: return true;
2712
2713 /* Guest-state fields. */
2714 case VMX_VMCS32_GUEST_ES_LIMIT:
2715 case VMX_VMCS32_GUEST_CS_LIMIT:
2716 case VMX_VMCS32_GUEST_SS_LIMIT:
2717 case VMX_VMCS32_GUEST_DS_LIMIT:
2718 case VMX_VMCS32_GUEST_FS_LIMIT:
2719 case VMX_VMCS32_GUEST_GS_LIMIT:
2720 case VMX_VMCS32_GUEST_LDTR_LIMIT:
2721 case VMX_VMCS32_GUEST_TR_LIMIT:
2722 case VMX_VMCS32_GUEST_GDTR_LIMIT:
2723 case VMX_VMCS32_GUEST_IDTR_LIMIT:
2724 case VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS:
2725 case VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS:
2726 case VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS:
2727 case VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS:
2728 case VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS:
2729 case VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS:
2730 case VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS:
2731 case VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS:
2732 case VMX_VMCS32_GUEST_INT_STATE:
2733 case VMX_VMCS32_GUEST_ACTIVITY_STATE:
2734 case VMX_VMCS32_GUEST_SMBASE:
2735 case VMX_VMCS32_GUEST_SYSENTER_CS: return true;
2736 case VMX_VMCS32_PREEMPT_TIMER_VALUE: return pFeat->fVmxPreemptTimer;
2737
2738 /* Host-state fields. */
2739 case VMX_VMCS32_HOST_SYSENTER_CS: return true;
2740
2741 /*
2742 * Natural-width fields.
2743 */
2744 /* Control fields. */
2745 case VMX_VMCS_CTRL_CR0_MASK:
2746 case VMX_VMCS_CTRL_CR4_MASK:
2747 case VMX_VMCS_CTRL_CR0_READ_SHADOW:
2748 case VMX_VMCS_CTRL_CR4_READ_SHADOW:
2749 case VMX_VMCS_CTRL_CR3_TARGET_VAL0:
2750 case VMX_VMCS_CTRL_CR3_TARGET_VAL1:
2751 case VMX_VMCS_CTRL_CR3_TARGET_VAL2:
2752 case VMX_VMCS_CTRL_CR3_TARGET_VAL3: return true;
2753
2754 /* Read-only data fields. */
2755 case VMX_VMCS_RO_EXIT_QUALIFICATION:
2756 case VMX_VMCS_RO_IO_RCX:
2757 case VMX_VMCS_RO_IO_RSI:
2758 case VMX_VMCS_RO_IO_RDI:
2759 case VMX_VMCS_RO_IO_RIP:
2760 case VMX_VMCS_RO_GUEST_LINEAR_ADDR: return true;
2761
2762 /* Guest-state fields. */
2763 case VMX_VMCS_GUEST_CR0:
2764 case VMX_VMCS_GUEST_CR3:
2765 case VMX_VMCS_GUEST_CR4:
2766 case VMX_VMCS_GUEST_ES_BASE:
2767 case VMX_VMCS_GUEST_CS_BASE:
2768 case VMX_VMCS_GUEST_SS_BASE:
2769 case VMX_VMCS_GUEST_DS_BASE:
2770 case VMX_VMCS_GUEST_FS_BASE:
2771 case VMX_VMCS_GUEST_GS_BASE:
2772 case VMX_VMCS_GUEST_LDTR_BASE:
2773 case VMX_VMCS_GUEST_TR_BASE:
2774 case VMX_VMCS_GUEST_GDTR_BASE:
2775 case VMX_VMCS_GUEST_IDTR_BASE:
2776 case VMX_VMCS_GUEST_DR7:
2777 case VMX_VMCS_GUEST_RSP:
2778 case VMX_VMCS_GUEST_RIP:
2779 case VMX_VMCS_GUEST_RFLAGS:
2780 case VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS:
2781 case VMX_VMCS_GUEST_SYSENTER_ESP:
2782 case VMX_VMCS_GUEST_SYSENTER_EIP: return true;
2783
2784 /* Host-state fields. */
2785 case VMX_VMCS_HOST_CR0:
2786 case VMX_VMCS_HOST_CR3:
2787 case VMX_VMCS_HOST_CR4:
2788 case VMX_VMCS_HOST_FS_BASE:
2789 case VMX_VMCS_HOST_GS_BASE:
2790 case VMX_VMCS_HOST_TR_BASE:
2791 case VMX_VMCS_HOST_GDTR_BASE:
2792 case VMX_VMCS_HOST_IDTR_BASE:
2793 case VMX_VMCS_HOST_SYSENTER_ESP:
2794 case VMX_VMCS_HOST_SYSENTER_EIP:
2795 case VMX_VMCS_HOST_RSP:
2796 case VMX_VMCS_HOST_RIP: return true;
2797 }
2798
2799 return false;
2800}
2801
2802
2803/**
2804 * Checks whether the given I/O access should cause a nested-guest VM-exit.
2805 *
2806 * @returns @c true if it causes a VM-exit, @c false otherwise.
2807 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2808 * @param u16Port The I/O port being accessed.
2809 * @param cbAccess The size of the I/O access in bytes (1, 2 or 4 bytes).
2810 */
2811VMM_INT_DECL(bool) CPUMIsGuestVmxIoInterceptSet(PCVMCPU pVCpu, uint16_t u16Port, uint8_t cbAccess)
2812{
2813 PCCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
2814 if (CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_UNCOND_IO_EXIT))
2815 return true;
2816
2817 if (CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_USE_IO_BITMAPS))
2818 return cpumGetVmxIoBitmapPermission(pCtx->hwvirt.vmx.abIoBitmap, u16Port, cbAccess);
2819
2820 return false;
2821}
2822
2823
2824/**
2825 * Checks whether the Mov-to-CR3 instruction causes a nested-guest VM-exit.
2826 *
2827 * @returns @c true if it causes a VM-exit, @c false otherwise.
2828 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2829 * @param uNewCr3 The CR3 value being written.
2830 */
2831VMM_INT_DECL(bool) CPUMIsGuestVmxMovToCr3InterceptSet(PVMCPU pVCpu, uint64_t uNewCr3)
2832{
2833 /*
2834 * If the CR3-load exiting control is set and the new CR3 value does not
2835 * match any of the CR3-target values in the VMCS, we must cause a VM-exit.
2836 *
2837 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
2838 */
2839 PCCPUMCTX const pCtx = &pVCpu->cpum.s.Guest;
2840 if (CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_CR3_LOAD_EXIT))
2841 {
2842 uint32_t const uCr3TargetCount = pCtx->hwvirt.vmx.Vmcs.u32Cr3TargetCount;
2843 Assert(uCr3TargetCount <= VMX_V_CR3_TARGET_COUNT);
2844
2845 /* If the CR3-target count is 0, cause a VM-exit. */
2846 if (uCr3TargetCount == 0)
2847 return true;
2848
2849 /* If the CR3 being written doesn't match any of the target values, cause a VM-exit. */
2850 AssertCompile(VMX_V_CR3_TARGET_COUNT == 4);
2851 if ( uNewCr3 != pCtx->hwvirt.vmx.Vmcs.u64Cr3Target0.u
2852 && uNewCr3 != pCtx->hwvirt.vmx.Vmcs.u64Cr3Target1.u
2853 && uNewCr3 != pCtx->hwvirt.vmx.Vmcs.u64Cr3Target2.u
2854 && uNewCr3 != pCtx->hwvirt.vmx.Vmcs.u64Cr3Target3.u)
2855 return true;
2856 }
2857 return false;
2858}
2859
2860
2861/**
2862 * Checks whether a VMREAD or VMWRITE instruction for the given VMCS field causes a
2863 * VM-exit or not.
2864 *
2865 * @returns @c true if the VMREAD/VMWRITE is intercepted, @c false otherwise.
2866 * @param pVCpu The cross context virtual CPU structure.
2867 * @param uExitReason The VM-exit reason (VMX_EXIT_VMREAD or
2868 * VMX_EXIT_VMREAD).
2869 * @param u64VmcsField The VMCS field.
2870 */
2871VMM_INT_DECL(bool) CPUMIsGuestVmxVmreadVmwriteInterceptSet(PCVMCPU pVCpu, uint32_t uExitReason, uint64_t u64VmcsField)
2872{
2873 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.s.Guest));
2874 Assert( uExitReason == VMX_EXIT_VMREAD
2875 || uExitReason == VMX_EXIT_VMWRITE);
2876
2877 /*
2878 * Without VMCS shadowing, all VMREAD and VMWRITE instructions are intercepted.
2879 */
2880 if (!CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.s.Guest, VMX_PROC_CTLS2_VMCS_SHADOWING))
2881 return true;
2882
2883 /*
2884 * If any reserved bit in the 64-bit VMCS field encoding is set, the VMREAD/VMWRITE
2885 * is intercepted. This excludes any reserved bits in the valid parts of the field
2886 * encoding (i.e. bit 12).
2887 */
2888 if (u64VmcsField & VMX_VMCSFIELD_RSVD_MASK)
2889 return true;
2890
2891 /*
2892 * Finally, consult the VMREAD/VMWRITE bitmap whether to intercept the instruction or not.
2893 */
2894 uint32_t const u32VmcsField = RT_LO_U32(u64VmcsField);
2895 uint8_t const * const pbBitmap = uExitReason == VMX_EXIT_VMREAD
2896 ? &pVCpu->cpum.s.Guest.hwvirt.vmx.abVmreadBitmap[0]
2897 : &pVCpu->cpum.s.Guest.hwvirt.vmx.abVmwriteBitmap[0];
2898 Assert(pbBitmap);
2899 Assert(u32VmcsField >> 3 < VMX_V_VMREAD_VMWRITE_BITMAP_SIZE);
2900 return ASMBitTest(&pbBitmap[u32VmcsField >> 3], u32VmcsField & 7);
2901}
2902
2903
2904
2905/**
2906 * Determines whether the given I/O access should cause a nested-guest \#VMEXIT.
2907 *
2908 * @param pvIoBitmap Pointer to the nested-guest IO bitmap.
2909 * @param u16Port The IO port being accessed.
2910 * @param enmIoType The type of IO access.
2911 * @param cbReg The IO operand size in bytes.
2912 * @param cAddrSizeBits The address size bits (for 16, 32 or 64).
2913 * @param iEffSeg The effective segment number.
2914 * @param fRep Whether this is a repeating IO instruction (REP prefix).
2915 * @param fStrIo Whether this is a string IO instruction.
2916 * @param pIoExitInfo Pointer to the SVMIOIOEXITINFO struct to be filled.
2917 * Optional, can be NULL.
2918 */
2919VMM_INT_DECL(bool) CPUMIsSvmIoInterceptSet(void *pvIoBitmap, uint16_t u16Port, SVMIOIOTYPE enmIoType, uint8_t cbReg,
2920 uint8_t cAddrSizeBits, uint8_t iEffSeg, bool fRep, bool fStrIo,
2921 PSVMIOIOEXITINFO pIoExitInfo)
2922{
2923 Assert(cAddrSizeBits == 16 || cAddrSizeBits == 32 || cAddrSizeBits == 64);
2924 Assert(cbReg == 1 || cbReg == 2 || cbReg == 4 || cbReg == 8);
2925
2926 /*
2927 * The IOPM layout:
2928 * Each bit represents one 8-bit port. That makes a total of 0..65535 bits or
2929 * two 4K pages.
2930 *
2931 * For IO instructions that access more than a single byte, the permission bits
2932 * for all bytes are checked; if any bit is set to 1, the IO access is intercepted.
2933 *
2934 * Since it's possible to do a 32-bit IO access at port 65534 (accessing 4 bytes),
2935 * we need 3 extra bits beyond the second 4K page.
2936 */
2937 static const uint16_t s_auSizeMasks[] = { 0, 1, 3, 0, 0xf, 0, 0, 0 };
2938
2939 uint16_t const offIopm = u16Port >> 3;
2940 uint16_t const fSizeMask = s_auSizeMasks[(cAddrSizeBits >> SVM_IOIO_OP_SIZE_SHIFT) & 7];
2941 uint8_t const cShift = u16Port - (offIopm << 3);
2942 uint16_t const fIopmMask = (1 << cShift) | (fSizeMask << cShift);
2943
2944 uint8_t const *pbIopm = (uint8_t *)pvIoBitmap;
2945 Assert(pbIopm);
2946 pbIopm += offIopm;
2947 uint16_t const u16Iopm = *(uint16_t *)pbIopm;
2948 if (u16Iopm & fIopmMask)
2949 {
2950 if (pIoExitInfo)
2951 {
2952 static const uint32_t s_auIoOpSize[] =
2953 { SVM_IOIO_32_BIT_OP, SVM_IOIO_8_BIT_OP, SVM_IOIO_16_BIT_OP, 0, SVM_IOIO_32_BIT_OP, 0, 0, 0 };
2954
2955 static const uint32_t s_auIoAddrSize[] =
2956 { 0, SVM_IOIO_16_BIT_ADDR, SVM_IOIO_32_BIT_ADDR, 0, SVM_IOIO_64_BIT_ADDR, 0, 0, 0 };
2957
2958 pIoExitInfo->u = s_auIoOpSize[cbReg & 7];
2959 pIoExitInfo->u |= s_auIoAddrSize[(cAddrSizeBits >> 4) & 7];
2960 pIoExitInfo->n.u1Str = fStrIo;
2961 pIoExitInfo->n.u1Rep = fRep;
2962 pIoExitInfo->n.u3Seg = iEffSeg & 7;
2963 pIoExitInfo->n.u1Type = enmIoType;
2964 pIoExitInfo->n.u16Port = u16Port;
2965 }
2966 return true;
2967 }
2968
2969 /** @todo remove later (for debugging as VirtualBox always traps all IO
2970 * intercepts). */
2971 AssertMsgFailed(("CPUMSvmIsIOInterceptActive: We expect an IO intercept here!\n"));
2972 return false;
2973}
2974
2975
2976/**
2977 * Gets the MSR permission bitmap byte and bit offset for the specified MSR.
2978 *
2979 * @returns VBox status code.
2980 * @param idMsr The MSR being requested.
2981 * @param pbOffMsrpm Where to store the byte offset in the MSR permission
2982 * bitmap for @a idMsr.
2983 * @param puMsrpmBit Where to store the bit offset starting at the byte
2984 * returned in @a pbOffMsrpm.
2985 */
2986VMM_INT_DECL(int) CPUMGetSvmMsrpmOffsetAndBit(uint32_t idMsr, uint16_t *pbOffMsrpm, uint8_t *puMsrpmBit)
2987{
2988 Assert(pbOffMsrpm);
2989 Assert(puMsrpmBit);
2990
2991 /*
2992 * MSRPM Layout:
2993 * Byte offset MSR range
2994 * 0x000 - 0x7ff 0x00000000 - 0x00001fff
2995 * 0x800 - 0xfff 0xc0000000 - 0xc0001fff
2996 * 0x1000 - 0x17ff 0xc0010000 - 0xc0011fff
2997 * 0x1800 - 0x1fff Reserved
2998 *
2999 * Each MSR is represented by 2 permission bits (read and write).
3000 */
3001 if (idMsr <= 0x00001fff)
3002 {
3003 /* Pentium-compatible MSRs. */
3004 uint32_t const bitoffMsr = idMsr << 1;
3005 *pbOffMsrpm = bitoffMsr >> 3;
3006 *puMsrpmBit = bitoffMsr & 7;
3007 return VINF_SUCCESS;
3008 }
3009
3010 if ( idMsr >= 0xc0000000
3011 && idMsr <= 0xc0001fff)
3012 {
3013 /* AMD Sixth Generation x86 Processor MSRs. */
3014 uint32_t const bitoffMsr = (idMsr - 0xc0000000) << 1;
3015 *pbOffMsrpm = 0x800 + (bitoffMsr >> 3);
3016 *puMsrpmBit = bitoffMsr & 7;
3017 return VINF_SUCCESS;
3018 }
3019
3020 if ( idMsr >= 0xc0010000
3021 && idMsr <= 0xc0011fff)
3022 {
3023 /* AMD Seventh and Eighth Generation Processor MSRs. */
3024 uint32_t const bitoffMsr = (idMsr - 0xc0010000) << 1;
3025 *pbOffMsrpm = 0x1000 + (bitoffMsr >> 3);
3026 *puMsrpmBit = bitoffMsr & 7;
3027 return VINF_SUCCESS;
3028 }
3029
3030 *pbOffMsrpm = 0;
3031 *puMsrpmBit = 0;
3032 return VERR_OUT_OF_RANGE;
3033}
3034
3035
3036/**
3037 * Checks whether the guest is in VMX non-root mode and using EPT paging.
3038 *
3039 * @returns @c true if in VMX non-root operation with EPT, @c false otherwise.
3040 * @param pVCpu The cross context virtual CPU structure.
3041 */
3042VMM_INT_DECL(bool) CPUMIsGuestVmxEptPagingEnabled(PCVMCPUCC pVCpu)
3043{
3044 return CPUMIsGuestVmxEptPagingEnabledEx(&pVCpu->cpum.s.Guest);
3045}
3046
3047
3048/**
3049 * Checks whether the guest is in VMX non-root mode and using EPT paging and the
3050 * nested-guest is in PAE mode.
3051 *
3052 * @returns @c true if in VMX non-root operation with EPT, @c false otherwise.
3053 * @param pVCpu The cross context virtual CPU structure.
3054 */
3055VMM_INT_DECL(bool) CPUMIsGuestVmxEptPaePagingEnabled(PCVMCPUCC pVCpu)
3056{
3057 return CPUMIsGuestVmxEptPagingEnabledEx(&pVCpu->cpum.s.Guest)
3058 && CPUMIsGuestInPAEModeEx(&pVCpu->cpum.s.Guest);
3059}
3060
Note: See TracBrowser for help on using the repository browser.

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