VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp@ 46438

Last change on this file since 46438 was 46420, checked in by vboxsync, 12 years ago

VMM, recompiler: Purge deprecated macros.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 387.1 KB
Line 
1/* $Id: HMVMXR0.cpp 46420 2013-06-06 16:27:25Z vboxsync $ */
2/** @file
3 * HM VMX (Intel VT-x) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2012-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_HM
22#include <iprt/asm-amd64-x86.h>
23#include <iprt/thread.h>
24#include <iprt/string.h>
25
26#include "HMInternal.h"
27#include <VBox/vmm/vm.h>
28#include "HWVMXR0.h"
29#include <VBox/vmm/pdmapi.h>
30#include <VBox/vmm/dbgf.h>
31#include <VBox/vmm/iom.h>
32#include <VBox/vmm/selm.h>
33#include <VBox/vmm/tm.h>
34#ifdef VBOX_WITH_REM
35# include <VBox/vmm/rem.h>
36#endif
37#ifdef DEBUG_ramshankar
38#define HMVMX_SAVE_FULL_GUEST_STATE
39#define HMVMX_SYNC_FULL_GUEST_STATE
40#define HMVMX_ALWAYS_TRAP_ALL_XCPTS
41#define HMVMX_ALWAYS_TRAP_PF
42#endif
43
44
45/*******************************************************************************
46* Defined Constants And Macros *
47*******************************************************************************/
48#define HMVMXHCUINTREG RTHCUINTREG
49#if defined(RT_ARCH_AMD64)
50# define HMVMX_IS_64BIT_HOST_MODE() (true)
51#elif defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
52extern "C" uint32_t g_fVMXIs64bitHost;
53# define HMVMX_IS_64BIT_HOST_MODE() (g_fVMXIs64bitHost != 0)
54# undef HMVMXHCUINTREG
55# define HMVMXHCUINTREG uint64_t
56#else
57# define HMVMX_IS_64BIT_HOST_MODE() (false)
58#endif
59
60/** Use the function table. */
61#define HMVMX_USE_FUNCTION_TABLE
62
63/** This bit indicates the segment selector is unusable in VT-x. */
64#define HMVMX_SEL_UNUSABLE RT_BIT(16)
65
66/** Determine which tagged-TLB flush handler to use. */
67#define HMVMX_FLUSH_TAGGED_TLB_EPT_VPID 0
68#define HMVMX_FLUSH_TAGGED_TLB_EPT 1
69#define HMVMX_FLUSH_TAGGED_TLB_VPID 2
70#define HMVMX_FLUSH_TAGGED_TLB_NONE 3
71
72/** @name Updated-guest-state flags.
73 * @{ */
74#define HMVMX_UPDATED_GUEST_RIP RT_BIT(0)
75#define HMVMX_UPDATED_GUEST_RSP RT_BIT(1)
76#define HMVMX_UPDATED_GUEST_RFLAGS RT_BIT(2)
77#define HMVMX_UPDATED_GUEST_CR0 RT_BIT(3)
78#define HMVMX_UPDATED_GUEST_CR3 RT_BIT(4)
79#define HMVMX_UPDATED_GUEST_CR4 RT_BIT(5)
80#define HMVMX_UPDATED_GUEST_GDTR RT_BIT(6)
81#define HMVMX_UPDATED_GUEST_IDTR RT_BIT(7)
82#define HMVMX_UPDATED_GUEST_LDTR RT_BIT(8)
83#define HMVMX_UPDATED_GUEST_TR RT_BIT(9)
84#define HMVMX_UPDATED_GUEST_SEGMENT_REGS RT_BIT(10)
85#define HMVMX_UPDATED_GUEST_DEBUG RT_BIT(11)
86#define HMVMX_UPDATED_GUEST_FS_BASE_MSR RT_BIT(12)
87#define HMVMX_UPDATED_GUEST_GS_BASE_MSR RT_BIT(13)
88#define HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR RT_BIT(14)
89#define HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR RT_BIT(15)
90#define HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR RT_BIT(16)
91#define HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS RT_BIT(17)
92#define HMVMX_UPDATED_GUEST_ACTIVITY_STATE RT_BIT(18)
93#define HMVMX_UPDATED_GUEST_APIC_STATE RT_BIT(19)
94#define HMVMX_UPDATED_GUEST_ALL ( HMVMX_UPDATED_GUEST_RIP \
95 | HMVMX_UPDATED_GUEST_RSP \
96 | HMVMX_UPDATED_GUEST_RFLAGS \
97 | HMVMX_UPDATED_GUEST_CR0 \
98 | HMVMX_UPDATED_GUEST_CR3 \
99 | HMVMX_UPDATED_GUEST_CR4 \
100 | HMVMX_UPDATED_GUEST_GDTR \
101 | HMVMX_UPDATED_GUEST_IDTR \
102 | HMVMX_UPDATED_GUEST_LDTR \
103 | HMVMX_UPDATED_GUEST_TR \
104 | HMVMX_UPDATED_GUEST_SEGMENT_REGS \
105 | HMVMX_UPDATED_GUEST_DEBUG \
106 | HMVMX_UPDATED_GUEST_FS_BASE_MSR \
107 | HMVMX_UPDATED_GUEST_GS_BASE_MSR \
108 | HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR \
109 | HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR \
110 | HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR \
111 | HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS \
112 | HMVMX_UPDATED_GUEST_ACTIVITY_STATE \
113 | HMVMX_UPDATED_GUEST_APIC_STATE)
114/** @} */
115
116/**
117 * Flags to skip redundant reads of some common VMCS fields that are not part of
118 * the guest-CPU state but are in the transient structure.
119 */
120#define HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO RT_BIT(0)
121#define HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE RT_BIT(1)
122#define HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION RT_BIT(2)
123#define HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN RT_BIT(3)
124#define HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO RT_BIT(4)
125#define HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE RT_BIT(5)
126
127/**
128 * Exception bitmap mask for real-mode guests (real-on-v86). We need to intercept all exceptions manually (except #PF).
129 * #NM is also handled spearetely, see hmR0VmxLoadGuestControlRegs(). #PF need not be intercepted even in real-mode if
130 * we have Nested Paging support.
131 */
132#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) | RT_BIT(X86_XCPT_DB) | RT_BIT(X86_XCPT_NMI) \
133 | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
134 | RT_BIT(X86_XCPT_UD) /* RT_BIT(X86_XCPT_NM) */ | RT_BIT(X86_XCPT_DF) \
135 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
136 | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
137 | RT_BIT(X86_XCPT_MF) | RT_BIT(X86_XCPT_AC) | RT_BIT(X86_XCPT_MC) \
138 | RT_BIT(X86_XCPT_XF))
139
140/**
141 * Exception bitmap mask for all contributory exceptions.
142 */
143#define HMVMX_CONTRIBUTORY_XCPT_MASK ( RT_BIT(X86_XCPT_GP) | RT_BIT(X86_XCPT_NP) | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_TS) \
144 | RT_BIT(X86_XCPT_DE))
145
146/** Maximum VM-instruction error number. */
147#define HMVMX_INSTR_ERROR_MAX 28
148
149/** Profiling macro. */
150#ifdef HM_PROFILE_EXIT_DISPATCH
151# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitDispatch, ed)
152# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitDispatch, ed)
153#else
154# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
155# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
156#endif
157
158
159/*******************************************************************************
160* Structures and Typedefs *
161*******************************************************************************/
162/**
163 * A state structure for holding miscellaneous information across
164 * VMX non-root operation and restored after the transition.
165 */
166typedef struct VMXTRANSIENT
167{
168 /** The host's rflags/eflags. */
169 RTCCUINTREG uEFlags;
170#if HC_ARCH_BITS == 32
171 uint32_t u32Alignment0;
172#endif
173 /** The guest's LSTAR MSR value used for TPR patching for 32-bit guests. */
174 uint64_t u64LStarMsr;
175 /** The guest's TPR value used for TPR shadowing. */
176 uint8_t u8GuestTpr;
177 /** Alignment. */
178 uint8_t abAlignment0[6];
179
180 /** The basic VM-exit reason. */
181 uint16_t uExitReason;
182 /** Alignment. */
183 uint16_t u16Alignment0;
184 /** The VM-exit interruption error code. */
185 uint32_t uExitIntrErrorCode;
186 /** The VM-exit exit qualification. */
187 uint64_t uExitQualification;
188
189 /** The VM-exit interruption-information field. */
190 uint32_t uExitIntrInfo;
191 /** The VM-exit instruction-length field. */
192 uint32_t cbInstr;
193 /** Whether the VM-entry failed or not. */
194 bool fVMEntryFailed;
195 /** Alignment. */
196 uint8_t abAlignment1[5];
197
198 /** The VM-entry interruption-information field. */
199 uint32_t uEntryIntrInfo;
200 /** The VM-entry exception error code field. */
201 uint32_t uEntryXcptErrorCode;
202 /** The VM-entry instruction length field. */
203 uint32_t cbEntryInstr;
204
205 /** IDT-vectoring information field. */
206 uint32_t uIdtVectoringInfo;
207 /** IDT-vectoring error code. */
208 uint32_t uIdtVectoringErrorCode;
209
210 /** Mask of currently read VMCS fields; HMVMX_UPDATED_TRANSIENT_*. */
211 uint32_t fVmcsFieldsRead;
212 /** Whether TSC-offsetting should be setup before VM-entry. */
213 bool fUpdateTscOffsettingAndPreemptTimer;
214 /** Whether the VM-exit was caused by a page-fault during delivery of a
215 * contributary exception or a page-fault. */
216 bool fVectoringPF;
217} VMXTRANSIENT, *PVMXTRANSIENT;
218AssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, sizeof(uint64_t));
219AssertCompileMemberAlignment(VMXTRANSIENT, uExitIntrInfo, sizeof(uint64_t));
220AssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntrInfo, sizeof(uint64_t));
221
222
223/**
224 * MSR-bitmap read permissions.
225 */
226typedef enum VMXMSREXITREAD
227{
228 /** Reading this MSR causes a VM-exit. */
229 VMXMSREXIT_INTERCEPT_READ = 0xb,
230 /** Reading this MSR does not cause a VM-exit. */
231 VMXMSREXIT_PASSTHRU_READ
232} VMXMSREXITREAD;
233
234/**
235 * MSR-bitmap write permissions.
236 */
237typedef enum VMXMSREXITWRITE
238{
239 /** Writing to this MSR causes a VM-exit. */
240 VMXMSREXIT_INTERCEPT_WRITE = 0xd,
241 /** Writing to this MSR does not cause a VM-exit. */
242 VMXMSREXIT_PASSTHRU_WRITE
243} VMXMSREXITWRITE;
244
245
246/*******************************************************************************
247* Internal Functions *
248*******************************************************************************/
249static void hmR0VmxFlushEpt(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_EPT enmFlush);
250static void hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_VPID enmFlush, RTGCPTR GCPtr);
251static int hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntrInfo, uint32_t cbInstr,
252 uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, uint32_t *puIntrState);
253#if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
254static int hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu);
255#endif
256#ifndef HMVMX_USE_FUNCTION_TABLE
257DECLINLINE(int) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason);
258#define HMVMX_EXIT_DECL static int
259#else
260#define HMVMX_EXIT_DECL static DECLCALLBACK(int)
261#endif
262
263HMVMX_EXIT_DECL hmR0VmxExitXcptNmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
264HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
265HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
266HMVMX_EXIT_DECL hmR0VmxExitInitSignal(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
267HMVMX_EXIT_DECL hmR0VmxExitSipi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
268HMVMX_EXIT_DECL hmR0VmxExitIoSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
269HMVMX_EXIT_DECL hmR0VmxExitSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
270HMVMX_EXIT_DECL hmR0VmxExitIntWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
271HMVMX_EXIT_DECL hmR0VmxExitNmiWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
272HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
273HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
274HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
275HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
276HMVMX_EXIT_DECL hmR0VmxExitInvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
277HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
278HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
279HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
280HMVMX_EXIT_DECL hmR0VmxExitRsm(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
281HMVMX_EXIT_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
282HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
283HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
284HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
285HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
286HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
287HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
288HMVMX_EXIT_DECL hmR0VmxExitErrMsrLoad(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
289HMVMX_EXIT_DECL hmR0VmxExitErrUndefined(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
290HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
291HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
292HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
293HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
294HMVMX_EXIT_DECL hmR0VmxExitErrMachineCheck(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
295HMVMX_EXIT_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
296HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
297HMVMX_EXIT_DECL hmR0VmxExitXdtrAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
298HMVMX_EXIT_DECL hmR0VmxExitXdtrAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
299HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
300HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
301HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
302HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
303HMVMX_EXIT_DECL hmR0VmxExitWbinvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
304HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
305HMVMX_EXIT_DECL hmR0VmxExitRdrand(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
306HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
307
308static int hmR0VmxExitXcptNM(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
309static int hmR0VmxExitXcptPF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
310static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
311static int hmR0VmxExitXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
312static int hmR0VmxExitXcptBP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
313static int hmR0VmxExitXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
314static int hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
315
316
317/*******************************************************************************
318* Global Variables *
319*******************************************************************************/
320#ifdef HMVMX_USE_FUNCTION_TABLE
321/**
322 * VM-exit handler.
323 *
324 * @returns VBox status code.
325 * @param pVCpu Pointer to the VMCPU.
326 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
327 * out-of-sync. Make sure to update the required
328 * fields before using them.
329 * @param pVmxTransient Pointer to the VMX-transient structure.
330 */
331typedef DECLCALLBACK(int) FNVMEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
332/** Pointer to VM-exit handler. */
333typedef FNVMEXITHANDLER *const PFNVMEXITHANDLER;
334
335/**
336 * VMX_EXIT dispatch table.
337 */
338static const PFNVMEXITHANDLER g_apfnVMExitHandlers[VMX_EXIT_MAX + 1] =
339{
340 /* 00 VMX_EXIT_XCPT_NMI */ hmR0VmxExitXcptNmi,
341 /* 01 VMX_EXIT_EXT_INT */ hmR0VmxExitExtInt,
342 /* 02 VMX_EXIT_TRIPLE_FAULT */ hmR0VmxExitTripleFault,
343 /* 03 VMX_EXIT_INIT_SIGNAL */ hmR0VmxExitInitSignal,
344 /* 04 VMX_EXIT_SIPI */ hmR0VmxExitSipi,
345 /* 05 VMX_EXIT_IO_SMI */ hmR0VmxExitIoSmi,
346 /* 06 VMX_EXIT_SMI */ hmR0VmxExitSmi,
347 /* 07 VMX_EXIT_INT_WINDOW */ hmR0VmxExitIntWindow,
348 /* 08 VMX_EXIT_NMI_WINDOW */ hmR0VmxExitNmiWindow,
349 /* 09 VMX_EXIT_TASK_SWITCH */ hmR0VmxExitTaskSwitch,
350 /* 10 VMX_EXIT_CPUID */ hmR0VmxExitCpuid,
351 /* 11 VMX_EXIT_GETSEC */ hmR0VmxExitGetsec,
352 /* 12 VMX_EXIT_HLT */ hmR0VmxExitHlt,
353 /* 13 VMX_EXIT_INVD */ hmR0VmxExitInvd,
354 /* 14 VMX_EXIT_INVLPG */ hmR0VmxExitInvlpg,
355 /* 15 VMX_EXIT_RDPMC */ hmR0VmxExitRdpmc,
356 /* 16 VMX_EXIT_RDTSC */ hmR0VmxExitRdtsc,
357 /* 17 VMX_EXIT_RSM */ hmR0VmxExitRsm,
358 /* 18 VMX_EXIT_VMCALL */ hmR0VmxExitSetPendingXcptUD,
359 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitSetPendingXcptUD,
360 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitSetPendingXcptUD,
361 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitSetPendingXcptUD,
362 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitSetPendingXcptUD,
363 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitSetPendingXcptUD,
364 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitSetPendingXcptUD,
365 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitSetPendingXcptUD,
366 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitSetPendingXcptUD,
367 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitSetPendingXcptUD,
368 /* 28 VMX_EXIT_MOV_CRX */ hmR0VmxExitMovCRx,
369 /* 29 VMX_EXIT_MOV_DRX */ hmR0VmxExitMovDRx,
370 /* 30 VMX_EXIT_IO_INSTR */ hmR0VmxExitIoInstr,
371 /* 31 VMX_EXIT_RDMSR */ hmR0VmxExitRdmsr,
372 /* 32 VMX_EXIT_WRMSR */ hmR0VmxExitWrmsr,
373 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ hmR0VmxExitErrInvalidGuestState,
374 /* 34 VMX_EXIT_ERR_MSR_LOAD */ hmR0VmxExitErrMsrLoad,
375 /* 35 UNDEFINED */ hmR0VmxExitErrUndefined,
376 /* 36 VMX_EXIT_MWAIT */ hmR0VmxExitMwait,
377 /* 37 VMX_EXIT_MTF */ hmR0VmxExitMtf,
378 /* 38 UNDEFINED */ hmR0VmxExitErrUndefined,
379 /* 39 VMX_EXIT_MONITOR */ hmR0VmxExitMonitor,
380 /* 40 UNDEFINED */ hmR0VmxExitPause,
381 /* 41 VMX_EXIT_PAUSE */ hmR0VmxExitErrMachineCheck,
382 /* 42 VMX_EXIT_ERR_MACHINE_CHECK */ hmR0VmxExitErrUndefined,
383 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ hmR0VmxExitTprBelowThreshold,
384 /* 44 VMX_EXIT_APIC_ACCESS */ hmR0VmxExitApicAccess,
385 /* 45 UNDEFINED */ hmR0VmxExitErrUndefined,
386 /* 46 VMX_EXIT_XDTR_ACCESS */ hmR0VmxExitXdtrAccess,
387 /* 47 VMX_EXIT_TR_ACCESS */ hmR0VmxExitXdtrAccess,
388 /* 48 VMX_EXIT_EPT_VIOLATION */ hmR0VmxExitEptViolation,
389 /* 49 VMX_EXIT_EPT_MISCONFIG */ hmR0VmxExitEptMisconfig,
390 /* 50 VMX_EXIT_INVEPT */ hmR0VmxExitSetPendingXcptUD,
391 /* 51 VMX_EXIT_RDTSCP */ hmR0VmxExitRdtscp,
392 /* 52 VMX_EXIT_PREEMPT_TIMER */ hmR0VmxExitPreemptTimer,
393 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitSetPendingXcptUD,
394 /* 54 VMX_EXIT_WBINVD */ hmR0VmxExitWbinvd,
395 /* 55 VMX_EXIT_XSETBV */ hmR0VmxExitXsetbv,
396 /* 56 UNDEFINED */ hmR0VmxExitErrUndefined,
397 /* 57 VMX_EXIT_RDRAND */ hmR0VmxExitRdrand,
398 /* 58 VMX_EXIT_INVPCID */ hmR0VmxExitInvpcid,
399 /* 59 VMX_EXIT_VMFUNC */ hmR0VmxExitSetPendingXcptUD
400};
401#endif /* HMVMX_USE_FUNCTION_TABLE */
402
403#ifdef VBOX_STRICT
404static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
405{
406 /* 0 */ "(Not Used)",
407 /* 1 */ "VMCALL executed in VMX root operation.",
408 /* 2 */ "VMCLEAR with invalid physical address.",
409 /* 3 */ "VMCLEAR with VMXON pointer.",
410 /* 4 */ "VMLAUNCH with non-clear VMCS.",
411 /* 5 */ "VMRESUME with non-launched VMCS.",
412 /* 6 */ "VMRESUME after VMXOFF",
413 /* 7 */ "VM entry with invalid control fields.",
414 /* 8 */ "VM entry with invalid host state fields.",
415 /* 9 */ "VMPTRLD with invalid physical address.",
416 /* 10 */ "VMPTRLD with VMXON pointer.",
417 /* 11 */ "VMPTRLD with incorrect revision identifier.",
418 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
419 /* 13 */ "VMWRITE to read-only VMCS component.",
420 /* 14 */ "(Not Used)",
421 /* 15 */ "VMXON executed in VMX root operation.",
422 /* 16 */ "VM entry with invalid executive-VMCS pointer.",
423 /* 17 */ "VM entry with non-launched executing VMCS.",
424 /* 18 */ "VM entry with executive-VMCS pointer not VMXON pointer.",
425 /* 19 */ "VMCALL with non-clear VMCS.",
426 /* 20 */ "VMCALL with invalid VM-exit control fields.",
427 /* 21 */ "(Not Used)",
428 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
429 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
430 /* 24 */ "VMCALL with invalid SMM-monitor features.",
431 /* 25 */ "VM entry with invalid VM-execution control fields in executive VMCS.",
432 /* 26 */ "VM entry with events blocked by MOV SS.",
433 /* 27 */ "(Not Used)",
434 /* 28 */ "Invalid operand to INVEPT/INVVPID."
435};
436#endif /* VBOX_STRICT */
437
438
439
440/**
441 * Updates the VM's last error record. If there was a VMX instruction error,
442 * reads the error data from the VMCS and updates VCPU's last error record as
443 * well.
444 *
445 * @param pVM Pointer to the VM.
446 * @param pVCpu Pointer to the VMCPU (can be NULL if @a rc is not
447 * VERR_VMX_UNABLE_TO_START_VM or
448 * VERR_VMX_INVALID_VMCS_FIELD).
449 * @param rc The error code.
450 */
451static void hmR0VmxUpdateErrorRecord(PVM pVM, PVMCPU pVCpu, int rc)
452{
453 AssertPtr(pVM);
454 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
455 || rc == VERR_VMX_UNABLE_TO_START_VM)
456 {
457 AssertPtrReturnVoid(pVCpu);
458 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.lasterror.u32InstrError);
459 }
460 pVM->hm.s.lLastError = rc;
461}
462
463
464/**
465 * Reads the VM-entry interruption-information field from the VMCS into the VMX
466 * transient structure.
467 *
468 * @returns VBox status code.
469 * @param pVmxTransient Pointer to the VMX transient structure.
470 *
471 * @remarks No-long-jump zone!!!
472 */
473DECLINLINE(int) hmR0VmxReadEntryIntrInfoVmcs(PVMXTRANSIENT pVmxTransient)
474{
475 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntrInfo);
476 AssertRCReturn(rc, rc);
477 return VINF_SUCCESS;
478}
479
480
481/**
482 * Reads the VM-entry exception error code field from the VMCS into
483 * the VMX transient structure.
484 *
485 * @returns VBox status code.
486 * @param pVmxTransient Pointer to the VMX transient structure.
487 *
488 * @remarks No-long-jump zone!!!
489 */
490DECLINLINE(int) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
491{
492 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
493 AssertRCReturn(rc, rc);
494 return VINF_SUCCESS;
495}
496
497
498/**
499 * Reads the VM-entry exception error code field from the VMCS into
500 * the VMX transient structure.
501 *
502 * @returns VBox status code.
503 * @param pVCpu Pointer to the VMCPU.
504 * @param pVmxTransient Pointer to the VMX transient structure.
505 *
506 * @remarks No-long-jump zone!!!
507 */
508DECLINLINE(int) hmR0VmxReadEntryInstrLenVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
509{
510 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
511 AssertRCReturn(rc, rc);
512 return VINF_SUCCESS;
513}
514
515
516/**
517 * Reads the VM-exit interruption-information field from the VMCS into the VMX
518 * transient structure.
519 *
520 * @returns VBox status code.
521 * @param pVCpu Pointer to the VMCPU.
522 * @param pVmxTransient Pointer to the VMX transient structure.
523 */
524DECLINLINE(int) hmR0VmxReadExitIntrInfoVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
525{
526 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO))
527 {
528 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntrInfo);
529 AssertRCReturn(rc, rc);
530 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO;
531 }
532 return VINF_SUCCESS;
533}
534
535
536/**
537 * Reads the VM-exit interruption error code from the VMCS into the VMX
538 * transient structure.
539 *
540 * @returns VBox status code.
541 * @param pVCpu Pointer to the VMCPU.
542 * @param pVmxTransient Pointer to the VMX transient structure.
543 */
544DECLINLINE(int) hmR0VmxReadExitIntrErrorCodeVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
545{
546 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE))
547 {
548 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntrErrorCode);
549 AssertRCReturn(rc, rc);
550 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE;
551 }
552 return VINF_SUCCESS;
553}
554
555
556/**
557 * Reads the VM-exit instruction length field from the VMCS into the VMX
558 * transient structure.
559 *
560 * @returns VBox status code.
561 * @param pVCpu Pointer to the VMCPU.
562 * @param pVmxTransient Pointer to the VMX transient structure.
563 */
564DECLINLINE(int) hmR0VmxReadExitInstrLenVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
565{
566 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN))
567 {
568 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbInstr);
569 AssertRCReturn(rc, rc);
570 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN;
571 }
572 return VINF_SUCCESS;
573}
574
575
576/**
577 * Reads the exit qualification from the VMCS into the VMX transient structure.
578 *
579 * @returns VBox status code.
580 * @param pVCpu Pointer to the VMCPU.
581 * @param pVmxTransient Pointer to the VMX transient structure.
582 */
583DECLINLINE(int) hmR0VmxReadExitQualificationVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
584{
585 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION))
586 {
587 int rc = VMXReadVmcsGstN(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQualification);
588 AssertRCReturn(rc, rc);
589 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION;
590 }
591 return VINF_SUCCESS;
592}
593
594
595/**
596 * Reads the IDT-vectoring information field from the VMCS into the VMX
597 * transient structure.
598 *
599 * @returns VBox status code.
600 * @param pVmxTransient Pointer to the VMX transient structure.
601 *
602 * @remarks No-long-jump zone!!!
603 */
604DECLINLINE(int) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
605{
606 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO))
607 {
608 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_INFO, &pVmxTransient->uIdtVectoringInfo);
609 AssertRCReturn(rc, rc);
610 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO;
611 }
612 return VINF_SUCCESS;
613}
614
615
616/**
617 * Reads the IDT-vectoring error code from the VMCS into the VMX
618 * transient structure.
619 *
620 * @returns VBox status code.
621 * @param pVmxTransient Pointer to the VMX transient structure.
622 */
623DECLINLINE(int) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
624{
625 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE))
626 {
627 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
628 AssertRCReturn(rc, rc);
629 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE;
630 }
631 return VINF_SUCCESS;
632}
633
634
635/**
636 * Enters VMX root mode operation on the current CPU.
637 *
638 * @returns VBox status code.
639 * @param pVM Pointer to the VM (optional, can be NULL, after
640 * a resume).
641 * @param HCPhysCpuPage Physical address of the VMXON region.
642 * @param pvCpuPage Pointer to the VMXON region.
643 */
644static int hmR0VmxEnterRootMode(PVM pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
645{
646 AssertReturn(HCPhysCpuPage != 0 && HCPhysCpuPage != NIL_RTHCPHYS, VERR_INVALID_PARAMETER);
647 AssertReturn(pvCpuPage, VERR_INVALID_PARAMETER);
648 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
649
650 if (pVM)
651 {
652 /* Write the VMCS revision dword to the VMXON region. */
653 *(uint32_t *)pvCpuPage = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.msr.vmx_basic_info);
654 }
655
656 /* Enable the VMX bit in CR4 if necessary. */
657 RTCCUINTREG uCr4 = ASMGetCR4();
658 if (!(uCr4 & X86_CR4_VMXE))
659 ASMSetCR4(uCr4 | X86_CR4_VMXE);
660
661 /* Enter VMX root mode. */
662 int rc = VMXEnable(HCPhysCpuPage);
663 if (RT_FAILURE(rc))
664 ASMSetCR4(uCr4);
665
666 return rc;
667}
668
669
670/**
671 * Exits VMX root mode operation on the current CPU.
672 *
673 * @returns VBox status code.
674 */
675static int hmR0VmxLeaveRootMode(void)
676{
677 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
678
679 /* If we're for some reason not in VMX root mode, then don't leave it. */
680 RTCCUINTREG uHostCR4 = ASMGetCR4();
681 if (uHostCR4 & X86_CR4_VMXE)
682 {
683 /* Exit VMX root mode and clear the VMX bit in CR4. */
684 VMXDisable();
685 ASMSetCR4(uHostCR4 & ~X86_CR4_VMXE);
686 return VINF_SUCCESS;
687 }
688
689 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
690}
691
692
693/**
694 * Allocates and maps one physically contiguous page. The allocated page is
695 * zero'd out. (Used by various VT-x structures).
696 *
697 * @returns IPRT status code.
698 * @param pMemObj Pointer to the ring-0 memory object.
699 * @param ppVirt Where to store the virtual address of the
700 * allocation.
701 * @param pPhys Where to store the physical address of the
702 * allocation.
703 */
704DECLINLINE(int) hmR0VmxPageAllocZ(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
705{
706 AssertPtrReturn(pMemObj, VERR_INVALID_PARAMETER);
707 AssertPtrReturn(ppVirt, VERR_INVALID_PARAMETER);
708 AssertPtrReturn(pHCPhys, VERR_INVALID_PARAMETER);
709
710 int rc = RTR0MemObjAllocCont(pMemObj, PAGE_SIZE, false /* fExecutable */);
711 if (RT_FAILURE(rc))
712 return rc;
713 *ppVirt = RTR0MemObjAddress(*pMemObj);
714 *pHCPhys = RTR0MemObjGetPagePhysAddr(*pMemObj, 0 /* iPage */);
715 ASMMemZero32(*ppVirt, PAGE_SIZE);
716 return VINF_SUCCESS;
717}
718
719
720/**
721 * Frees and unmaps an allocated physical page.
722 *
723 * @param pMemObj Pointer to the ring-0 memory object.
724 * @param ppVirt Where to re-initialize the virtual address of
725 * allocation as 0.
726 * @param pHCPhys Where to re-initialize the physical address of the
727 * allocation as 0.
728 */
729DECLINLINE(void) hmR0VmxPageFree(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
730{
731 AssertPtr(pMemObj);
732 AssertPtr(ppVirt);
733 AssertPtr(pHCPhys);
734 if (*pMemObj != NIL_RTR0MEMOBJ)
735 {
736 int rc = RTR0MemObjFree(*pMemObj, true /* fFreeMappings */);
737 AssertRC(rc);
738 *pMemObj = NIL_RTR0MEMOBJ;
739 *ppVirt = 0;
740 *pHCPhys = 0;
741 }
742}
743
744
745/**
746 * Worker function to free VT-x related structures.
747 *
748 * @returns IPRT status code.
749 * @param pVM Pointer to the VM.
750 */
751static void hmR0VmxStructsFree(PVM pVM)
752{
753 for (VMCPUID i = 0; i < pVM->cCpus; i++)
754 {
755 PVMCPU pVCpu = &pVM->aCpus[i];
756 AssertPtr(pVCpu);
757
758#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
759 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjHostMsr, &pVCpu->hm.s.vmx.pvHostMsr, &pVCpu->hm.s.vmx.HCPhysHostMsr);
760 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjGuestMsr, &pVCpu->hm.s.vmx.pvGuestMsr, &pVCpu->hm.s.vmx.HCPhysGuestMsr);
761#endif
762
763 if (pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
764 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjMsrBitmap, &pVCpu->hm.s.vmx.pvMsrBitmap, &pVCpu->hm.s.vmx.HCPhysMsrBitmap);
765
766 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjVirtApic, (PRTR0PTR)&pVCpu->hm.s.vmx.pbVirtApic, &pVCpu->hm.s.vmx.HCPhysVirtApic);
767 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjVmcs, &pVCpu->hm.s.vmx.pvVmcs, &pVCpu->hm.s.vmx.HCPhysVmcs);
768 }
769
770 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess, &pVM->hm.s.vmx.HCPhysApicAccess);
771#ifdef VBOX_WITH_CRASHDUMP_MAGIC
772 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
773#endif
774}
775
776
777/**
778 * Worker function to allocate VT-x related VM structures.
779 *
780 * @returns IPRT status code.
781 * @param pVM Pointer to the VM.
782 */
783static int hmR0VmxStructsAlloc(PVM pVM)
784{
785 /*
786 * Initialize members up-front so we can cleanup properly on allocation failure.
787 */
788#define VMXLOCAL_INIT_VM_MEMOBJ(a_Name, a_VirtPrefix) \
789 pVM->hm.s.vmx.hMemObj##a_Name = NIL_RTR0MEMOBJ; \
790 pVM->hm.s.vmx.a_VirtPrefix##a_Name = 0; \
791 pVM->hm.s.vmx.HCPhys##a_Name = 0;
792
793#define VMXLOCAL_INIT_VMCPU_MEMOBJ(a_Name, a_VirtPrefix) \
794 pVCpu->hm.s.vmx.hMemObj##a_Name = NIL_RTR0MEMOBJ; \
795 pVCpu->hm.s.vmx.a_VirtPrefix##a_Name = 0; \
796 pVCpu->hm.s.vmx.HCPhys##a_Name = 0;
797
798#ifdef VBOX_WITH_CRASHDUMP_MAGIC
799 VMXLOCAL_INIT_VM_MEMOBJ(Scratch, pv);
800#endif
801 VMXLOCAL_INIT_VM_MEMOBJ(ApicAccess, pb);
802
803 AssertCompile(sizeof(VMCPUID) == sizeof(pVM->cCpus));
804 for (VMCPUID i = 0; i < pVM->cCpus; i++)
805 {
806 PVMCPU pVCpu = &pVM->aCpus[i];
807 VMXLOCAL_INIT_VMCPU_MEMOBJ(Vmcs, pv);
808 VMXLOCAL_INIT_VMCPU_MEMOBJ(VirtApic, pb);
809 VMXLOCAL_INIT_VMCPU_MEMOBJ(MsrBitmap, pv);
810#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
811 VMXLOCAL_INIT_VMCPU_MEMOBJ(GuestMsr, pv);
812 VMXLOCAL_INIT_VMCPU_MEMOBJ(HostMsr, pv);
813#endif
814 }
815#undef VMXLOCAL_INIT_VMCPU_MEMOBJ
816#undef VMXLOCAL_INIT_VM_MEMOBJ
817
818 /*
819 * Allocate all the VT-x structures.
820 */
821 int rc = VINF_SUCCESS;
822#ifdef VBOX_WITH_CRASHDUMP_MAGIC
823 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
824 if (RT_FAILURE(rc))
825 goto cleanup;
826 strcpy((char *)pVM->hm.s.vmx.pbScratch, "SCRATCH Magic");
827 *(uint64_t *)(pVM->hm.s.vmx.pbScratch + 16) = UINT64_C(0xDEADBEEFDEADBEEF);
828#endif
829
830 /* Allocate the APIC-access page for trapping APIC accesses from the guest. */
831 if (pVM->hm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC)
832 {
833 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess,
834 &pVM->hm.s.vmx.HCPhysApicAccess);
835 if (RT_FAILURE(rc))
836 goto cleanup;
837 }
838
839 /*
840 * Initialize per-VCPU VT-x structures.
841 */
842 for (VMCPUID i = 0; i < pVM->cCpus; i++)
843 {
844 PVMCPU pVCpu = &pVM->aCpus[i];
845 AssertPtr(pVCpu);
846
847 /* Allocate the VM control structure (VMCS). */
848 AssertReturn(MSR_IA32_VMX_BASIC_INFO_VMCS_SIZE(pVM->hm.s.vmx.msr.vmx_basic_info) <= PAGE_SIZE, VERR_INTERNAL_ERROR);
849 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjVmcs, &pVCpu->hm.s.vmx.pvVmcs, &pVCpu->hm.s.vmx.HCPhysVmcs);
850 if (RT_FAILURE(rc))
851 goto cleanup;
852
853 /* Allocate the Virtual-APIC page for transparent TPR accesses. */
854 if (pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
855 {
856 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjVirtApic, (PRTR0PTR)&pVCpu->hm.s.vmx.pbVirtApic,
857 &pVCpu->hm.s.vmx.HCPhysVirtApic);
858 if (RT_FAILURE(rc))
859 goto cleanup;
860 }
861
862 /* Allocate the MSR-bitmap if supported by the CPU. The MSR-bitmap is for transparent accesses of specific MSRs. */
863 if (pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
864 {
865 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjMsrBitmap, &pVCpu->hm.s.vmx.pvMsrBitmap,
866 &pVCpu->hm.s.vmx.HCPhysMsrBitmap);
867 if (RT_FAILURE(rc))
868 goto cleanup;
869 memset(pVCpu->hm.s.vmx.pvMsrBitmap, 0xff, PAGE_SIZE);
870 }
871
872#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
873 /* Allocate the VM-entry MSR-load and VM-exit MSR-store page for the guest MSRs. */
874 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjGuestMsr, &pVCpu->hm.s.vmx.pvGuestMsr, &pVCpu->hm.s.vmx.HCPhysGuestMsr);
875 if (RT_FAILURE(rc))
876 goto cleanup;
877
878 /* Allocate the VM-exit MSR-load page for the host MSRs. */
879 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjHostMsr, &pVCpu->hm.s.vmx.pvHostMsr, &pVCpu->hm.s.vmx.HCPhysHostMsr);
880 if (RT_FAILURE(rc))
881 goto cleanup;
882#endif
883 }
884
885 return VINF_SUCCESS;
886
887cleanup:
888 hmR0VmxStructsFree(pVM);
889 return rc;
890}
891
892
893/**
894 * Does global VT-x initialization (called during module initialization).
895 *
896 * @returns VBox status code.
897 */
898VMMR0DECL(int) VMXR0GlobalInit(void)
899{
900#ifdef HMVMX_USE_FUNCTION_TABLE
901 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_apfnVMExitHandlers));
902# ifdef VBOX_STRICT
903 for (unsigned i = 0; i < RT_ELEMENTS(g_apfnVMExitHandlers); i++)
904 Assert(g_apfnVMExitHandlers[i]);
905# endif
906#endif
907 return VINF_SUCCESS;
908}
909
910
911/**
912 * Does global VT-x termination (called during module termination).
913 */
914VMMR0DECL(void) VMXR0GlobalTerm()
915{
916 /* Nothing to do currently. */
917}
918
919
920/**
921 * Sets up and activates VT-x on the current CPU.
922 *
923 * @returns VBox status code.
924 * @param pCpu Pointer to the global CPU info struct.
925 * @param pVM Pointer to the VM (can be NULL after a host resume
926 * operation).
927 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
928 * fEnabledByHost is true).
929 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
930 * @a fEnabledByHost is true).
931 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
932 * enable VT-x on the host.
933 */
934VMMR0DECL(int) VMXR0EnableCpu(PHMGLOBLCPUINFO pCpu, PVM pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost)
935{
936 AssertReturn(pCpu, VERR_INVALID_PARAMETER);
937 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
938
939 if (!fEnabledByHost)
940 {
941 int rc = hmR0VmxEnterRootMode(pVM, HCPhysCpuPage, pvCpuPage);
942 if (RT_FAILURE(rc))
943 return rc;
944 }
945
946 /*
947 * Flush all EPTP tagged-TLB entries (in case any other hypervisor have been using EPTPs) so that
948 * we can avoid an explicit flush while using new VPIDs. We would still need to flush
949 * each time while reusing a VPID after hitting the MaxASID limit once.
950 */
951 if ( pVM
952 && pVM->hm.s.fNestedPaging)
953 {
954 /* We require ALL_CONTEXT flush-type to be available on the CPU. See hmR0VmxSetupTaggedTlb(). */
955 Assert(pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS);
956 hmR0VmxFlushEpt(pVM, NULL /* pVCpu */, VMX_FLUSH_EPT_ALL_CONTEXTS);
957 pCpu->fFlushAsidBeforeUse = false;
958 }
959 else
960 {
961 /** @todo This is still not perfect. If on host resume (pVM is NULL or a VM
962 * without NestedPaging triggered this function) we still have the risk
963 * of potentially running with stale TLB-entries from other hypervisors
964 * when later we use a VM with NestedPaging. To fix this properly we will
965 * have to pass '&g_HvmR0' (see HMR0.cpp) to this function and read
966 * 'vmx_ept_vpid_caps' from it. Sigh. */
967 pCpu->fFlushAsidBeforeUse = true;
968 }
969
970 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
971 ++pCpu->cTlbFlushes;
972
973 return VINF_SUCCESS;
974}
975
976
977/**
978 * Deactivates VT-x on the current CPU.
979 *
980 * @returns VBox status code.
981 * @param pCpu Pointer to the global CPU info struct.
982 * @param pvCpuPage Pointer to the VMXON region.
983 * @param HCPhysCpuPage Physical address of the VMXON region.
984 *
985 * @remarks This function should never be called when SUPR0EnableVTx() or
986 * similar was used to enable VT-x on the host.
987 */
988VMMR0DECL(int) VMXR0DisableCpu(PHMGLOBLCPUINFO pCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
989{
990 NOREF(pCpu);
991 NOREF(pvCpuPage);
992 NOREF(HCPhysCpuPage);
993
994 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
995 return hmR0VmxLeaveRootMode();
996}
997
998
999/**
1000 * Sets the permission bits for the specified MSR in the MSR bitmap.
1001 *
1002 * @param pVCpu Pointer to the VMCPU.
1003 * @param uMSR The MSR value.
1004 * @param enmRead Whether reading this MSR causes a VM-exit.
1005 * @param enmWrite Whether writing this MSR causes a VM-exit.
1006 */
1007static void hmR0VmxSetMsrPermission(PVMCPU pVCpu, uint32_t uMsr, VMXMSREXITREAD enmRead, VMXMSREXITWRITE enmWrite)
1008{
1009 int32_t iBit;
1010 uint8_t *pbMsrBitmap = (uint8_t *)pVCpu->hm.s.vmx.pvMsrBitmap;
1011
1012 /*
1013 * Layout:
1014 * 0x000 - 0x3ff - Low MSR read bits
1015 * 0x400 - 0x7ff - High MSR read bits
1016 * 0x800 - 0xbff - Low MSR write bits
1017 * 0xc00 - 0xfff - High MSR write bits
1018 */
1019 if (uMsr <= 0x00001FFF)
1020 iBit = uMsr;
1021 else if ( uMsr >= 0xC0000000
1022 && uMsr <= 0xC0001FFF)
1023 {
1024 iBit = (uMsr - 0xC0000000);
1025 pbMsrBitmap += 0x400;
1026 }
1027 else
1028 {
1029 AssertMsgFailed(("hmR0VmxSetMsrPermission: Invalid MSR %#RX32\n", uMsr));
1030 return;
1031 }
1032
1033 Assert(iBit <= 0x1fff);
1034 if (enmRead == VMXMSREXIT_INTERCEPT_READ)
1035 ASMBitSet(pbMsrBitmap, iBit);
1036 else
1037 ASMBitClear(pbMsrBitmap, iBit);
1038
1039 if (enmWrite == VMXMSREXIT_INTERCEPT_WRITE)
1040 ASMBitSet(pbMsrBitmap + 0x800, iBit);
1041 else
1042 ASMBitClear(pbMsrBitmap + 0x800, iBit);
1043}
1044
1045
1046/**
1047 * Flushes the TLB using EPT.
1048 *
1049 * @returns VBox status code.
1050 * @param pVM Pointer to the VM.
1051 * @param pVCpu Pointer to the VMCPU (can be NULL depending on @a
1052 * enmFlush).
1053 * @param enmFlush Type of flush.
1054 */
1055static void hmR0VmxFlushEpt(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_EPT enmFlush)
1056{
1057 AssertPtr(pVM);
1058 Assert(pVM->hm.s.fNestedPaging);
1059
1060 uint64_t descriptor[2];
1061 if (enmFlush == VMX_FLUSH_EPT_ALL_CONTEXTS)
1062 descriptor[0] = 0;
1063 else
1064 {
1065 Assert(pVCpu);
1066 descriptor[0] = pVCpu->hm.s.vmx.HCPhysEPTP;
1067 }
1068 descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
1069
1070 int rc = VMXR0InvEPT(enmFlush, &descriptor[0]);
1071 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %RGv failed with %Rrc\n", enmFlush, pVCpu ? pVCpu->hm.s.vmx.HCPhysEPTP : 0,
1072 rc));
1073 if ( RT_SUCCESS(rc)
1074 && pVCpu)
1075 {
1076 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
1077 }
1078}
1079
1080
1081/**
1082 * Flushes the TLB using VPID.
1083 *
1084 * @returns VBox status code.
1085 * @param pVM Pointer to the VM.
1086 * @param pVCpu Pointer to the VMCPU (can be NULL depending on @a
1087 * enmFlush).
1088 * @param enmFlush Type of flush.
1089 * @param GCPtr Virtual address of the page to flush (can be 0 depending
1090 * on @a enmFlush).
1091 */
1092static void hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_VPID enmFlush, RTGCPTR GCPtr)
1093{
1094 AssertPtr(pVM);
1095 Assert(pVM->hm.s.vmx.fVpid);
1096
1097 uint64_t descriptor[2];
1098 if (enmFlush == VMX_FLUSH_VPID_ALL_CONTEXTS)
1099 {
1100 descriptor[0] = 0;
1101 descriptor[1] = 0;
1102 }
1103 else
1104 {
1105 AssertPtr(pVCpu);
1106 AssertMsg(pVCpu->hm.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
1107 AssertMsg(pVCpu->hm.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
1108 descriptor[0] = pVCpu->hm.s.uCurrentAsid;
1109 descriptor[1] = GCPtr;
1110 }
1111
1112 int rc = VMXR0InvVPID(enmFlush, &descriptor[0]); NOREF(rc);
1113 AssertMsg(rc == VINF_SUCCESS,
1114 ("VMXR0InvVPID %#x %u %RGv failed with %d\n", enmFlush, pVCpu ? pVCpu->hm.s.uCurrentAsid : 0, GCPtr, rc));
1115 if ( RT_SUCCESS(rc)
1116 && pVCpu)
1117 {
1118 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
1119 }
1120}
1121
1122
1123/**
1124 * Invalidates a guest page by guest virtual address. Only relevant for
1125 * EPT/VPID, otherwise there is nothing really to invalidate.
1126 *
1127 * @returns VBox status code.
1128 * @param pVM Pointer to the VM.
1129 * @param pVCpu Pointer to the VMCPU.
1130 * @param GCVirt Guest virtual address of the page to invalidate.
1131 */
1132VMMR0DECL(int) VMXR0InvalidatePage(PVM pVM, PVMCPU pVCpu, RTGCPTR GCVirt)
1133{
1134 AssertPtr(pVM);
1135 AssertPtr(pVCpu);
1136 LogFlowFunc(("pVM=%p pVCpu=%p GCVirt=%RGv\n", pVM, pVCpu, GCVirt));
1137
1138 bool fFlushPending = VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1139 if (!fFlushPending)
1140 {
1141 /*
1142 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for the EPT case
1143 * See @bugref{6043} and @bugref{6177}.
1144 *
1145 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*() as this
1146 * function maybe called in a loop with individual addresses.
1147 */
1148 if (pVM->hm.s.vmx.fVpid)
1149 {
1150 if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
1151 {
1152 hmR0VmxFlushVpid(pVM, pVCpu, VMX_FLUSH_VPID_INDIV_ADDR, GCVirt);
1153 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
1154 }
1155 else
1156 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1157 }
1158 else if (pVM->hm.s.fNestedPaging)
1159 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1160 }
1161
1162 return VINF_SUCCESS;
1163}
1164
1165
1166/**
1167 * Invalidates a guest page by physical address. Only relevant for EPT/VPID,
1168 * otherwise there is nothing really to invalidate.
1169 *
1170 * @returns VBox status code.
1171 * @param pVM Pointer to the VM.
1172 * @param pVCpu Pointer to the VMCPU.
1173 * @param GCPhys Guest physical address of the page to invalidate.
1174 */
1175VMMR0DECL(int) VMXR0InvalidatePhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
1176{
1177 LogFlowFunc(("%RGp\n", GCPhys));
1178
1179 /*
1180 * We cannot flush a page by guest-physical address. invvpid takes only a linear address while invept only flushes
1181 * by EPT not individual addresses. We update the force flag here and flush before the next VM-entry in hmR0VmxFlushTLB*().
1182 * This function might be called in a loop. This should cause a flush-by-EPT if EPT is in use. See @bugref{6568}.
1183 */
1184 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1185 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgPhys);
1186 return VINF_SUCCESS;
1187}
1188
1189
1190/**
1191 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
1192 * case where neither EPT nor VPID is supported by the CPU.
1193 *
1194 * @param pVM Pointer to the VM.
1195 * @param pVCpu Pointer to the VMCPU.
1196 *
1197 * @remarks Called with interrupts disabled.
1198 */
1199static void hmR0VmxFlushTaggedTlbNone(PVM pVM, PVMCPU pVCpu)
1200{
1201 NOREF(pVM);
1202 AssertPtr(pVCpu);
1203 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
1204 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
1205
1206 PHMGLOBLCPUINFO pCpu = HMR0GetCurrentCpu();
1207 AssertPtr(pCpu);
1208
1209 pVCpu->hm.s.TlbShootdown.cPages = 0;
1210 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
1211 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
1212 pVCpu->hm.s.fForceTLBFlush = false;
1213 return;
1214}
1215
1216
1217/**
1218 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
1219 *
1220 * @param pVM Pointer to the VM.
1221 * @param pVCpu Pointer to the VMCPU.
1222 * @remarks All references to "ASID" in this function pertains to "VPID" in
1223 * Intel's nomenclature. The reason is, to avoid confusion in compare
1224 * statements since the host-CPU copies are named "ASID".
1225 *
1226 * @remarks Called with interrupts disabled.
1227 */
1228static void hmR0VmxFlushTaggedTlbBoth(PVM pVM, PVMCPU pVCpu)
1229{
1230 AssertPtr(pVM);
1231 AssertPtr(pVCpu);
1232 AssertMsg(pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid,
1233 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
1234 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hm.s.fNestedPaging, pVM->hm.s.vmx.fVpid));
1235
1236 PHMGLOBLCPUINFO pCpu = HMR0GetCurrentCpu();
1237 AssertPtr(pCpu);
1238
1239 /*
1240 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
1241 * This can happen both for start & resume due to long jumps back to ring-3.
1242 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB
1243 * or the host CPU is online after a suspend/resume, so we cannot reuse the current ASID anymore.
1244 */
1245 bool fNewASID = false;
1246 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
1247 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
1248 {
1249 pVCpu->hm.s.fForceTLBFlush = true;
1250 fNewASID = true;
1251 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
1252 }
1253
1254 /*
1255 * Check for explicit TLB shootdowns.
1256 */
1257 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
1258 {
1259 pVCpu->hm.s.fForceTLBFlush = true;
1260 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
1261 }
1262
1263 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
1264 if (pVCpu->hm.s.fForceTLBFlush)
1265 {
1266 if (fNewASID)
1267 {
1268 ++pCpu->uCurrentAsid;
1269 if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
1270 {
1271 pCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
1272 pCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
1273 pCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
1274 }
1275
1276 pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
1277 if (pCpu->fFlushAsidBeforeUse)
1278 hmR0VmxFlushVpid(pVM, pVCpu, pVM->hm.s.vmx.enmFlushVpid, 0 /* GCPtr */);
1279 }
1280 else
1281 {
1282 /*
1283 * Changes to the EPT paging structure by VMM requires flushing by EPT as the CPU creates
1284 * guest-physical (only EPT-tagged) mappings while traversing the EPT tables when EPT is in use.
1285 * Flushing by VPID will only flush linear (only VPID-tagged) and combined (EPT+VPID tagged) mappings
1286 * but not guest-physical mappings.
1287 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information". See @bugref{6568}.
1288 */
1289 hmR0VmxFlushEpt(pVM, pVCpu, pVM->hm.s.vmx.enmFlushEpt);
1290 }
1291
1292 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
1293 pVCpu->hm.s.fForceTLBFlush = false;
1294 }
1295 else
1296 {
1297 AssertMsg(pVCpu->hm.s.uCurrentAsid && pCpu->uCurrentAsid,
1298 ("hm->uCurrentAsid=%lu hm->cTlbFlushes=%lu cpu->uCurrentAsid=%lu cpu->cTlbFlushes=%lu\n",
1299 pVCpu->hm.s.uCurrentAsid, pVCpu->hm.s.cTlbFlushes,
1300 pCpu->uCurrentAsid, pCpu->cTlbFlushes));
1301
1302 /** @todo We never set VMCPU_FF_TLB_SHOOTDOWN anywhere so this path should
1303 * not be executed. See hmQueueInvlPage() where it is commented
1304 * out. Support individual entry flushing someday. */
1305 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TLB_SHOOTDOWN))
1306 {
1307 STAM_COUNTER_INC(&pVCpu->hm.s.StatTlbShootdown);
1308
1309 /*
1310 * Flush individual guest entries using VPID from the TLB or as little as possible with EPT
1311 * as supported by the CPU.
1312 */
1313 if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
1314 {
1315 for (uint32_t i = 0; i < pVCpu->hm.s.TlbShootdown.cPages; i++)
1316 hmR0VmxFlushVpid(pVM, pVCpu, VMX_FLUSH_VPID_INDIV_ADDR, pVCpu->hm.s.TlbShootdown.aPages[i]);
1317 }
1318 else
1319 hmR0VmxFlushEpt(pVM, pVCpu, pVM->hm.s.vmx.enmFlushEpt);
1320 }
1321 else
1322 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch);
1323 }
1324 pVCpu->hm.s.TlbShootdown.cPages = 0;
1325 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
1326
1327 AssertMsg(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes,
1328 ("Flush count mismatch for cpu %d (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
1329 AssertMsg(pCpu->uCurrentAsid >= 1 && pCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
1330 ("cpu%d uCurrentAsid = %u\n", pCpu->idCpu, pCpu->uCurrentAsid));
1331 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
1332 ("cpu%d VM uCurrentAsid = %u\n", pCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
1333
1334 /* Update VMCS with the VPID. */
1335 int rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_FIELD_VPID, pVCpu->hm.s.uCurrentAsid);
1336 AssertRC(rc);
1337}
1338
1339
1340/**
1341 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
1342 *
1343 * @returns VBox status code.
1344 * @param pVM Pointer to the VM.
1345 * @param pVCpu Pointer to the VMCPU.
1346 *
1347 * @remarks Called with interrupts disabled.
1348 */
1349static void hmR0VmxFlushTaggedTlbEpt(PVM pVM, PVMCPU pVCpu)
1350{
1351 AssertPtr(pVM);
1352 AssertPtr(pVCpu);
1353 AssertMsg(pVM->hm.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with NestedPaging disabled."));
1354 AssertMsg(!pVM->hm.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID enabled."));
1355
1356 PHMGLOBLCPUINFO pCpu = HMR0GetCurrentCpu();
1357 AssertPtr(pCpu);
1358
1359 /*
1360 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
1361 * This can happen both for start & resume due to long jumps back to ring-3.
1362 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
1363 */
1364 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
1365 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
1366 {
1367 pVCpu->hm.s.fForceTLBFlush = true;
1368 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
1369 }
1370
1371 /* Check for explicit TLB shootdown flushes. */
1372 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
1373 {
1374 pVCpu->hm.s.fForceTLBFlush = true;
1375 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
1376 }
1377
1378 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
1379 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
1380
1381 if (pVCpu->hm.s.fForceTLBFlush)
1382 {
1383 hmR0VmxFlushEpt(pVM, pVCpu, pVM->hm.s.vmx.enmFlushEpt);
1384 pVCpu->hm.s.fForceTLBFlush = false;
1385 }
1386 else
1387 {
1388 /** @todo We never set VMCPU_FF_TLB_SHOOTDOWN anywhere so this path should
1389 * not be executed. See hmQueueInvlPage() where it is commented
1390 * out. Support individual entry flushing someday. */
1391 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TLB_SHOOTDOWN))
1392 {
1393 /* We cannot flush individual entries without VPID support. Flush using EPT. */
1394 STAM_COUNTER_INC(&pVCpu->hm.s.StatTlbShootdown);
1395 hmR0VmxFlushEpt(pVM, pVCpu, pVM->hm.s.vmx.enmFlushEpt);
1396 }
1397 else
1398 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch);
1399 }
1400
1401 pVCpu->hm.s.TlbShootdown.cPages = 0;
1402 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
1403}
1404
1405
1406/**
1407 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
1408 *
1409 * @returns VBox status code.
1410 * @param pVM Pointer to the VM.
1411 * @param pVCpu Pointer to the VMCPU.
1412 *
1413 * @remarks Called with interrupts disabled.
1414 */
1415static void hmR0VmxFlushTaggedTlbVpid(PVM pVM, PVMCPU pVCpu)
1416{
1417 AssertPtr(pVM);
1418 AssertPtr(pVCpu);
1419 AssertMsg(pVM->hm.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked with VPID disabled."));
1420 AssertMsg(!pVM->hm.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging enabled"));
1421
1422 PHMGLOBLCPUINFO pCpu = HMR0GetCurrentCpu();
1423
1424 /*
1425 * Force a TLB flush for the first world switch if the current CPU differs from the one we ran on last.
1426 * This can happen both for start & resume due to long jumps back to ring-3.
1427 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB
1428 * or the host CPU is online after a suspend/resume, so we cannot reuse the current ASID anymore.
1429 */
1430 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
1431 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
1432 {
1433 pVCpu->hm.s.fForceTLBFlush = true;
1434 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
1435 }
1436
1437 /* Check for explicit TLB shootdown flushes. */
1438 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
1439 {
1440 /*
1441 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see hmR0VmxSetupTaggedTlb())
1442 * we would need to explicitly flush in this case (add an fExplicitFlush = true here and change the
1443 * pCpu->fFlushAsidBeforeUse check below to include fExplicitFlush's too) - an obscure corner case.
1444 */
1445 pVCpu->hm.s.fForceTLBFlush = true;
1446 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
1447 }
1448
1449 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
1450 if (pVCpu->hm.s.fForceTLBFlush)
1451 {
1452 ++pCpu->uCurrentAsid;
1453 if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
1454 {
1455 pCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
1456 pCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
1457 pCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
1458 }
1459
1460 pVCpu->hm.s.fForceTLBFlush = false;
1461 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
1462 pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
1463 if (pCpu->fFlushAsidBeforeUse)
1464 hmR0VmxFlushVpid(pVM, pVCpu, pVM->hm.s.vmx.enmFlushVpid, 0 /* GCPtr */);
1465 }
1466 else
1467 {
1468 AssertMsg(pVCpu->hm.s.uCurrentAsid && pCpu->uCurrentAsid,
1469 ("hm->uCurrentAsid=%lu hm->cTlbFlushes=%lu cpu->uCurrentAsid=%lu cpu->cTlbFlushes=%lu\n",
1470 pVCpu->hm.s.uCurrentAsid, pVCpu->hm.s.cTlbFlushes,
1471 pCpu->uCurrentAsid, pCpu->cTlbFlushes));
1472
1473 /** @todo We never set VMCPU_FF_TLB_SHOOTDOWN anywhere so this path should
1474 * not be executed. See hmQueueInvlPage() where it is commented
1475 * out. Support individual entry flushing someday. */
1476 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TLB_SHOOTDOWN))
1477 {
1478 /* Flush individual guest entries using VPID or as little as possible with EPT as supported by the CPU. */
1479 if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
1480 {
1481 for (uint32_t i = 0; i < pVCpu->hm.s.TlbShootdown.cPages; i++)
1482 hmR0VmxFlushVpid(pVM, pVCpu, VMX_FLUSH_VPID_INDIV_ADDR, pVCpu->hm.s.TlbShootdown.aPages[i]);
1483 }
1484 else
1485 hmR0VmxFlushVpid(pVM, pVCpu, pVM->hm.s.vmx.enmFlushVpid, 0 /* GCPtr */);
1486 }
1487 else
1488 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch);
1489 }
1490
1491 pVCpu->hm.s.TlbShootdown.cPages = 0;
1492 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
1493
1494 AssertMsg(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes,
1495 ("Flush count mismatch for cpu %d (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
1496 AssertMsg(pCpu->uCurrentAsid >= 1 && pCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
1497 ("cpu%d uCurrentAsid = %u\n", pCpu->idCpu, pCpu->uCurrentAsid));
1498 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
1499 ("cpu%d VM uCurrentAsid = %u\n", pCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
1500
1501 int rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_FIELD_VPID, pVCpu->hm.s.uCurrentAsid);
1502 AssertRC(rc);
1503}
1504
1505
1506/**
1507 * Flushes the guest TLB entry based on CPU capabilities.
1508 *
1509 * @param pVCpu Pointer to the VMCPU.
1510 */
1511DECLINLINE(void) hmR0VmxFlushTaggedTlb(PVMCPU pVCpu)
1512{
1513 PVM pVM = pVCpu->CTX_SUFF(pVM);
1514 switch (pVM->hm.s.vmx.uFlushTaggedTlb)
1515 {
1516 case HMVMX_FLUSH_TAGGED_TLB_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pVM, pVCpu); break;
1517 case HMVMX_FLUSH_TAGGED_TLB_EPT: hmR0VmxFlushTaggedTlbEpt(pVM, pVCpu); break;
1518 case HMVMX_FLUSH_TAGGED_TLB_VPID: hmR0VmxFlushTaggedTlbVpid(pVM, pVCpu); break;
1519 case HMVMX_FLUSH_TAGGED_TLB_NONE: hmR0VmxFlushTaggedTlbNone(pVM, pVCpu); break;
1520 default:
1521 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
1522 break;
1523 }
1524}
1525
1526
1527/**
1528 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
1529 * TLB entries from the host TLB before VM-entry.
1530 *
1531 * @returns VBox status code.
1532 * @param pVM Pointer to the VM.
1533 */
1534static int hmR0VmxSetupTaggedTlb(PVM pVM)
1535{
1536 /*
1537 * Determine optimal flush type for Nested Paging.
1538 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup unrestricted
1539 * guest execution (see hmR3InitFinalizeR0()).
1540 */
1541 if (pVM->hm.s.fNestedPaging)
1542 {
1543 if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
1544 {
1545 if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
1546 pVM->hm.s.vmx.enmFlushEpt = VMX_FLUSH_EPT_SINGLE_CONTEXT;
1547 else if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
1548 pVM->hm.s.vmx.enmFlushEpt = VMX_FLUSH_EPT_ALL_CONTEXTS;
1549 else
1550 {
1551 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
1552 pVM->hm.s.vmx.enmFlushEpt = VMX_FLUSH_EPT_NOT_SUPPORTED;
1553 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1554 }
1555
1556 /* Make sure the write-back cacheable memory type for EPT is supported. */
1557 if (!(pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB))
1558 {
1559 LogRel(("hmR0VmxSetupTaggedTlb: Unsupported EPTP memory type %#x.\n", pVM->hm.s.vmx.msr.vmx_ept_vpid_caps));
1560 pVM->hm.s.vmx.enmFlushEpt = VMX_FLUSH_EPT_NOT_SUPPORTED;
1561 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1562 }
1563 }
1564 else
1565 {
1566 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
1567 pVM->hm.s.vmx.enmFlushEpt = VMX_FLUSH_EPT_NOT_SUPPORTED;
1568 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1569 }
1570 }
1571
1572 /*
1573 * Determine optimal flush type for VPID.
1574 */
1575 if (pVM->hm.s.vmx.fVpid)
1576 {
1577 if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
1578 {
1579 if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
1580 pVM->hm.s.vmx.enmFlushVpid = VMX_FLUSH_VPID_SINGLE_CONTEXT;
1581 else if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
1582 pVM->hm.s.vmx.enmFlushVpid = VMX_FLUSH_VPID_ALL_CONTEXTS;
1583 else
1584 {
1585 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
1586 if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
1587 LogRel(("hmR0VmxSetupTaggedTlb: Only INDIV_ADDR supported. Ignoring VPID.\n"));
1588 if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
1589 LogRel(("hmR0VmxSetupTaggedTlb: Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
1590 pVM->hm.s.vmx.enmFlushVpid = VMX_FLUSH_VPID_NOT_SUPPORTED;
1591 pVM->hm.s.vmx.fVpid = false;
1592 }
1593 }
1594 else
1595 {
1596 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
1597 Log4(("hmR0VmxSetupTaggedTlb: VPID supported without INVEPT support. Ignoring VPID.\n"));
1598 pVM->hm.s.vmx.enmFlushVpid = VMX_FLUSH_VPID_NOT_SUPPORTED;
1599 pVM->hm.s.vmx.fVpid = false;
1600 }
1601 }
1602
1603 /*
1604 * Setup the handler for flushing tagged-TLBs.
1605 */
1606 if (pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid)
1607 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_EPT_VPID;
1608 else if (pVM->hm.s.fNestedPaging)
1609 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_EPT;
1610 else if (pVM->hm.s.vmx.fVpid)
1611 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_VPID;
1612 else
1613 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_NONE;
1614 return VINF_SUCCESS;
1615}
1616
1617
1618/**
1619 * Sets up pin-based VM-execution controls in the VMCS.
1620 *
1621 * @returns VBox status code.
1622 * @param pVM Pointer to the VM.
1623 * @param pVCpu Pointer to the VMCPU.
1624 */
1625static int hmR0VmxSetupPinCtls(PVM pVM, PVMCPU pVCpu)
1626{
1627 AssertPtr(pVM);
1628 AssertPtr(pVCpu);
1629
1630 uint32_t val = pVM->hm.s.vmx.msr.vmx_pin_ctls.n.disallowed0; /* Bits set here must always be set. */
1631 uint32_t zap = pVM->hm.s.vmx.msr.vmx_pin_ctls.n.allowed1; /* Bits cleared here must always be cleared. */
1632
1633 val |= VMX_VMCS_CTRL_PIN_EXEC_EXT_INT_EXIT /* External interrupts causes a VM-exits. */
1634 | VMX_VMCS_CTRL_PIN_EXEC_NMI_EXIT; /* Non-maskable interrupts causes a VM-exit. */
1635 Assert(!(val & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI));
1636
1637 /* Enable the VMX preemption timer. */
1638 if (pVM->hm.s.vmx.fUsePreemptTimer)
1639 {
1640 Assert(pVM->hm.s.vmx.msr.vmx_pin_ctls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_PREEMPT_TIMER);
1641 val |= VMX_VMCS_CTRL_PIN_EXEC_PREEMPT_TIMER;
1642 }
1643
1644 if ((val & zap) != val)
1645 {
1646 LogRel(("hmR0VmxSetupPinCtls: invalid pin-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
1647 pVM->hm.s.vmx.msr.vmx_pin_ctls.n.disallowed0, val, zap));
1648 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1649 }
1650
1651 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, val);
1652 AssertRCReturn(rc, rc);
1653
1654 /* Update VCPU with the currently set pin-based VM-execution controls. */
1655 pVCpu->hm.s.vmx.u32PinCtls = val;
1656 return rc;
1657}
1658
1659
1660/**
1661 * Sets up processor-based VM-execution controls in the VMCS.
1662 *
1663 * @returns VBox status code.
1664 * @param pVM Pointer to the VM.
1665 * @param pVMCPU Pointer to the VMCPU.
1666 */
1667static int hmR0VmxSetupProcCtls(PVM pVM, PVMCPU pVCpu)
1668{
1669 AssertPtr(pVM);
1670 AssertPtr(pVCpu);
1671
1672 int rc = VERR_INTERNAL_ERROR_5;
1673 uint32_t val = pVM->hm.s.vmx.msr.vmx_proc_ctls.n.disallowed0; /* Bits set here must be set in the VMCS. */
1674 uint32_t zap = pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
1675
1676 val |= VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT /* HLT causes a VM-exit. */
1677 | VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
1678 | VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
1679 | VMX_VMCS_CTRL_PROC_EXEC_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
1680 | VMX_VMCS_CTRL_PROC_EXEC_RDPMC_EXIT /* RDPMC causes a VM-exit. */
1681 | VMX_VMCS_CTRL_PROC_EXEC_MONITOR_EXIT /* MONITOR causes a VM-exit. */
1682 | VMX_VMCS_CTRL_PROC_EXEC_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
1683
1684 /* We toggle VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
1685 if ( !(pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT)
1686 || (pVM->hm.s.vmx.msr.vmx_proc_ctls.n.disallowed0 & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT))
1687 {
1688 LogRel(("hmR0VmxSetupProcCtls: unsupported VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT combo!"));
1689 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1690 }
1691
1692 /* Without Nested Paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
1693 if (!pVM->hm.s.fNestedPaging)
1694 {
1695 Assert(!pVM->hm.s.vmx.fUnrestrictedGuest); /* Paranoia. */
1696 val |= VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT
1697 | VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
1698 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
1699 }
1700
1701 /* Use TPR shadowing if supported by the CPU. */
1702 if (pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
1703 {
1704 Assert(pVCpu->hm.s.vmx.HCPhysVirtApic);
1705 Assert(!(pVCpu->hm.s.vmx.HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
1706 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, 0);
1707 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VAPIC_PAGEADDR_FULL, pVCpu->hm.s.vmx.HCPhysVirtApic);
1708 AssertRCReturn(rc, rc);
1709
1710 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
1711 /* CR8 writes causes a VM-exit based on TPR threshold. */
1712 Assert(!(val & VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT));
1713 Assert(!(val & VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT));
1714 }
1715 else
1716 {
1717 val |= VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT /* CR8 reads causes a VM-exit. */
1718 | VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT; /* CR8 writes causes a VM-exit. */
1719 }
1720
1721 /* Use MSR-bitmaps if supported by the CPU. */
1722 if (pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1723 {
1724 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS;
1725
1726 Assert(pVCpu->hm.s.vmx.HCPhysMsrBitmap);
1727 Assert(!(pVCpu->hm.s.vmx.HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
1728 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, pVCpu->hm.s.vmx.HCPhysMsrBitmap);
1729 AssertRCReturn(rc, rc);
1730
1731 /*
1732 * The guest can access the following MSRs (read, write) without causing VM-exits; they are loaded/stored
1733 * automatically (either as part of the MSR-load/store areas or dedicated fields in the VMCS).
1734 */
1735 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_CS, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1736 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_ESP, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1737 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_EIP, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1738 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_LSTAR, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1739 hmR0VmxSetMsrPermission(pVCpu, MSR_K6_STAR, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1740 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_SF_MASK, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1741 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_KERNEL_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1742 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1743 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_FS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1744 }
1745
1746 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
1747 if (pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
1748 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL;
1749
1750 if ((val & zap) != val)
1751 {
1752 LogRel(("hmR0VmxSetupProcCtls: invalid processor-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
1753 pVM->hm.s.vmx.msr.vmx_proc_ctls.n.disallowed0, val, zap));
1754 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1755 }
1756
1757 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, val);
1758 AssertRCReturn(rc, rc);
1759
1760 /* Update VCPU with the currently set processor-based VM-execution controls. */
1761 pVCpu->hm.s.vmx.u32ProcCtls = val;
1762
1763 /*
1764 * Secondary processor-based VM-execution controls.
1765 */
1766 if (RT_LIKELY(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL))
1767 {
1768 val = pVM->hm.s.vmx.msr.vmx_proc_ctls2.n.disallowed0; /* Bits set here must be set in the VMCS. */
1769 zap = pVM->hm.s.vmx.msr.vmx_proc_ctls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
1770
1771 if (pVM->hm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT)
1772 val |= VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT; /* WBINVD causes a VM-exit. */
1773
1774 if (pVM->hm.s.fNestedPaging)
1775 val |= VMX_VMCS_CTRL_PROC_EXEC2_EPT; /* Enable EPT. */
1776 else
1777 {
1778 /*
1779 * Without Nested Paging, INVPCID should cause a VM-exit. Enabling this bit causes the CPU to refer to
1780 * VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT when INVPCID is executed by the guest.
1781 * See Intel spec. 25.4 "Changes to instruction behaviour in VMX non-root operation".
1782 */
1783 if (pVM->hm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_INVPCID)
1784 val |= VMX_VMCS_CTRL_PROC_EXEC2_INVPCID;
1785 }
1786
1787 if (pVM->hm.s.vmx.fVpid)
1788 val |= VMX_VMCS_CTRL_PROC_EXEC2_VPID; /* Enable VPID. */
1789
1790 if (pVM->hm.s.vmx.fUnrestrictedGuest)
1791 val |= VMX_VMCS_CTRL_PROC_EXEC2_UNRESTRICTED_GUEST; /* Enable Unrestricted Execution. */
1792
1793 /* Enable Virtual-APIC page accesses if supported by the CPU. This is essentially where the TPR shadow resides. */
1794 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
1795 * done dynamically. */
1796 if (pVM->hm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC)
1797 {
1798 Assert(pVM->hm.s.vmx.HCPhysApicAccess);
1799 Assert(!(pVM->hm.s.vmx.HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
1800 val |= VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC; /* Virtualize APIC accesses. */
1801 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, pVM->hm.s.vmx.HCPhysApicAccess);
1802 AssertRCReturn(rc, rc);
1803 }
1804
1805 if (pVM->hm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP)
1806 {
1807 val |= VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP; /* Enable RDTSCP support. */
1808 if (pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1809 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_TSC_AUX, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1810 }
1811
1812 if ((val & zap) != val)
1813 {
1814 LogRel(("hmR0VmxSetupProcCtls: invalid secondary processor-based VM-execution controls combo! "
1815 "cpu=%#RX64 val=%#RX64 zap=%#RX64\n", pVM->hm.s.vmx.msr.vmx_proc_ctls2.n.disallowed0, val, zap));
1816 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1817 }
1818
1819 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, val);
1820 AssertRCReturn(rc, rc);
1821
1822 /* Update VCPU with the currently set secondary processor-based VM-execution controls. */
1823 pVCpu->hm.s.vmx.u32ProcCtls2 = val;
1824 }
1825
1826 return VINF_SUCCESS;
1827}
1828
1829
1830/**
1831 * Sets up miscellaneous (everything other than Pin & Processor-based
1832 * VM-execution) control fields in the VMCS.
1833 *
1834 * @returns VBox status code.
1835 * @param pVM Pointer to the VM.
1836 * @param pVCpu Pointer to the VMCPU.
1837 */
1838static int hmR0VmxSetupMiscCtls(PVM pVM, PVMCPU pVCpu)
1839{
1840 AssertPtr(pVM);
1841 AssertPtr(pVCpu);
1842
1843 /** @todo Shouldn't we able to avoid initializing with 0? */
1844 int rc = VERR_GENERAL_FAILURE;
1845
1846 /* All CR3 accesses cause VM-exits. Later we optimize CR3 accesses (see hmR0VmxLoadGuestControlRegs())*/
1847 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_CR3_TARGET_COUNT, 0); AssertRCReturn(rc, rc);
1848 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, 0); AssertRCReturn(rc, rc);
1849
1850 /*
1851 * Set MASK & MATCH to 0. VMX checks if GuestPFErrCode & MASK == MATCH. If equal (in our case it always is)
1852 * and if the X86_XCPT_PF bit in the exception bitmap is set it causes a VM-exit, if clear doesn't cause an exit.
1853 * We thus use the exception bitmap to control it rather than use both.
1854 */
1855 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, 0); AssertRCReturn(rc, rc);
1856 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, 0); AssertRCReturn(rc, rc);
1857
1858 /** @todo Explore possibility of using IO-bitmaps. */
1859 /* All IO & IOIO instructions cause VM-exits. */
1860 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_IO_BITMAP_A_FULL, 0); AssertRCReturn(rc, rc);
1861 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_IO_BITMAP_B_FULL, 0); AssertRCReturn(rc, rc);
1862
1863 /* Initialize the MSR-bitmap area. */
1864 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, 0); AssertRCReturn(rc, rc);
1865 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, 0); AssertRCReturn(rc, rc);
1866 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, 0); AssertRCReturn(rc, rc);
1867
1868#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
1869 /* Setup MSR autoloading/storing. */
1870 Assert(pVCpu->hm.s.vmx.HCPhysGuestMsr);
1871 Assert(!(pVCpu->hm.s.vmx.HCPhysGuestMsr & 0xf)); /* Lower 4 bits MBZ. */
1872 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, pVCpu->hm.s.vmx.HCPhysGuestMsr);
1873 AssertRCReturn(rc, rc);
1874 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, pVCpu->hm.s.vmx.HCPhysGuestMsr);
1875 AssertRCReturn(rc, rc);
1876
1877 Assert(pVCpu->hm.s.vmx.HCPhysHostMsr);
1878 Assert(!(pVCpu->hm.s.vmx.HCPhysHostMsr & 0xf)); /* Lower 4 bits MBZ. */
1879 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, pVCpu->hm.s.vmx.HCPhysHostMsr);
1880 AssertRCReturn(rc, rc);
1881#endif
1882
1883 /* Set VMCS link pointer. Reserved for future use, must be -1. Intel spec. 24.4 "Guest-State Area". */
1884 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, UINT64_C(0xffffffffffffffff));
1885 AssertRCReturn(rc, rc);
1886
1887 /* Setup debug controls */
1888 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, 0); /** @todo We don't support IA32_DEBUGCTL MSR. Should we? */
1889 AssertRCReturn(rc, rc);
1890 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, 0);
1891 AssertRCReturn(rc, rc);
1892 return rc;
1893}
1894
1895
1896/**
1897 * Sets up the initial exception bitmap in the VMCS based on static conditions
1898 * (i.e. conditions that cannot ever change at runtime).
1899 *
1900 * @returns VBox status code.
1901 * @param pVM Pointer to the VM.
1902 * @param pVCpu Pointer to the VMCPU.
1903 */
1904static int hmR0VmxInitXcptBitmap(PVM pVM, PVMCPU pVCpu)
1905{
1906 AssertPtr(pVM);
1907 AssertPtr(pVCpu);
1908
1909 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
1910
1911 uint32_t u32XcptBitmap = 0;
1912
1913 /* Without Nested Paging, #PF must cause a VM-exit so we can sync our shadow page tables. */
1914 if (!pVM->hm.s.fNestedPaging)
1915 u32XcptBitmap |= RT_BIT(X86_XCPT_PF);
1916
1917 pVCpu->hm.s.vmx.u32XcptBitmap = u32XcptBitmap;
1918 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
1919 AssertRCReturn(rc, rc);
1920 return rc;
1921}
1922
1923
1924/**
1925 * Sets up the initial guest-state mask. The guest-state mask is consulted
1926 * before reading guest-state fields from the VMCS as VMREADs can be expensive
1927 * for the nested virtualization case (as it would cause a VM-exit).
1928 *
1929 * @param pVCpu Pointer to the VMCPU.
1930 */
1931static int hmR0VmxInitUpdatedGuestStateMask(PVMCPU pVCpu)
1932{
1933 /* Initially the guest-state is up-to-date as there is nothing in the VMCS. */
1934 pVCpu->hm.s.vmx.fUpdatedGuestState = HMVMX_UPDATED_GUEST_ALL;
1935 return VINF_SUCCESS;
1936}
1937
1938
1939/**
1940 * Does per-VM VT-x initialization.
1941 *
1942 * @returns VBox status code.
1943 * @param pVM Pointer to the VM.
1944 */
1945VMMR0DECL(int) VMXR0InitVM(PVM pVM)
1946{
1947 LogFlowFunc(("pVM=%p\n", pVM));
1948
1949 int rc = hmR0VmxStructsAlloc(pVM);
1950 if (RT_FAILURE(rc))
1951 {
1952 LogRel(("VMXR0InitVM: hmR0VmxStructsAlloc failed! rc=%Rrc\n", rc));
1953 return rc;
1954 }
1955
1956 return VINF_SUCCESS;
1957}
1958
1959
1960/**
1961 * Does per-VM VT-x termination.
1962 *
1963 * @returns VBox status code.
1964 * @param pVM Pointer to the VM.
1965 */
1966VMMR0DECL(int) VMXR0TermVM(PVM pVM)
1967{
1968 LogFlowFunc(("pVM=%p\n", pVM));
1969
1970#ifdef VBOX_WITH_CRASHDUMP_MAGIC
1971 if (pVM->hm.s.vmx.hMemObjScratch != NIL_RTR0MEMOBJ)
1972 ASMMemZero32(pVM->hm.s.vmx.pvScratch, PAGE_SIZE);
1973#endif
1974 hmR0VmxStructsFree(pVM);
1975 return VINF_SUCCESS;
1976}
1977
1978
1979/**
1980 * Sets up the VM for execution under VT-x.
1981 * This function is only called once per-VM during initalization.
1982 *
1983 * @returns VBox status code.
1984 * @param pVM Pointer to the VM.
1985 */
1986VMMR0DECL(int) VMXR0SetupVM(PVM pVM)
1987{
1988 AssertPtrReturn(pVM, VERR_INVALID_PARAMETER);
1989 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1990
1991 LogFlowFunc(("pVM=%p\n", pVM));
1992
1993 /*
1994 * Without UnrestrictedGuest, pRealModeTSS and pNonPagingModeEPTPageTable *must* always be allocated.
1995 * We no longer support the highly unlikely case of UnrestrictedGuest without pRealModeTSS. See hmR3InitFinalizeR0().
1996 */
1997 /* -XXX- change hmR3InitFinalizeR0Intel() to fail if pRealModeTSS alloc fails. */
1998 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
1999 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
2000 || !pVM->hm.s.vmx.pRealModeTSS))
2001 {
2002 LogRel(("VMXR0SetupVM: invalid real-on-v86 state.\n"));
2003 return VERR_INTERNAL_ERROR;
2004 }
2005
2006 /* Initialize these always, see hmR3InitFinalizeR0().*/
2007 pVM->hm.s.vmx.enmFlushEpt = VMX_FLUSH_EPT_NONE;
2008 pVM->hm.s.vmx.enmFlushVpid = VMX_FLUSH_VPID_NONE;
2009
2010 /* Setup the tagged-TLB flush handlers. */
2011 int rc = hmR0VmxSetupTaggedTlb(pVM);
2012 if (RT_FAILURE(rc))
2013 {
2014 LogRel(("VMXR0SetupVM: hmR0VmxSetupTaggedTlb failed! rc=%Rrc\n", rc));
2015 return rc;
2016 }
2017
2018 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2019 {
2020 PVMCPU pVCpu = &pVM->aCpus[i];
2021 AssertPtr(pVCpu);
2022 AssertPtr(pVCpu->hm.s.vmx.pvVmcs);
2023
2024 /* Set revision dword at the beginning of the VMCS structure. */
2025 *(uint32_t *)pVCpu->hm.s.vmx.pvVmcs = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.msr.vmx_basic_info);
2026
2027 /* Initialize our VMCS region in memory, set the VMCS launch state to "clear". */
2028 rc = VMXClearVMCS(pVCpu->hm.s.vmx.HCPhysVmcs);
2029 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVMCS failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2030 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2031
2032 /* Load this VMCS as the current VMCS. */
2033 rc = VMXActivateVMCS(pVCpu->hm.s.vmx.HCPhysVmcs);
2034 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXActivateVMCS failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2035 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2036
2037 rc = hmR0VmxSetupPinCtls(pVM, pVCpu);
2038 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupPinCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2039 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2040
2041 rc = hmR0VmxSetupProcCtls(pVM, pVCpu);
2042 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupProcCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2043 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2044
2045 rc = hmR0VmxSetupMiscCtls(pVM, pVCpu);
2046 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupMiscCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2047 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2048
2049 rc = hmR0VmxInitXcptBitmap(pVM, pVCpu);
2050 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitXcptBitmap failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2051 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2052
2053 rc = hmR0VmxInitUpdatedGuestStateMask(pVCpu);
2054 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitUpdatedGuestStateMask failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2055 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2056
2057#if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
2058 rc = hmR0VmxInitVmcsReadCache(pVM, pVCpu);
2059 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitVmcsReadCache failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2060 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2061#endif
2062
2063 /* Re-sync the CPU's internal data into our VMCS memory region & reset the launch state to "clear". */
2064 rc = VMXClearVMCS(pVCpu->hm.s.vmx.HCPhysVmcs);
2065 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVMCS(2) failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2066 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2067
2068 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc);
2069 }
2070
2071 return VINF_SUCCESS;
2072}
2073
2074
2075/**
2076 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
2077 * the VMCS.
2078 *
2079 * @returns VBox status code.
2080 * @param pVM Pointer to the VM.
2081 * @param pVCpu Pointer to the VMCPU.
2082 */
2083DECLINLINE(int) hmR0VmxSaveHostControlRegs(PVM pVM, PVMCPU pVCpu)
2084{
2085 RTCCUINTREG uReg = ASMGetCR0();
2086 int rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR0, uReg);
2087 AssertRCReturn(rc, rc);
2088
2089#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
2090 /* For the darwin 32-bit hybrid kernel, we need the 64-bit CR3 as it uses 64-bit paging. */
2091 if (HMVMX_IS_64BIT_HOST_MODE())
2092 {
2093 uint64_t uRegCR3 = HMR0Get64bitCR3();
2094 rc = VMXWriteVmcs64(VMX_VMCS_HOST_CR3, uRegCR3);
2095 }
2096 else
2097#endif
2098 {
2099 uReg = ASMGetCR3();
2100 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR3, uReg);
2101 }
2102 AssertRCReturn(rc, rc);
2103
2104 uReg = ASMGetCR4();
2105 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR4, uReg);
2106 AssertRCReturn(rc, rc);
2107 return rc;
2108}
2109
2110
2111/**
2112 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
2113 * the host-state area in the VMCS.
2114 *
2115 * @returns VBox status code.
2116 * @param pVM Pointer to the VM.
2117 * @param pVCpu Pointer to the VMCPU.
2118 */
2119DECLINLINE(int) hmR0VmxSaveHostSegmentRegs(PVM pVM, PVMCPU pVCpu)
2120{
2121 int rc = VERR_INTERNAL_ERROR_5;
2122 RTSEL uSelDS = 0;
2123 RTSEL uSelES = 0;
2124 RTSEL uSelFS = 0;
2125 RTSEL uSelGS = 0;
2126 RTSEL uSelTR = 0;
2127
2128 /*
2129 * Host DS, ES, FS and GS segment registers.
2130 */
2131#if HC_ARCH_BITS == 64
2132 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
2133 uSelDS = ASMGetDS();
2134 uSelES = ASMGetES();
2135 uSelFS = ASMGetFS();
2136 uSelGS = ASMGetGS();
2137#endif
2138
2139 /*
2140 * Host CS and SS segment registers.
2141 */
2142 RTSEL uSelCS;
2143 RTSEL uSelSS;
2144#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
2145 if (HMVMX_IS_64BIT_HOST_MODE())
2146 {
2147 uSelCS = (RTSEL)(uintptr_t)&SUPR0Abs64bitKernelCS;
2148 uSelSS = (RTSEL)(uintptr_t)&SUPR0Abs64bitKernelSS;
2149 }
2150 else
2151 {
2152 /* Seems darwin uses the LDT (TI flag is set) in the CS & SS selectors which VT-x doesn't like. */
2153 uSelCS = (RTSEL)(uintptr_t)&SUPR0AbsKernelCS;
2154 uSelSS = (RTSEL)(uintptr_t)&SUPR0AbsKernelSS;
2155 }
2156#else
2157 uSelCS = ASMGetCS();
2158 uSelSS = ASMGetSS();
2159#endif
2160
2161 /*
2162 * Host TR segment register.
2163 */
2164 uSelTR = ASMGetTR();
2165
2166#if HC_ARCH_BITS == 64
2167 /*
2168 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to gain VM-entry and restore them
2169 * before we get preempted. See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
2170 */
2171 if (uSelDS & (X86_SEL_RPL | X86_SEL_LDT))
2172 {
2173 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_DS;
2174 pVCpu->hm.s.vmx.RestoreHost.uHostSelDS = uSelDS;
2175 uSelDS = 0;
2176 }
2177 if (uSelES & (X86_SEL_RPL | X86_SEL_LDT))
2178 {
2179 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_ES;
2180 pVCpu->hm.s.vmx.RestoreHost.uHostSelES = uSelES;
2181 uSelES = 0;
2182 }
2183 if (uSelFS & (X86_SEL_RPL | X86_SEL_LDT))
2184 {
2185 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_FS;
2186 pVCpu->hm.s.vmx.RestoreHost.uHostSelFS = uSelFS;
2187 uSelFS = 0;
2188 }
2189 if (uSelGS & (X86_SEL_RPL | X86_SEL_LDT))
2190 {
2191 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_GS;
2192 pVCpu->hm.s.vmx.RestoreHost.uHostSelGS = uSelGS;
2193 uSelGS = 0;
2194 }
2195#endif
2196
2197 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
2198 Assert(!(uSelCS & X86_SEL_RPL)); Assert(!(uSelCS & X86_SEL_LDT));
2199 Assert(!(uSelSS & X86_SEL_RPL)); Assert(!(uSelSS & X86_SEL_LDT));
2200 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
2201 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
2202 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
2203 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
2204 Assert(!(uSelTR & X86_SEL_RPL)); Assert(!(uSelTR & X86_SEL_LDT));
2205 Assert(uSelCS);
2206 Assert(uSelTR);
2207
2208 /* Assertion is right but we would not have updated u32ExitCtls yet. */
2209#if 0
2210 if (!(pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE))
2211 Assert(uSelSS != 0);
2212#endif
2213
2214 /* Write these host selector fields into the host-state area in the VMCS. */
2215 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_FIELD_CS, uSelCS); AssertRCReturn(rc, rc);
2216 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_FIELD_SS, uSelSS); AssertRCReturn(rc, rc);
2217#if HC_ARCH_BITS == 64
2218 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_FIELD_DS, uSelDS); AssertRCReturn(rc, rc);
2219 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_FIELD_ES, uSelES); AssertRCReturn(rc, rc);
2220 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_FIELD_FS, uSelFS); AssertRCReturn(rc, rc);
2221 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_FIELD_GS, uSelGS); AssertRCReturn(rc, rc);
2222#endif
2223 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_FIELD_TR, uSelTR); AssertRCReturn(rc, rc);
2224
2225 /*
2226 * Host GDTR and IDTR.
2227 */
2228 RTGDTR Gdtr;
2229 RT_ZERO(Gdtr);
2230#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
2231 if (HMVMX_IS_64BIT_HOST_MODE())
2232 {
2233 X86XDTR64 Gdtr64;
2234 X86XDTR64 Idtr64;
2235 HMR0Get64bitGdtrAndIdtr(&Gdtr64, &Idtr64);
2236 rc = VMXWriteVmcs64(VMX_VMCS_HOST_GDTR_BASE, Gdtr64.uAddr); AssertRCReturn(rc, rc);
2237 rc = VMXWriteVmcs64(VMX_VMCS_HOST_IDTR_BASE, Idtr64.uAddr); AssertRCReturn(rc, rc);
2238
2239 Gdtr.cbGdt = Gdtr64.cb;
2240 Gdtr.pGdt = (uintptr_t)Gdtr64.uAddr;
2241 }
2242 else
2243#endif
2244 {
2245 RTIDTR Idtr;
2246 ASMGetGDTR(&Gdtr);
2247 ASMGetIDTR(&Idtr);
2248 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_GDTR_BASE, Gdtr.pGdt); AssertRCReturn(rc, rc);
2249 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_IDTR_BASE, Idtr.pIdt); AssertRCReturn(rc, rc);
2250
2251#if HC_ARCH_BITS == 64
2252 /*
2253 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps them to the
2254 * maximum limit (0xffff) on every VM-exit.
2255 */
2256 if (Gdtr.cbGdt != 0xffff)
2257 {
2258 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
2259 AssertCompile(sizeof(Gdtr) == sizeof(X86XDTR64));
2260 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
2261 }
2262
2263 /*
2264 * IDT limit is practically 0xfff. Therefore if the host has the limit as 0xfff, VT-x bloating the limit to 0xffff
2265 * is not a problem as it's not possible to get at them anyway. See Intel spec. 6.14.1 "64-Bit Mode IDT" and
2266 * Intel spec. 6.2 "Exception and Interrupt Vectors".
2267 */
2268 if (Idtr.cbIdt < 0x0fff)
2269 {
2270 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
2271 AssertCompile(sizeof(Idtr) == sizeof(X86XDTR64));
2272 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostIdtr, &Idtr, sizeof(X86XDTR64));
2273 }
2274#endif
2275 }
2276
2277 /*
2278 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI and RPL bits
2279 * is effectively what the CPU does for "scaling by 8". TI is always 0 and RPL should be too in most cases.
2280 */
2281 if ((uSelTR & X86_SEL_MASK) > Gdtr.cbGdt)
2282 {
2283 AssertMsgFailed(("hmR0VmxSaveHostSegmentRegs: TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, Gdtr.cbGdt));
2284 return VERR_VMX_INVALID_HOST_STATE;
2285 }
2286
2287 PCX86DESCHC pDesc = (PCX86DESCHC)(Gdtr.pGdt + (uSelTR & X86_SEL_MASK));
2288#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
2289 if (HMVMX_IS_64BIT_HOST_MODE())
2290 {
2291 /* We need the 64-bit TR base for hybrid darwin. */
2292 uint64_t u64TRBase = X86DESC64_BASE((PX86DESC64)pDesc);
2293 rc = VMXWriteVmcs64(VMX_VMCS_HOST_TR_BASE, u64TRBase);
2294 }
2295 else
2296#endif
2297 {
2298 uintptr_t uTRBase;
2299#if HC_ARCH_BITS == 64
2300 uTRBase = X86DESC64_BASE(pDesc);
2301#else
2302 uTRBase = X86DESC_BASE(pDesc);
2303#endif
2304 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_TR_BASE, uTRBase);
2305 }
2306 AssertRCReturn(rc, rc);
2307
2308 /*
2309 * Host FS base and GS base.
2310 */
2311#if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
2312 if (HMVMX_IS_64BIT_HOST_MODE())
2313 {
2314 uint64_t u64FSBase = ASMRdMsr(MSR_K8_FS_BASE);
2315 uint64_t u64GSBase = ASMRdMsr(MSR_K8_GS_BASE);
2316 rc = VMXWriteVmcs64(VMX_VMCS_HOST_FS_BASE, u64FSBase); AssertRCReturn(rc, rc);
2317 rc = VMXWriteVmcs64(VMX_VMCS_HOST_GS_BASE, u64GSBase); AssertRCReturn(rc, rc);
2318
2319# if HC_ARCH_BITS == 64
2320 /* Store the base if we have to restore FS or GS manually as we need to restore the base as well. */
2321 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_FS)
2322 pVCpu->hm.s.vmx.RestoreHost.uHostFSBase = u64FSBase;
2323 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_GS)
2324 pVCpu->hm.s.vmx.RestoreHost.uHostGSBase = u64GSBase;
2325# endif
2326 }
2327#endif
2328 return rc;
2329}
2330
2331
2332/**
2333 * Saves certain host MSRs in the VM-Exit MSR-load area and some in the
2334 * host-state area of the VMCS. Theses MSRs will be automatically restored on
2335 * the host after every successful VM exit.
2336 *
2337 * @returns VBox status code.
2338 * @param pVM Pointer to the VM.
2339 * @param pVCpu Pointer to the VMCPU.
2340 */
2341DECLINLINE(int) hmR0VmxSaveHostMsrs(PVM pVM, PVMCPU pVCpu)
2342{
2343 AssertPtr(pVCpu);
2344 AssertPtr(pVCpu->hm.s.vmx.pvHostMsr);
2345
2346 int rc = VINF_SUCCESS;
2347#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
2348 PVMXMSR pHostMsr = (PVMXMSR)pVCpu->hm.s.vmx.pvHostMsr;
2349 uint32_t cHostMsrs = 0;
2350 uint32_t u32HostExtFeatures = pVM->hm.s.cpuid.u32AMDFeatureEDX;
2351
2352 if (u32HostExtFeatures & (X86_CPUID_EXT_FEATURE_EDX_NX | X86_CPUID_EXT_FEATURE_EDX_LONG_MODE))
2353 {
2354 uint64_t u64HostEfer = ASMRdMsr(MSR_K6_EFER);
2355
2356# if HC_ARCH_BITS == 64
2357 /* Paranoia. 64-bit code requires these bits to be set always. */
2358 Assert((u64HostEfer & (MSR_K6_EFER_LMA | MSR_K6_EFER_LME)) == (MSR_K6_EFER_LMA | MSR_K6_EFER_LME));
2359
2360 /*
2361 * We currently do not save/restore host EFER, we just make sure it doesn't get modified by VT-x operation.
2362 * All guest accesses (read, write) on EFER cause VM-exits. If we are to conditionally load the guest EFER for
2363 * some reason (e.g. allow transparent reads) we would activate the code below.
2364 */
2365# if 0
2366 /* All our supported 64-bit host platforms must have NXE bit set. Otherwise we can change the below code to save EFER. */
2367 Assert(u64HostEfer & (MSR_K6_EFER_NXE));
2368 /* The SCE bit is only applicable in 64-bit mode. Save EFER if it doesn't match what the guest has.
2369 See Intel spec. 30.10.4.3 "Handling the SYSCALL and SYSRET Instructions". */
2370 if (CPUMIsGuestInLongMode(pVCpu))
2371 {
2372 uint64_t u64GuestEfer;
2373 rc = CPUMQueryGuestMsr(pVCpu, MSR_K6_EFER, &u64GuestEfer);
2374 AssertRC(rc);
2375
2376 if ((u64HostEfer & MSR_K6_EFER_SCE) != (u64GuestEfer & MSR_K6_EFER_SCE))
2377 {
2378 pHostMsr->u32IndexMSR = MSR_K6_EFER;
2379 pHostMsr->u32Reserved = 0;
2380 pHostMsr->u64Value = u64HostEfer;
2381 pHostMsr++; cHostMsrs++;
2382 }
2383 }
2384# endif
2385# else /* HC_ARCH_BITS != 64 */
2386 pHostMsr->u32IndexMSR = MSR_K6_EFER;
2387 pHostMsr->u32Reserved = 0;
2388# if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
2389 if (CPUMIsGuestInLongMode(pVCpu))
2390 {
2391 /* Must match the EFER value in our 64 bits switcher. */
2392 pHostMsr->u64Value = u64HostEfer | MSR_K6_EFER_LME | MSR_K6_EFER_SCE | MSR_K6_EFER_NXE;
2393 }
2394 else
2395# endif
2396 pHostMsr->u64Value = u64HostEfer;
2397 pHostMsr++; cHostMsrs++;
2398# endif /* HC_ARCH_BITS == 64 */
2399 }
2400
2401# if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
2402 if (HMVMX_IS_64BIT_HOST_MODE())
2403 {
2404 pHostMsr->u32IndexMSR = MSR_K6_STAR;
2405 pHostMsr->u32Reserved = 0;
2406 pHostMsr->u64Value = ASMRdMsr(MSR_K6_STAR); /* legacy syscall eip, cs & ss */
2407 pHostMsr++; cHostMsrs++;
2408 pHostMsr->u32IndexMSR = MSR_K8_LSTAR;
2409 pHostMsr->u32Reserved = 0;
2410 pHostMsr->u64Value = ASMRdMsr(MSR_K8_LSTAR); /* 64-bit mode syscall rip */
2411 pHostMsr++; cHostMsrs++;
2412 pHostMsr->u32IndexMSR = MSR_K8_SF_MASK;
2413 pHostMsr->u32Reserved = 0;
2414 pHostMsr->u64Value = ASMRdMsr(MSR_K8_SF_MASK); /* syscall flag mask */
2415 pHostMsr++; cHostMsrs++;
2416 pHostMsr->u32IndexMSR = MSR_K8_KERNEL_GS_BASE;
2417 pHostMsr->u32Reserved = 0;
2418 pHostMsr->u64Value = ASMRdMsr(MSR_K8_KERNEL_GS_BASE); /* swapgs exchange value */
2419 pHostMsr++; cHostMsrs++;
2420 }
2421# endif
2422
2423 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
2424 if (RT_UNLIKELY(cHostMsrs > MSR_IA32_VMX_MISC_MAX_MSR(pVM->hm.s.vmx.msr.vmx_misc)))
2425 {
2426 LogRel(("cHostMsrs=%u Cpu=%u\n", cHostMsrs, (unsigned)MSR_IA32_VMX_MISC_MAX_MSR(pVM->hm.s.vmx.msr.vmx_misc)));
2427 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2428 }
2429
2430 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cHostMsrs);
2431#endif /* VBOX_WITH_AUTO_MSR_LOAD_RESTORE */
2432
2433 /*
2434 * Host Sysenter MSRs.
2435 */
2436 rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS));
2437 AssertRCReturn(rc, rc);
2438#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
2439 if (HMVMX_IS_64BIT_HOST_MODE())
2440 {
2441 rc = VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP));
2442 AssertRCReturn(rc, rc);
2443 rc = VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP));
2444 }
2445 else
2446 {
2447 rc = VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP));
2448 AssertRCReturn(rc, rc);
2449 rc = VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP));
2450 }
2451#elif HC_ARCH_BITS == 32
2452 rc = VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP));
2453 AssertRCReturn(rc, rc);
2454 rc = VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP));
2455#else
2456 rc = VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP));
2457 AssertRCReturn(rc, rc);
2458 rc = VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP));
2459#endif
2460 AssertRCReturn(rc, rc);
2461
2462 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT, IA32_EFER, also see
2463 * hmR0VmxSetupExitCtls() !! */
2464 return rc;
2465}
2466
2467
2468/**
2469 * Sets up VM-entry controls in the VMCS. These controls can affect things done
2470 * on VM-exit; e.g. "load debug controls", see Intel spec. 24.8.1 "VM-entry
2471 * controls".
2472 *
2473 * @returns VBox status code.
2474 * @param pVCpu Pointer to the VMCPU.
2475 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
2476 * out-of-sync. Make sure to update the required fields
2477 * before using them.
2478 *
2479 * @remarks No-long-jump zone!!!
2480 */
2481DECLINLINE(int) hmR0VmxLoadGuestEntryCtls(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
2482{
2483 int rc = VINF_SUCCESS;
2484 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_VMX_ENTRY_CTLS)
2485 {
2486 PVM pVM = pVCpu->CTX_SUFF(pVM);
2487 uint32_t val = pVM->hm.s.vmx.msr.vmx_entry.n.disallowed0; /* Bits set here must be set in the VMCS. */
2488 uint32_t zap = pVM->hm.s.vmx.msr.vmx_entry.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2489
2490 /* Load debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x capable CPUs only supports the 1-setting of this bit. */
2491 val |= VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG;
2492
2493 /* Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry. */
2494 if (CPUMIsGuestInLongModeEx(pMixedCtx))
2495 val |= VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST;
2496 else
2497 Assert(!(val & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST));
2498
2499 /*
2500 * The following should not be set (since we're not in SMM mode):
2501 * - VMX_VMCS_CTRL_ENTRY_ENTRY_SMM
2502 * - VMX_VMCS_CTRL_ENTRY_DEACTIVATE_DUALMON
2503 */
2504
2505 /** @todo VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PERF_MSR,
2506 * VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PAT_MSR,
2507 * VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR */
2508
2509 if ((val & zap) != val)
2510 {
2511 LogRel(("hmR0VmxLoadGuestEntryCtls: invalid VM-entry controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
2512 pVM->hm.s.vmx.msr.vmx_entry.n.disallowed0, val, zap));
2513 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2514 }
2515
2516 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, val);
2517 AssertRCReturn(rc, rc);
2518
2519 /* Update VCPU with the currently set VM-exit controls. */
2520 pVCpu->hm.s.vmx.u32EntryCtls = val;
2521 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_VMX_ENTRY_CTLS;
2522 }
2523 return rc;
2524}
2525
2526
2527/**
2528 * Sets up the VM-exit controls in the VMCS.
2529 *
2530 * @returns VBox status code.
2531 * @param pVM Pointer to the VM.
2532 * @param pVCpu Pointer to the VMCPU.
2533 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
2534 * out-of-sync. Make sure to update the required fields
2535 * before using them.
2536 *
2537 * @remarks requires EFER.
2538 */
2539DECLINLINE(int) hmR0VmxLoadGuestExitCtls(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
2540{
2541 int rc = VINF_SUCCESS;
2542 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_VMX_EXIT_CTLS)
2543 {
2544 PVM pVM = pVCpu->CTX_SUFF(pVM);
2545 uint32_t val = pVM->hm.s.vmx.msr.vmx_exit.n.disallowed0; /* Bits set here must be set in the VMCS. */
2546 uint32_t zap = pVM->hm.s.vmx.msr.vmx_exit.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2547
2548 /* Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only supported the 1-setting of this bit. */
2549 val |= VMX_VMCS_CTRL_EXIT_SAVE_DEBUG;
2550
2551 /*
2552 * Set the host long mode active (EFER.LMA) bit (which Intel calls "Host address-space size") if necessary.
2553 * On VM-exit, VT-x sets both the host EFER.LMA and EFER.LME bit to this value. See assertion in hmR0VmxSaveHostMsrs().
2554 */
2555#if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
2556 if (HMVMX_IS_64BIT_HOST_MODE())
2557 val |= VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE;
2558 else
2559 Assert(!(val & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE));
2560#elif HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
2561 if (CPUMIsGuestInLongModeEx(pMixedCtx))
2562 val |= VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE; /* The switcher goes to long mode. */
2563 else
2564 Assert(!(val & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE));
2565#endif
2566
2567 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
2568 Assert(!(val & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT));
2569
2570 /** @todo VMX_VMCS_CTRL_EXIT_LOAD_PERF_MSR,
2571 * VMX_VMCS_CTRL_EXIT_SAVE_GUEST_PAT_MSR,
2572 * VMX_VMCS_CTRL_EXIT_LOAD_HOST_PAT_MSR,
2573 * VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR,
2574 * VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR. */
2575
2576 if (pVM->hm.s.vmx.msr.vmx_exit.n.allowed1 & VMX_VMCS_CTRL_EXIT_SAVE_VMX_PREEMPT_TIMER)
2577 val |= VMX_VMCS_CTRL_EXIT_SAVE_VMX_PREEMPT_TIMER;
2578
2579 if ((val & zap) != val)
2580 {
2581 LogRel(("hmR0VmxSetupProcCtls: invalid VM-exit controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
2582 pVM->hm.s.vmx.msr.vmx_exit.n.disallowed0, val, zap));
2583 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2584 }
2585
2586 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, val);
2587 AssertRCReturn(rc, rc);
2588
2589 /* Update VCPU with the currently set VM-exit controls. */
2590 pVCpu->hm.s.vmx.u32ExitCtls = val;
2591 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_VMX_EXIT_CTLS;
2592 }
2593 return rc;
2594}
2595
2596
2597/**
2598 * Loads the guest APIC and related state.
2599 *
2600 * @returns VBox status code.
2601 * @param pVM Pointer to the VM.
2602 * @param pVCpu Pointer to the VMCPU.
2603 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
2604 * out-of-sync. Make sure to update the required fields
2605 * before using them.
2606 */
2607DECLINLINE(int) hmR0VmxLoadGuestApicState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
2608{
2609 int rc = VINF_SUCCESS;
2610 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_VMX_GUEST_APIC_STATE)
2611 {
2612 /* Setup TPR shadowing. Also setup TPR patching for 32-bit guests. */
2613 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
2614 {
2615 Assert(pVCpu->hm.s.vmx.HCPhysVirtApic);
2616
2617 bool fPendingIntr = false;
2618 uint8_t u8Tpr = 0;
2619 uint8_t u8PendingIntr = 0;
2620 rc = PDMApicGetTPR(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
2621 AssertRCReturn(rc, rc);
2622
2623 /*
2624 * If there are external interrupts pending but masked by the TPR value, instruct VT-x to cause a VM-exit when
2625 * the guest lowers its TPR below the highest-priority pending interrupt and we can deliver the interrupt.
2626 * If there are no external interrupts pending, set threshold to 0 to not cause a VM-exit. We will eventually deliver
2627 * the interrupt when we VM-exit for other reasons.
2628 */
2629 pVCpu->hm.s.vmx.pbVirtApic[0x80] = u8Tpr; /* Offset 0x80 is TPR in the APIC MMIO range. */
2630 uint32_t u32TprThreshold = 0;
2631 if (fPendingIntr)
2632 {
2633 /* Bits 3-0 of the TPR threshold field correspond to bits 7-4 of the TPR (which is the Task-Priority Class). */
2634 const uint8_t u8PendingPriority = (u8PendingIntr >> 4);
2635 const uint8_t u8TprPriority = (u8Tpr >> 4) & 7;
2636 if (u8PendingPriority <= u8TprPriority)
2637 u32TprThreshold = u8PendingPriority;
2638 else
2639 u32TprThreshold = u8TprPriority; /* Required for Vista 64-bit guest, see @bugref{6398}. */
2640 }
2641 Assert(!(u32TprThreshold & 0xfffffff0)); /* Bits 31:4 MBZ. */
2642
2643 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
2644 AssertRCReturn(rc, rc);
2645
2646 /* 32-bit guests uses LSTAR MSR for patching guest code which touches the TPR. */
2647 if (pVCpu->CTX_SUFF(pVM)->hm.s.fTPRPatchingActive)
2648 {
2649 Assert(!CPUMIsGuestInLongModeEx(pMixedCtx)); /* EFER always up-to-date. */
2650 pMixedCtx->msrLSTAR = u8Tpr;
2651 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
2652 {
2653 /* If there are interrupts pending, intercept CR8 writes, otherwise don't intercept CR8 reads or writes. */
2654 if (fPendingIntr)
2655 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_LSTAR, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_INTERCEPT_WRITE);
2656 else
2657 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_LSTAR, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2658 }
2659 }
2660 }
2661
2662 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_VMX_GUEST_APIC_STATE;
2663 }
2664 return rc;
2665}
2666
2667
2668/**
2669 * Gets the guest's interruptibility-state ("interrupt shadow" as AMD calls it).
2670 *
2671 * @returns
2672 * @param pVCpu Pointer to the VMCPU.
2673 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
2674 * out-of-sync. Make sure to update the required fields
2675 * before using them.
2676 *
2677 * @remarks No-long-jump zone!!!
2678 * @remarks Has side-effects with VMCPU_FF_INHIBIT_INTERRUPTS force-flag.
2679 */
2680DECLINLINE(uint32_t) hmR0VmxGetGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
2681{
2682 /*
2683 * Instructions like STI and MOV SS inhibit interrupts till the next instruction completes. Check if we should
2684 * inhibit interrupts or clear any existing interrupt-inhibition.
2685 */
2686 uint32_t uIntrState = 0;
2687 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
2688 {
2689 /* If inhibition is active, RIP & RFLAGS should've been accessed (i.e. read previously from the VMCS or from ring-3). */
2690 AssertMsg((pVCpu->hm.s.vmx.fUpdatedGuestState & (HMVMX_UPDATED_GUEST_RIP | HMVMX_UPDATED_GUEST_RFLAGS))
2691 == (HMVMX_UPDATED_GUEST_RIP | HMVMX_UPDATED_GUEST_RFLAGS), ("%#x\n", pVCpu->hm.s.vmx.fUpdatedGuestState));
2692 if (pMixedCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
2693 {
2694 /*
2695 * We can clear the inhibit force flag as even if we go back to the recompiler without executing guest code in
2696 * VT-x the flag's condition to be cleared is met and thus the cleared state is correct.
2697 */
2698 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
2699 }
2700 else if (pMixedCtx->eflags.Bits.u1IF)
2701 uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
2702 else
2703 uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS;
2704 }
2705 return uIntrState;
2706}
2707
2708
2709/**
2710 * Loads the guest's interruptibility-state into the guest-state area in the
2711 * VMCS.
2712 *
2713 * @returns VBox status code.
2714 * @param pVCpu Pointer to the VMCPU.
2715 * @param uIntrState The interruptibility-state to set.
2716 */
2717static int hmR0VmxLoadGuestIntrState(PVMCPU pVCpu, uint32_t uIntrState)
2718{
2719 AssertMsg(!(uIntrState & 0xfffffff0), ("%#x\n", uIntrState)); /* Bits 31:4 MBZ. */
2720 Assert((uIntrState & 0x3) != 0x3); /* Block-by-STI and MOV SS cannot be simultaneously set. */
2721 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, uIntrState);
2722 AssertRCReturn(rc, rc);
2723 return rc;
2724}
2725
2726
2727/**
2728 * Loads the guest's RIP into the guest-state area in the VMCS.
2729 *
2730 * @returns VBox status code.
2731 * @param pVCpu Pointer to the VMCPU.
2732 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
2733 * out-of-sync. Make sure to update the required fields
2734 * before using them.
2735 *
2736 * @remarks No-long-jump zone!!!
2737 */
2738static int hmR0VmxLoadGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
2739{
2740 int rc = VINF_SUCCESS;
2741 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_RIP)
2742 {
2743 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_RIP, pMixedCtx->rip);
2744 AssertRCReturn(rc, rc);
2745 Log4(("Load: VMX_VMCS_GUEST_RIP=%#RX64\n", pMixedCtx->rip));
2746 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_RIP;
2747 }
2748 return rc;
2749}
2750
2751
2752/**
2753 * Loads the guest's RSP into the guest-state area in the VMCS.
2754 *
2755 * @returns VBox status code.
2756 * @param pVCpu Pointer to the VMCPU.
2757 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
2758 * out-of-sync. Make sure to update the required fields
2759 * before using them.
2760 *
2761 * @remarks No-long-jump zone!!!
2762 */
2763static int hmR0VmxLoadGuestRsp(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
2764{
2765 int rc = VINF_SUCCESS;
2766 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_RSP)
2767 {
2768 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_RSP, pMixedCtx->rsp);
2769 AssertRCReturn(rc, rc);
2770 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_RSP;
2771 }
2772 return rc;
2773}
2774
2775
2776/**
2777 * Loads the guest's RFLAGS into the guest-state area in the VMCS.
2778 *
2779 * @returns VBox status code.
2780 * @param pVCpu Pointer to the VMCPU.
2781 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
2782 * out-of-sync. Make sure to update the required fields
2783 * before using them.
2784 *
2785 * @remarks No-long-jump zone!!!
2786 */
2787static int hmR0VmxLoadGuestRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
2788{
2789 int rc = VINF_SUCCESS;
2790 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_RFLAGS)
2791 {
2792 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
2793 Let us assert it as such and use 32-bit VMWRITE. */
2794 Assert(!(pMixedCtx->rflags.u64 >> 32));
2795 X86EFLAGS uEFlags = pMixedCtx->eflags;
2796 uEFlags.u32 &= VMX_EFLAGS_RESERVED_0; /* Bits 22-31, 15, 5 & 3 MBZ. */
2797 uEFlags.u32 |= VMX_EFLAGS_RESERVED_1; /* Bit 1 MB1. */
2798
2799 /*
2800 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so we can restore them on VM exit.
2801 * Modify the real-mode guest's eflags so that VT-x can run the real-mode guest code under Virtual 8086 mode.
2802 */
2803 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
2804 {
2805 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
2806 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
2807 pVCpu->hm.s.vmx.RealMode.eflags.u32 = uEFlags.u32; /* Save the original eflags of the real-mode guest. */
2808 uEFlags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
2809 uEFlags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
2810 }
2811
2812 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_RFLAGS, uEFlags.u32);
2813 AssertRCReturn(rc, rc);
2814
2815 Log4(("Load: VMX_VMCS_GUEST_RFLAGS=%#RX32\n", uEFlags.u32));
2816 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_RFLAGS;
2817 }
2818 return rc;
2819}
2820
2821
2822/**
2823 * Loads the guest RIP, RSP and RFLAGS into the guest-state area in the VMCS.
2824 *
2825 * @returns VBox status code.
2826 * @param pVCpu Pointer to the VMCPU.
2827 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
2828 * out-of-sync. Make sure to update the required fields
2829 * before using them.
2830 *
2831 * @remarks No-long-jump zone!!!
2832 */
2833DECLINLINE(int) hmR0VmxLoadGuestRipRspRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
2834{
2835 int rc = hmR0VmxLoadGuestRip(pVCpu, pMixedCtx);
2836 AssertRCReturn(rc, rc);
2837 rc = hmR0VmxLoadGuestRsp(pVCpu, pMixedCtx);
2838 AssertRCReturn(rc, rc);
2839 rc = hmR0VmxLoadGuestRflags(pVCpu, pMixedCtx);
2840 AssertRCReturn(rc, rc);
2841 return rc;
2842}
2843
2844
2845/**
2846 * Loads the guest control registers (CR0, CR3, CR4) into the guest-state area
2847 * in the VMCS.
2848 *
2849 * @returns VBox status code.
2850 * @param pVM Pointer to the VM.
2851 * @param pVCpu Pointer to the VMCPU.
2852 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
2853 * out-of-sync. Make sure to update the required fields
2854 * before using them.
2855 *
2856 * @remarks No-long-jump zone!!!
2857 */
2858static int hmR0VmxLoadGuestControlRegs(PVMCPU pVCpu, PCPUMCTX pCtx)
2859{
2860 int rc = VINF_SUCCESS;
2861 PVM pVM = pVCpu->CTX_SUFF(pVM);
2862
2863 /*
2864 * Guest CR0.
2865 * Guest FPU.
2866 */
2867 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_CR0)
2868 {
2869 Assert(!(pCtx->cr0 >> 32));
2870 uint32_t u32GuestCR0 = pCtx->cr0;
2871
2872 /* The guest's view (read access) of its CR0 is unblemished. */
2873 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_READ_SHADOW, u32GuestCR0);
2874 AssertRCReturn(rc, rc);
2875 Log4(("Load: VMX_VMCS_CTRL_CR0_READ_SHADOW=%#RX32\n", u32GuestCR0));
2876
2877 /* Setup VT-x's view of the guest CR0. */
2878 /* Minimize VM-exits due to CR3 changes when we have NestedPaging. */
2879 if (pVM->hm.s.fNestedPaging)
2880 {
2881 if (CPUMIsGuestPagingEnabledEx(pCtx))
2882 {
2883 /* The guest has paging enabled, let it access CR3 without causing a VM exit if supported. */
2884 pVCpu->hm.s.vmx.u32ProcCtls &= ~( VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
2885 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT);
2886 }
2887 else
2888 {
2889 /* The guest doesn't have paging enabled, make CR3 access to cause VM exits to update our shadow. */
2890 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
2891 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
2892 }
2893
2894 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
2895 if (pVM->hm.s.vmx.fUnrestrictedGuest)
2896 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
2897
2898 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
2899 AssertRCReturn(rc, rc);
2900 }
2901 else
2902 u32GuestCR0 |= X86_CR0_WP; /* Guest CPL 0 writes to its read-only pages should cause a VM-exit. */
2903
2904 /*
2905 * Guest FPU bits.
2906 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be set on the first
2907 * CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
2908 */
2909 u32GuestCR0 |= X86_CR0_NE;
2910 bool fInterceptNM = false;
2911 if (CPUMIsGuestFPUStateActive(pVCpu))
2912 {
2913 fInterceptNM = false; /* Guest FPU active, no need to VM-exit on #NM. */
2914 /* The guest should still get #NM exceptions when it expects it to, so we should not clear TS & MP bits here.
2915 We're only concerned about -us- not intercepting #NMs when the guest-FPU is active. Not the guest itself! */
2916 }
2917 else
2918 {
2919 fInterceptNM = true; /* Guest FPU inactive, VM-exit on #NM for lazy FPU loading. */
2920 u32GuestCR0 |= X86_CR0_TS /* Guest can task switch quickly and do lazy FPU syncing. */
2921 | X86_CR0_MP; /* FWAIT/WAIT should not ignore CR0.TS and should generate #NM. */
2922 }
2923
2924 /* Catch floating point exceptions if we need to report them to the guest in a different way. */
2925 bool fInterceptMF = false;
2926 if (!(pCtx->cr0 & X86_CR0_NE))
2927 fInterceptMF = true;
2928
2929 /* Finally, intercept all exceptions as we cannot directly inject them in real-mode, see hmR0VmxInjectEventVmcs(). */
2930 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
2931 {
2932 Assert(PDMVmmDevHeapIsEnabled(pVM));
2933 Assert(pVM->hm.s.vmx.pRealModeTSS);
2934 pVCpu->hm.s.vmx.u32XcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
2935 fInterceptNM = true;
2936 fInterceptMF = true;
2937 }
2938 else
2939 pVCpu->hm.s.vmx.u32XcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
2940
2941 if (fInterceptNM)
2942 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_NM);
2943 else
2944 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_NM);
2945
2946 if (fInterceptMF)
2947 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_MF);
2948 else
2949 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_MF);
2950
2951 /* Additional intercepts for debugging, define these yourself explicitly. */
2952#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
2953 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_BP)
2954 | RT_BIT(X86_XCPT_DB)
2955 | RT_BIT(X86_XCPT_DE)
2956 | RT_BIT(X86_XCPT_NM)
2957 | RT_BIT(X86_XCPT_UD)
2958 | RT_BIT(X86_XCPT_NP)
2959 | RT_BIT(X86_XCPT_SS)
2960 | RT_BIT(X86_XCPT_GP)
2961 | RT_BIT(X86_XCPT_PF)
2962 | RT_BIT(X86_XCPT_MF);
2963#elif defined(HMVMX_ALWAYS_TRAP_PF)
2964 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_PF);
2965#endif
2966
2967 Assert(pVM->hm.s.fNestedPaging || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_PF)));
2968
2969 /* Set/clear the CR0 specific bits along with their exceptions (PE, PG, CD, NW). */
2970 uint32_t uSetCR0 = (uint32_t)(pVM->hm.s.vmx.msr.vmx_cr0_fixed0 & pVM->hm.s.vmx.msr.vmx_cr0_fixed1);
2971 uint32_t uZapCR0 = (uint32_t)(pVM->hm.s.vmx.msr.vmx_cr0_fixed0 | pVM->hm.s.vmx.msr.vmx_cr0_fixed1);
2972 if (pVM->hm.s.vmx.fUnrestrictedGuest) /* Exceptions for unrestricted-guests for fixed CR0 bits (PE, PG). */
2973 uSetCR0 &= ~(X86_CR0_PE | X86_CR0_PG);
2974 else
2975 Assert((uSetCR0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
2976
2977 u32GuestCR0 |= uSetCR0;
2978 u32GuestCR0 &= uZapCR0;
2979 u32GuestCR0 &= ~(X86_CR0_CD | X86_CR0_NW); /* Always enable caching. */
2980
2981 /* Write VT-x's view of the guest CR0 into the VMCS and update the exception bitmap. */
2982 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_CR0, u32GuestCR0);
2983 AssertRCReturn(rc, rc);
2984 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
2985 AssertRCReturn(rc, rc);
2986 Log4(("Load: VMX_VMCS_GUEST_CR0=%#RX32 (uSetCR0=%#RX32 uZapCR0=%#RX32)\n", u32GuestCR0, uSetCR0, uZapCR0));
2987
2988 /*
2989 * CR0 is shared between host and guest along with a CR0 read shadow. Therefore, certain bits must not be changed
2990 * by the guest because VT-x ignores saving/restoring them (namely CD, ET, NW) and for certain other bits
2991 * we want to be notified immediately of guest CR0 changes (e.g. PG to update our shadow page tables).
2992 */
2993 uint32_t u32CR0Mask = 0;
2994 u32CR0Mask = X86_CR0_PE
2995 | X86_CR0_NE
2996 | X86_CR0_WP
2997 | X86_CR0_PG
2998 | X86_CR0_ET /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.ET */
2999 | X86_CR0_CD /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.CD */
3000 | X86_CR0_NW; /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.NW */
3001 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3002 u32CR0Mask &= ~X86_CR0_PE;
3003 if (pVM->hm.s.fNestedPaging)
3004 u32CR0Mask &= ~X86_CR0_WP;
3005
3006 /* If the guest FPU state is active, don't need to VM-exit on writes to FPU related bits in CR0. */
3007 if (fInterceptNM)
3008 u32CR0Mask |= (X86_CR0_TS | X86_CR0_MP);
3009 else
3010 u32CR0Mask &= ~(X86_CR0_TS | X86_CR0_MP);
3011
3012 /* Write the CR0 mask into the VMCS and update the VCPU's copy of the current CR0 mask. */
3013 pVCpu->hm.s.vmx.u32CR0Mask = u32CR0Mask;
3014 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_MASK, u32CR0Mask);
3015 AssertRCReturn(rc, rc);
3016
3017 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_CR0;
3018 }
3019
3020 /*
3021 * Guest CR2.
3022 * It's always loaded in the assembler code. Nothing to do here.
3023 */
3024
3025 /*
3026 * Guest CR3.
3027 */
3028 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_CR3)
3029 {
3030 RTGCPHYS GCPhysGuestCR3 = NIL_RTGCPHYS;
3031 if (pVM->hm.s.fNestedPaging)
3032 {
3033 pVCpu->hm.s.vmx.HCPhysEPTP = PGMGetHyperCR3(pVCpu);
3034
3035 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
3036 Assert(pVCpu->hm.s.vmx.HCPhysEPTP);
3037 Assert(!(pVCpu->hm.s.vmx.HCPhysEPTP & UINT64_C(0xfff0000000000000)));
3038 Assert(!(pVCpu->hm.s.vmx.HCPhysEPTP & 0xfff));
3039
3040 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
3041 pVCpu->hm.s.vmx.HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
3042 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
3043
3044 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
3045 AssertMsg( ((pVCpu->hm.s.vmx.HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
3046 && ((pVCpu->hm.s.vmx.HCPhysEPTP >> 6) & 0x3f) == 0, /* Bits 6:11 MBZ. */
3047 ("EPTP %#RX64\n", pVCpu->hm.s.vmx.HCPhysEPTP));
3048
3049 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVCpu->hm.s.vmx.HCPhysEPTP);
3050 AssertRCReturn(rc, rc);
3051 Log4(("Load: VMX_VMCS64_CTRL_EPTP_FULL=%#RX64\n", pVCpu->hm.s.vmx.HCPhysEPTP));
3052
3053 if ( pVM->hm.s.vmx.fUnrestrictedGuest
3054 || CPUMIsGuestPagingEnabledEx(pCtx))
3055 {
3056 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
3057 if (CPUMIsGuestInPAEModeEx(pCtx))
3058 {
3059 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]); AssertRCReturn(rc, rc);
3060 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u); AssertRCReturn(rc, rc);
3061 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u); AssertRCReturn(rc, rc);
3062 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u); AssertRCReturn(rc, rc);
3063 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u); AssertRCReturn(rc, rc);
3064 }
3065
3066 /* The guest's view of its CR3 is unblemished with Nested Paging when the guest is using paging or we
3067 have Unrestricted Execution to handle the guest when it's not using paging. */
3068 GCPhysGuestCR3 = pCtx->cr3;
3069 }
3070 else
3071 {
3072 /*
3073 * The guest is not using paging, but the CPU (VT-x) has to. While the guest thinks it accesses physical memory
3074 * directly, we use our identity-mapped page table to map guest-linear to guest-physical addresses.
3075 * EPT takes care of translating it to host-physical addresses.
3076 */
3077 RTGCPHYS GCPhys;
3078 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
3079 Assert(PDMVmmDevHeapIsEnabled(pVM));
3080
3081 /* We obtain it here every time as the guest could have relocated this PCI region. */
3082 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
3083 AssertRCReturn(rc, rc);
3084
3085 GCPhysGuestCR3 = GCPhys;
3086 }
3087
3088 Log4(("Load: VMX_VMCS_GUEST_CR3=%#RGv (GstN)\n", GCPhysGuestCR3));
3089 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_CR3, GCPhysGuestCR3);
3090 }
3091 else
3092 {
3093 /* Non-nested paging case, just use the hypervisor's CR3. */
3094 RTHCPHYS HCPhysGuestCR3 = PGMGetHyperCR3(pVCpu);
3095
3096 Log4(("Load: VMX_VMCS_GUEST_CR3=%#RHv (HstN)\n", HCPhysGuestCR3));
3097 rc = VMXWriteVmcsHstN(VMX_VMCS_GUEST_CR3, HCPhysGuestCR3);
3098 }
3099 AssertRCReturn(rc, rc);
3100
3101 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_CR3;
3102 }
3103
3104 /*
3105 * Guest CR4.
3106 */
3107 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_CR4)
3108 {
3109 Assert(!(pCtx->cr4 >> 32));
3110 uint32_t u32GuestCR4 = pCtx->cr4;
3111
3112 /* The guest's view of its CR4 is unblemished. */
3113 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_READ_SHADOW, u32GuestCR4);
3114 AssertRCReturn(rc, rc);
3115 Log4(("Load: VMX_VMCS_CTRL_CR4_READ_SHADOW=%#RX32\n", u32GuestCR4));
3116
3117 /* Setup VT-x's view of the guest CR4. */
3118 /*
3119 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software interrupts to the 8086 program
3120 * interrupt handler. Clear the VME bit (the interrupt redirection bitmap is already all 0, see hmR3InitFinalizeR0())
3121 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
3122 */
3123 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3124 {
3125 Assert(pVM->hm.s.vmx.pRealModeTSS);
3126 Assert(PDMVmmDevHeapIsEnabled(pVM));
3127 u32GuestCR4 &= ~X86_CR4_VME;
3128 }
3129
3130 if (pVM->hm.s.fNestedPaging)
3131 {
3132 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
3133 && !pVM->hm.s.vmx.fUnrestrictedGuest)
3134 {
3135 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
3136 u32GuestCR4 |= X86_CR4_PSE;
3137 /* Our identity mapping is a 32 bits page directory. */
3138 u32GuestCR4 &= ~X86_CR4_PAE;
3139 }
3140 /* else use guest CR4.*/
3141 }
3142 else
3143 {
3144 /*
3145 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
3146 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
3147 */
3148 switch (pVCpu->hm.s.enmShadowMode)
3149 {
3150 case PGMMODE_REAL: /* Real-mode. */
3151 case PGMMODE_PROTECTED: /* Protected mode without paging. */
3152 case PGMMODE_32_BIT: /* 32-bit paging. */
3153 {
3154 u32GuestCR4 &= ~X86_CR4_PAE;
3155 break;
3156 }
3157
3158 case PGMMODE_PAE: /* PAE paging. */
3159 case PGMMODE_PAE_NX: /* PAE paging with NX. */
3160 {
3161 u32GuestCR4 |= X86_CR4_PAE;
3162 break;
3163 }
3164
3165 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
3166 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
3167#ifdef VBOX_ENABLE_64_BITS_GUESTS
3168 break;
3169#endif
3170 default:
3171 AssertFailed();
3172 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
3173 }
3174 }
3175
3176 /* We need to set and clear the CR4 specific bits here (mainly the X86_CR4_VMXE bit). */
3177 uint64_t uSetCR4 = (pVM->hm.s.vmx.msr.vmx_cr4_fixed0 & pVM->hm.s.vmx.msr.vmx_cr4_fixed1);
3178 uint64_t uZapCR4 = (pVM->hm.s.vmx.msr.vmx_cr4_fixed0 | pVM->hm.s.vmx.msr.vmx_cr4_fixed1);
3179 u32GuestCR4 |= uSetCR4;
3180 u32GuestCR4 &= uZapCR4;
3181
3182 /* Write VT-x's view of the guest CR4 into the VMCS. */
3183 Log4(("Load: VMX_VMCS_GUEST_CR4=%#RX32 (Set=%#RX32 Zap=%#RX32)\n", u32GuestCR4, uSetCR4, uZapCR4));
3184 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_CR4, u32GuestCR4);
3185 AssertRCReturn(rc, rc);
3186
3187 /* Setup CR4 mask. CR4 flags owned by the host, if the guest attempts to change them, that would cause a VM exit. */
3188 uint32_t u32CR4Mask = 0;
3189 u32CR4Mask = X86_CR4_VME
3190 | X86_CR4_PAE
3191 | X86_CR4_PGE
3192 | X86_CR4_PSE
3193 | X86_CR4_VMXE;
3194 pVCpu->hm.s.vmx.u32CR4Mask = u32CR4Mask;
3195 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_MASK, u32CR4Mask);
3196 AssertRCReturn(rc, rc);
3197
3198 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_CR4;
3199 }
3200 return rc;
3201}
3202
3203
3204/**
3205 * Loads the guest debug registers into the guest-state area in the VMCS.
3206 * This also sets up whether #DB and MOV DRx accesses cause VM exits.
3207 *
3208 * @returns VBox status code.
3209 * @param pVCpu Pointer to the VMCPU.
3210 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3211 * out-of-sync. Make sure to update the required fields
3212 * before using them.
3213 *
3214 * @remarks No-long-jump zone!!!
3215 */
3216static int hmR0VmxLoadGuestDebugRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3217{
3218 if (!(pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_DEBUG))
3219 return VINF_SUCCESS;
3220
3221#ifdef VBOX_STRICT
3222 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
3223 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
3224 {
3225 Assert(!(pMixedCtx->dr[7] >> 32)); /* upper 32 bits are reserved (MBZ). */
3226 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
3227 Assert((pMixedCtx->dr[7] & 0xd800) == 0); /* bits 15, 14, 12, 11 are reserved (MBZ). */
3228 Assert((pMixedCtx->dr[7] & 0x400) == 0x400); /* bit 10 is reserved (MB1). */
3229 }
3230#endif
3231
3232 int rc = VERR_INTERNAL_ERROR_5;
3233 PVM pVM = pVCpu->CTX_SUFF(pVM);
3234 bool fInterceptDB = false;
3235 bool fInterceptMovDRx = false;
3236 if (DBGFIsStepping(pVCpu))
3237 {
3238 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
3239 if (pVM->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG)
3240 {
3241 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG;
3242 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
3243 AssertRCReturn(rc, rc);
3244 Assert(fInterceptDB == false);
3245 }
3246 else
3247 {
3248 fInterceptDB = true;
3249 pMixedCtx->eflags.u32 |= X86_EFL_TF;
3250 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RFLAGS;
3251 }
3252 }
3253
3254 if (CPUMGetHyperDR7(pVCpu) & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
3255 {
3256 if (!CPUMIsHyperDebugStateActive(pVCpu))
3257 {
3258 rc = CPUMR0LoadHyperDebugState(pVM, pVCpu, pMixedCtx, true /* include DR6 */);
3259 AssertRC(rc);
3260 }
3261 Assert(CPUMIsHyperDebugStateActive(pVCpu));
3262 fInterceptMovDRx = true;
3263 }
3264 else if (pMixedCtx->dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
3265 {
3266 if (!CPUMIsGuestDebugStateActive(pVCpu))
3267 {
3268 rc = CPUMR0LoadGuestDebugState(pVM, pVCpu, pMixedCtx, true /* include DR6 */);
3269 AssertRC(rc);
3270 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
3271 }
3272 Assert(CPUMIsGuestDebugStateActive(pVCpu));
3273 Assert(fInterceptMovDRx == false);
3274 }
3275 else if (!CPUMIsGuestDebugStateActive(pVCpu))
3276 {
3277 /* For the first time we would need to intercept MOV DRx accesses even when the guest debug registers aren't loaded. */
3278 fInterceptMovDRx = true;
3279 }
3280
3281 /* Update the exception bitmap regarding intercepting #DB generated by the guest. */
3282 if (fInterceptDB)
3283 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_DB);
3284 else if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3285 {
3286#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
3287 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_DB);
3288#endif
3289 }
3290
3291 /* Update the processor-based VM-execution controls regarding intercepting MOV DRx instructions. */
3292 if (fInterceptMovDRx)
3293 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
3294 else
3295 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
3296
3297 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
3298 AssertRCReturn(rc, rc);
3299 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
3300 AssertRCReturn(rc, rc);
3301
3302 /* The guest's view of its DR7 is unblemished. Use 32-bit write as upper 32-bits MBZ as asserted above. */
3303 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, (uint32_t)pMixedCtx->dr[7]);
3304 AssertRCReturn(rc, rc);
3305
3306 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_DEBUG;
3307 return rc;
3308}
3309
3310
3311#ifdef VBOX_STRICT
3312/**
3313 * Strict function to validate segment registers.
3314 *
3315 * @remarks Requires CR0.
3316 */
3317static void hmR0VmxValidateSegmentRegs(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
3318{
3319 /* Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers". */
3320 Assert(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_CR0);
3321 Assert(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_RFLAGS);
3322
3323 /* NOTE: The reason we check for attribute value 0 and not just the unusable bit here is because hmR0VmxWriteSegmentReg()
3324 * only updates the VMCS bits with the unusable bit and doesn't change the guest-context value. */
3325 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
3326 && ( !CPUMIsGuestInRealModeEx(pCtx)
3327 && !CPUMIsGuestInV86ModeEx(pCtx)))
3328 {
3329 /* Protected mode checks */
3330 /* CS */
3331 Assert(pCtx->cs.Attr.n.u1Present);
3332 Assert(!(pCtx->cs.Attr.u & 0xf00));
3333 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
3334 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
3335 || !(pCtx->cs.Attr.n.u1Granularity));
3336 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
3337 || (pCtx->cs.Attr.n.u1Granularity));
3338 /* CS cannot be loaded with NULL in protected mode. */
3339 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & HMVMX_SEL_UNUSABLE)); /** @todo is this really true even for 64-bit CS?!? */
3340 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
3341 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
3342 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
3343 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
3344 else
3345 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
3346 /* SS */
3347 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
3348 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
3349 Assert(!(pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_CR0));
3350 if ( !(pCtx->cr0 & X86_CR0_PE)
3351 || pCtx->cs.Attr.n.u4Type == 3)
3352 {
3353 Assert(!pCtx->ss.Attr.n.u2Dpl);
3354 }
3355 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & HMVMX_SEL_UNUSABLE))
3356 {
3357 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
3358 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
3359 Assert(pCtx->ss.Attr.n.u1Present);
3360 Assert(!(pCtx->ss.Attr.u & 0xf00));
3361 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
3362 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
3363 || !(pCtx->ss.Attr.n.u1Granularity));
3364 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
3365 || (pCtx->ss.Attr.n.u1Granularity));
3366 }
3367 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxWriteSegmentReg(). */
3368 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & HMVMX_SEL_UNUSABLE))
3369 {
3370 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
3371 Assert(pCtx->ds.Attr.n.u1Present);
3372 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
3373 Assert(!(pCtx->ds.Attr.u & 0xf00));
3374 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
3375 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
3376 || !(pCtx->ds.Attr.n.u1Granularity));
3377 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
3378 || (pCtx->ds.Attr.n.u1Granularity));
3379 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
3380 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
3381 }
3382 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & HMVMX_SEL_UNUSABLE))
3383 {
3384 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
3385 Assert(pCtx->es.Attr.n.u1Present);
3386 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
3387 Assert(!(pCtx->es.Attr.u & 0xf00));
3388 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
3389 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
3390 || !(pCtx->es.Attr.n.u1Granularity));
3391 Assert( !(pCtx->es.u32Limit & 0xfff00000)
3392 || (pCtx->es.Attr.n.u1Granularity));
3393 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
3394 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
3395 }
3396 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & HMVMX_SEL_UNUSABLE))
3397 {
3398 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
3399 Assert(pCtx->fs.Attr.n.u1Present);
3400 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
3401 Assert(!(pCtx->fs.Attr.u & 0xf00));
3402 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
3403 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
3404 || !(pCtx->fs.Attr.n.u1Granularity));
3405 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
3406 || (pCtx->fs.Attr.n.u1Granularity));
3407 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
3408 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
3409 }
3410 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & HMVMX_SEL_UNUSABLE))
3411 {
3412 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
3413 Assert(pCtx->gs.Attr.n.u1Present);
3414 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
3415 Assert(!(pCtx->gs.Attr.u & 0xf00));
3416 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
3417 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
3418 || !(pCtx->gs.Attr.n.u1Granularity));
3419 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
3420 || (pCtx->gs.Attr.n.u1Granularity));
3421 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
3422 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
3423 }
3424 /* 64-bit capable CPUs. */
3425# if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
3426 Assert(!(pCtx->cs.u64Base >> 32));
3427 Assert(!pCtx->ss.Attr.u || !(pCtx->ss.u64Base >> 32));
3428 Assert(!pCtx->ds.Attr.u || !(pCtx->ds.u64Base >> 32));
3429 Assert(!pCtx->es.Attr.u || !(pCtx->es.u64Base >> 32));
3430# endif
3431 }
3432 else if ( CPUMIsGuestInV86ModeEx(pCtx)
3433 || ( CPUMIsGuestInRealModeEx(pCtx)
3434 && !pVM->hm.s.vmx.fUnrestrictedGuest))
3435 {
3436 /* Real and v86 mode checks. */
3437 /* hmR0VmxWriteSegmentReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
3438 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
3439 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3440 {
3441 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3; u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
3442 }
3443 else
3444 {
3445 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
3446 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
3447 }
3448
3449 /* CS */
3450 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
3451 Assert(pCtx->cs.u32Limit == 0xffff);
3452 Assert(u32CSAttr == 0xf3);
3453 /* SS */
3454 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
3455 Assert(pCtx->ss.u32Limit == 0xffff);
3456 Assert(u32SSAttr == 0xf3);
3457 /* DS */
3458 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
3459 Assert(pCtx->ds.u32Limit == 0xffff);
3460 Assert(u32DSAttr == 0xf3);
3461 /* ES */
3462 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
3463 Assert(pCtx->es.u32Limit == 0xffff);
3464 Assert(u32ESAttr == 0xf3);
3465 /* FS */
3466 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
3467 Assert(pCtx->fs.u32Limit == 0xffff);
3468 Assert(u32FSAttr == 0xf3);
3469 /* GS */
3470 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
3471 Assert(pCtx->gs.u32Limit == 0xffff);
3472 Assert(u32GSAttr == 0xf3);
3473 /* 64-bit capable CPUs. */
3474# if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
3475 Assert(!(pCtx->cs.u64Base >> 32));
3476 Assert(!u32SSAttr || !(pCtx->ss.u64Base >> 32));
3477 Assert(!u32DSAttr || !(pCtx->ds.u64Base >> 32));
3478 Assert(!u32ESAttr || !(pCtx->es.u64Base >> 32));
3479# endif
3480 }
3481}
3482#endif /* VBOX_STRICT */
3483
3484
3485/**
3486 * Writes a guest segment register into the guest-state area in the VMCS.
3487 *
3488 * @returns VBox status code.
3489 * @param pVCpu Pointer to the VMCPU.
3490 * @param idxSel Index of the selector in the VMCS.
3491 * @param idxLimit Index of the segment limit in the VMCS.
3492 * @param idxBase Index of the segment base in the VMCS.
3493 * @param idxAccess Index of the access rights of the segment in the VMCS.
3494 * @param pSelReg Pointer to the segment selector.
3495 * @param pCtx Pointer to the guest-CPU context.
3496 *
3497 * @remarks No-long-jump zone!!!
3498 */
3499static int hmR0VmxWriteSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase,
3500 uint32_t idxAccess, PCPUMSELREG pSelReg, PCPUMCTX pCtx)
3501{
3502 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); /* 16-bit guest selector field. */
3503 AssertRCReturn(rc, rc);
3504 rc = VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); /* 32-bit guest segment limit field. */
3505 AssertRCReturn(rc, rc);
3506 rc = VMXWriteVmcsGstN(idxBase, pSelReg->u64Base); /* Natural width guest segment base field.*/
3507 AssertRCReturn(rc, rc);
3508
3509 uint32_t u32Access = pSelReg->Attr.u;
3510 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3511 {
3512 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
3513 u32Access = 0xf3;
3514 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
3515 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
3516 }
3517 else
3518 {
3519 /*
3520 * The way to differentiate between whether this is really a null selector or was just a selector loaded with 0 in
3521 * real-mode is using the segment attributes. A selector loaded in real-mode with the value 0 is valid and usable in
3522 * protected-mode and we should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures NULL selectors
3523 * loaded in protected-mode have their attribute as 0.
3524 */
3525 if (!u32Access)
3526 u32Access = HMVMX_SEL_UNUSABLE;
3527 }
3528
3529 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
3530 AssertMsg((u32Access & HMVMX_SEL_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
3531 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
3532
3533 rc = VMXWriteVmcs32(idxAccess, u32Access); /* 32-bit guest segment access-rights field. */
3534 AssertRCReturn(rc, rc);
3535 return rc;
3536}
3537
3538
3539/**
3540 * Loads the guest segment registers, GDTR, IDTR, LDTR, (TR, FS and GS bases)
3541 * into the guest-state area in the VMCS.
3542 *
3543 * @returns VBox status code.
3544 * @param pVM Pointer to the VM.
3545 * @param pVCPU Pointer to the VMCPU.
3546 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3547 * out-of-sync. Make sure to update the required fields
3548 * before using them.
3549 *
3550 * @remarks Requires CR0 (strict builds validation).
3551 * @remarks No-long-jump zone!!!
3552 */
3553static int hmR0VmxLoadGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3554{
3555 int rc = VERR_INTERNAL_ERROR_5;
3556 PVM pVM = pVCpu->CTX_SUFF(pVM);
3557
3558 /*
3559 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
3560 */
3561 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_SEGMENT_REGS)
3562 {
3563 /* Save the segment attributes for real-on-v86 mode hack, so we can restore them on VM-exit. */
3564 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3565 {
3566 pVCpu->hm.s.vmx.RealMode.uAttrCS.u = pMixedCtx->cs.Attr.u;
3567 pVCpu->hm.s.vmx.RealMode.uAttrSS.u = pMixedCtx->ss.Attr.u;
3568 pVCpu->hm.s.vmx.RealMode.uAttrDS.u = pMixedCtx->ds.Attr.u;
3569 pVCpu->hm.s.vmx.RealMode.uAttrES.u = pMixedCtx->es.Attr.u;
3570 pVCpu->hm.s.vmx.RealMode.uAttrFS.u = pMixedCtx->fs.Attr.u;
3571 pVCpu->hm.s.vmx.RealMode.uAttrGS.u = pMixedCtx->gs.Attr.u;
3572 }
3573
3574#ifdef VBOX_WITH_REM
3575 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
3576 {
3577 Assert(pVM->hm.s.vmx.pRealModeTSS);
3578 AssertCompile(PGMMODE_REAL < PGMMODE_PROTECTED);
3579 if ( pVCpu->hm.s.vmx.fWasInRealMode
3580 && PGMGetGuestMode(pVCpu) >= PGMMODE_PROTECTED)
3581 {
3582 /* Signal that the recompiler must flush its code-cache as the guest -may- rewrite code it will later execute
3583 in real-mode (e.g. OpenBSD 4.0) */
3584 REMFlushTBs(pVM);
3585 Log4(("Load: Switch to protected mode detected!\n"));
3586 pVCpu->hm.s.vmx.fWasInRealMode = false;
3587 }
3588 }
3589#endif
3590 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_CS, VMX_VMCS32_GUEST_CS_LIMIT, VMX_VMCS_GUEST_CS_BASE,
3591 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS, &pMixedCtx->cs, pMixedCtx);
3592 AssertRCReturn(rc, rc);
3593 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_SS, VMX_VMCS32_GUEST_SS_LIMIT, VMX_VMCS_GUEST_SS_BASE,
3594 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS, &pMixedCtx->ss, pMixedCtx);
3595 AssertRCReturn(rc, rc);
3596 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_DS, VMX_VMCS32_GUEST_DS_LIMIT, VMX_VMCS_GUEST_DS_BASE,
3597 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS, &pMixedCtx->ds, pMixedCtx);
3598 AssertRCReturn(rc, rc);
3599 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_ES, VMX_VMCS32_GUEST_ES_LIMIT, VMX_VMCS_GUEST_ES_BASE,
3600 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS, &pMixedCtx->es, pMixedCtx);
3601 AssertRCReturn(rc, rc);
3602 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_FS, VMX_VMCS32_GUEST_FS_LIMIT, VMX_VMCS_GUEST_FS_BASE,
3603 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS, &pMixedCtx->fs, pMixedCtx);
3604 AssertRCReturn(rc, rc);
3605 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_GS, VMX_VMCS32_GUEST_GS_LIMIT, VMX_VMCS_GUEST_GS_BASE,
3606 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS, &pMixedCtx->gs, pMixedCtx);
3607 AssertRCReturn(rc, rc);
3608
3609 Log4(("Load: CS=%#RX16 Base=%#RX64 Limit=%#RX32 Attr=%#RX32\n", pMixedCtx->cs.Sel, pMixedCtx->cs.u64Base,
3610 pMixedCtx->cs.u32Limit, pMixedCtx->cs.Attr.u));
3611#ifdef VBOX_STRICT
3612 hmR0VmxValidateSegmentRegs(pVM, pVCpu, pMixedCtx);
3613#endif
3614 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_SEGMENT_REGS;
3615 }
3616
3617 /*
3618 * Guest TR.
3619 */
3620 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_TR)
3621 {
3622 /*
3623 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is achieved
3624 * using the interrupt redirection bitmap (all bits cleared to let the guest handle INT-n's) in the TSS.
3625 * See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
3626 */
3627 uint16_t u16Sel = 0;
3628 uint32_t u32Limit = 0;
3629 uint64_t u64Base = 0;
3630 uint32_t u32AccessRights = 0;
3631
3632 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3633 {
3634 u16Sel = pMixedCtx->tr.Sel;
3635 u32Limit = pMixedCtx->tr.u32Limit;
3636 u64Base = pMixedCtx->tr.u64Base;
3637 u32AccessRights = pMixedCtx->tr.Attr.u;
3638 }
3639 else
3640 {
3641 Assert(pVM->hm.s.vmx.pRealModeTSS);
3642 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMR3CanExecuteGuest() -XXX- what about inner loop changes? */
3643
3644 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
3645 RTGCPHYS GCPhys;
3646 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
3647 AssertRCReturn(rc, rc);
3648
3649 X86DESCATTR DescAttr;
3650 DescAttr.u = 0;
3651 DescAttr.n.u1Present = 1;
3652 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
3653
3654 u16Sel = 0;
3655 u32Limit = HM_VTX_TSS_SIZE;
3656 u64Base = GCPhys; /* in real-mode phys = virt. */
3657 u32AccessRights = DescAttr.u;
3658 }
3659
3660 /* Validate. */
3661 Assert(!(u16Sel & RT_BIT(2)));
3662 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
3663 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
3664 AssertMsg(!(u32AccessRights & HMVMX_SEL_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
3665 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
3666 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
3667 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
3668 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
3669 Assert( (u32Limit & 0xfff) == 0xfff
3670 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
3671 Assert( !(pMixedCtx->tr.u32Limit & 0xfff00000)
3672 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
3673
3674 rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_FIELD_TR, u16Sel); AssertRCReturn(rc, rc);
3675 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRCReturn(rc, rc);
3676 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRCReturn(rc, rc);
3677 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRCReturn(rc, rc);
3678
3679 Log4(("Load: VMX_VMCS_GUEST_TR_BASE=%#RX64\n", u64Base));
3680 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_TR;
3681 }
3682
3683 /*
3684 * Guest GDTR.
3685 */
3686 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_GDTR)
3687 {
3688 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pMixedCtx->gdtr.cbGdt); AssertRCReturn(rc, rc);
3689 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_GDTR_BASE, pMixedCtx->gdtr.pGdt); AssertRCReturn(rc, rc);
3690
3691 Assert(!(pMixedCtx->gdtr.cbGdt & UINT64_C(0xffff0000))); /* Bits 31:16 MBZ. */
3692 Log4(("Load: VMX_VMCS_GUEST_GDTR_BASE=%#RX64\n", pMixedCtx->gdtr.pGdt));
3693 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_GDTR;
3694 }
3695
3696 /*
3697 * Guest LDTR.
3698 */
3699 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_LDTR)
3700 {
3701 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
3702 uint32_t u32Access = 0;
3703 if (!pMixedCtx->ldtr.Attr.u)
3704 u32Access = HMVMX_SEL_UNUSABLE;
3705 else
3706 u32Access = pMixedCtx->ldtr.Attr.u;
3707
3708 rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_FIELD_LDTR, pMixedCtx->ldtr.Sel); AssertRCReturn(rc, rc);
3709 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pMixedCtx->ldtr.u32Limit); AssertRCReturn(rc, rc);
3710 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_LDTR_BASE, pMixedCtx->ldtr.u64Base); AssertRCReturn(rc, rc);
3711 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRCReturn(rc, rc);
3712
3713 /* Validate. */
3714 if (!(u32Access & HMVMX_SEL_UNUSABLE))
3715 {
3716 Assert(!(pMixedCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
3717 Assert(pMixedCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
3718 Assert(!pMixedCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
3719 Assert(pMixedCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
3720 Assert(!pMixedCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
3721 Assert(!(pMixedCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
3722 Assert( (pMixedCtx->ldtr.u32Limit & 0xfff) == 0xfff
3723 || !pMixedCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
3724 Assert( !(pMixedCtx->ldtr.u32Limit & 0xfff00000)
3725 || pMixedCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
3726 }
3727
3728 Log4(("Load: VMX_VMCS_GUEST_LDTR_BASE=%#RX64\n", pMixedCtx->ldtr.u64Base));
3729 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_LDTR;
3730 }
3731
3732 /*
3733 * Guest IDTR.
3734 */
3735 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_IDTR)
3736 {
3737 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pMixedCtx->idtr.cbIdt); AssertRCReturn(rc, rc);
3738 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_IDTR_BASE, pMixedCtx->idtr.pIdt); AssertRCReturn(rc, rc);
3739
3740 Assert(!(pMixedCtx->idtr.cbIdt & UINT64_C(0xffff0000))); /* Bits 31:16 MBZ. */
3741 Log4(("Load: VMX_VMCS_GUEST_IDTR_BASE=%#RX64\n", pMixedCtx->idtr.pIdt));
3742 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_IDTR;
3743 }
3744
3745 return VINF_SUCCESS;
3746}
3747
3748
3749/**
3750 * Loads certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
3751 * areas. These MSRs will automatically be loaded to the host CPU on every
3752 * successful VM entry and stored from the host CPU on every successful VM exit.
3753 * Also loads the sysenter MSRs into the guest-state area in the VMCS.
3754 *
3755 * @returns VBox status code.
3756 * @param pVCpu Pointer to the VMCPU.
3757 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3758 * out-of-sync. Make sure to update the required fields
3759 * before using them.
3760 *
3761 * @remarks No-long-jump zone!!!
3762 */
3763static int hmR0VmxLoadGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3764{
3765 AssertPtr(pVCpu);
3766 AssertPtr(pVCpu->hm.s.vmx.pvGuestMsr);
3767
3768 /*
3769 * MSRs covered by Auto-load/store: EFER, LSTAR, STAR, SF_MASK, TSC_AUX (RDTSCP).
3770 */
3771 int rc = VINF_SUCCESS;
3772 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
3773 {
3774#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
3775 PVM pVM = pVCpu->CTX_SUFF(pVM);
3776 PVMXMSR pGuestMsr = (PVMXMSR)pVCpu->hm.s.vmx.pvGuestMsr;
3777 uint32_t cGuestMsrs = 0;
3778
3779 /* See Intel spec. 4.1.4 "Enumeration of Paging Features by CPUID". */
3780 /** @todo r=ramshankar: Optimize this further to do lazy restoration and only
3781 * when the guest really is in 64-bit mode. */
3782 bool fSupportsLongMode = CPUMGetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_LONG_MODE);
3783 if (fSupportsLongMode)
3784 {
3785 pGuestMsr->u32IndexMSR = MSR_K8_LSTAR;
3786 pGuestMsr->u32Reserved = 0;
3787 pGuestMsr->u64Value = pMixedCtx->msrLSTAR; /* 64 bits mode syscall rip */
3788 pGuestMsr++; cGuestMsrs++;
3789 pGuestMsr->u32IndexMSR = MSR_K6_STAR;
3790 pGuestMsr->u32Reserved = 0;
3791 pGuestMsr->u64Value = pMixedCtx->msrSTAR; /* legacy syscall eip, cs & ss */
3792 pGuestMsr++; cGuestMsrs++;
3793 pGuestMsr->u32IndexMSR = MSR_K8_SF_MASK;
3794 pGuestMsr->u32Reserved = 0;
3795 pGuestMsr->u64Value = pMixedCtx->msrSFMASK; /* syscall flag mask */
3796 pGuestMsr++; cGuestMsrs++;
3797 pGuestMsr->u32IndexMSR = MSR_K8_KERNEL_GS_BASE;
3798 pGuestMsr->u32Reserved = 0;
3799 pGuestMsr->u64Value = pMixedCtx->msrKERNELGSBASE; /* swapgs exchange value */
3800 pGuestMsr++; cGuestMsrs++;
3801 }
3802
3803 /*
3804 * RDTSCP requires the TSC_AUX MSR. Host and guest share the physical MSR. So we have to
3805 * load the guest's copy if the guest can execute RDTSCP without causing VM-exits.
3806 */
3807 if ( CPUMGetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_RDTSCP)
3808 && (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP))
3809 {
3810 pGuestMsr->u32IndexMSR = MSR_K8_TSC_AUX;
3811 pGuestMsr->u32Reserved = 0;
3812 rc = CPUMQueryGuestMsr(pVCpu, MSR_K8_TSC_AUX, &pGuestMsr->u64Value);
3813 AssertRCReturn(rc, rc);
3814 pGuestMsr++; cGuestMsrs++;
3815 }
3816
3817 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
3818 if (cGuestMsrs > MSR_IA32_VMX_MISC_MAX_MSR(pVM->hm.s.vmx.msr.vmx_misc))
3819 {
3820 LogRel(("CPU autoload/store MSR count in VMCS exceeded cGuestMsrs=%u.\n", cGuestMsrs));
3821 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3822 }
3823
3824 /* Update the VCPU's copy of the guest MSR count. */
3825 pVCpu->hm.s.vmx.cGuestMsrs = cGuestMsrs;
3826 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cGuestMsrs); AssertRCReturn(rc, rc);
3827 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cGuestMsrs); AssertRCReturn(rc, rc);
3828#endif /* VBOX_WITH_AUTO_MSR_LOAD_RESTORE */
3829
3830 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_VMX_GUEST_AUTO_MSRS;
3831 }
3832
3833 /*
3834 * Guest Sysenter MSRs.
3835 * These flags are only set when MSR-bitmaps are not supported by the CPU and we cause
3836 * VM-exits on WRMSRs for these MSRs.
3837 */
3838 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
3839 {
3840 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pMixedCtx->SysEnter.cs); AssertRCReturn(rc, rc);
3841 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_SYSENTER_CS_MSR;
3842 }
3843 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
3844 {
3845 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, pMixedCtx->SysEnter.eip); AssertRCReturn(rc, rc);
3846 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR;
3847 }
3848 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
3849 {
3850 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, pMixedCtx->SysEnter.esp); AssertRCReturn(rc, rc);
3851 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR;
3852 }
3853
3854 return rc;
3855}
3856
3857
3858/**
3859 * Loads the guest activity state into the guest-state area in the VMCS.
3860 *
3861 * @returns VBox status code.
3862 * @param pVCpu Pointer to the VMCPU.
3863 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3864 * out-of-sync. Make sure to update the required fields
3865 * before using them.
3866 *
3867 * @remarks No-long-jump zone!!!
3868 */
3869static int hmR0VmxLoadGuestActivityState(PVMCPU pVCpu, PCPUMCTX pCtx)
3870{
3871 /** @todo See if we can make use of other states, e.g.
3872 * VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN or HLT. */
3873 int rc = VINF_SUCCESS;
3874 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_VMX_GUEST_ACTIVITY_STATE)
3875 {
3876 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, VMX_VMCS_GUEST_ACTIVITY_ACTIVE);
3877 AssertRCReturn(rc, rc);
3878 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_VMX_GUEST_ACTIVITY_STATE;
3879 }
3880 return rc;
3881}
3882
3883
3884/**
3885 * Sets up the appropriate function to run guest code.
3886 *
3887 * @returns VBox status code.
3888 * @param pVCpu Pointer to the VMCPU.
3889 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3890 * out-of-sync. Make sure to update the required fields
3891 * before using them.
3892 *
3893 * @remarks No-long-jump zone!!!
3894 */
3895static int hmR0VmxSetupVMRunHandler(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3896{
3897 if (CPUMIsGuestInLongModeEx(pMixedCtx))
3898 {
3899#ifndef VBOX_ENABLE_64_BITS_GUESTS
3900 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
3901#endif
3902 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
3903#if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
3904 /* 32-bit host. We need to switch to 64-bit before running the 64-bit guest. */
3905 pVCpu->hm.s.vmx.pfnStartVM = VMXR0SwitcherStartVM64;
3906#else
3907 /* 64-bit host or hybrid host. */
3908 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM64;
3909#endif
3910 }
3911 else
3912 {
3913 /* Guest is not in long mode, use the 32-bit handler. */
3914 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
3915 }
3916 Assert(pVCpu->hm.s.vmx.pfnStartVM);
3917 return VINF_SUCCESS;
3918}
3919
3920
3921/**
3922 * Wrapper for running the guest code in VT-x.
3923 *
3924 * @returns VBox strict status code.
3925 * @param pVM Pointer to the VM.
3926 * @param pVCpu Pointer to the VMCPU.
3927 * @param pCtx Pointer to the guest-CPU context.
3928 *
3929 * @remarks No-long-jump zone!!!
3930 */
3931DECLINLINE(int) hmR0VmxRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
3932{
3933 /*
3934 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses floating-point operations
3935 * using SSE instructions. Some XMM registers (XMM6-XMM15) are callee-saved and thus the need for this XMM wrapper.
3936 * Refer MSDN docs. "Configuring Programs for 64-bit / x64 Software Conventions / Register Usage" for details.
3937 */
3938#ifdef VBOX_WITH_KERNEL_USING_XMM
3939 return HMR0VMXStartVMWrapXMM(pVCpu->hm.s.fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu, pVCpu->hm.s.vmx.pfnStartVM);
3940#else
3941 return pVCpu->hm.s.vmx.pfnStartVM(pVCpu->hm.s.fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu);
3942#endif
3943}
3944
3945
3946/**
3947 * Report world-switch error and dump some useful debug info.
3948 *
3949 * @param pVM Pointer to the VM.
3950 * @param pVCpu Pointer to the VMCPU.
3951 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
3952 * @param pCtx Pointer to the guest-CPU context.
3953 * @param pVmxTransient Pointer to the VMX transient structure (only
3954 * exitReason updated).
3955 */
3956static void hmR0VmxReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, int rcVMRun, PCPUMCTX pCtx, PVMXTRANSIENT pVmxTransient)
3957{
3958 Assert(pVM);
3959 Assert(pVCpu);
3960 Assert(pCtx);
3961 Assert(pVmxTransient);
3962 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
3963
3964 Log4(("VM-entry failure: %Rrc\n", rcVMRun));
3965 switch (rcVMRun)
3966 {
3967 case VERR_VMX_INVALID_VMXON_PTR:
3968 AssertFailed();
3969 break;
3970 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
3971 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
3972 {
3973 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.lasterror.u32ExitReason);
3974 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.lasterror.u32InstrError);
3975 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
3976 AssertRC(rc);
3977
3978#ifdef VBOX_STRICT
3979 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.lasterror.u32ExitReason,
3980 pVmxTransient->uExitReason));
3981 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQualification));
3982 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.lasterror.u32InstrError));
3983 if (pVCpu->hm.s.vmx.lasterror.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
3984 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.lasterror.u32InstrError]));
3985 else
3986 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
3987
3988 /* VMX control bits. */
3989 uint32_t u32Val;
3990 uint64_t u64Val;
3991 HMVMXHCUINTREG uHCReg;
3992 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val); AssertRC(rc);
3993 Log4(("VMX_VMCS32_CTRL_PIN_EXEC %#RX32\n", u32Val));
3994 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val); AssertRC(rc);
3995 Log4(("VMX_VMCS32_CTRL_PROC_EXEC %#RX32\n", u32Val));
3996 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val); AssertRC(rc);
3997 Log4(("VMX_VMCS32_CTRL_PROC_EXEC2 %#RX32\n", u32Val));
3998 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val); AssertRC(rc);
3999 Log4(("VMX_VMCS32_CTRL_ENTRY %#RX32\n", u32Val));
4000 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val); AssertRC(rc);
4001 Log4(("VMX_VMCS32_CTRL_EXIT %#RX32\n", u32Val));
4002 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_CR3_TARGET_COUNT, &u32Val); AssertRC(rc);
4003 Log4(("VMX_VMCS32_CTRL_CR3_TARGET_COUNT %#RX32\n", u32Val));
4004 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32Val); AssertRC(rc);
4005 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", u32Val));
4006 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &u32Val); AssertRC(rc);
4007 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", u32Val));
4008 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &u32Val); AssertRC(rc);
4009 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %u\n", u32Val));
4010 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, &u32Val); AssertRC(rc);
4011 Log4(("VMX_VMCS32_CTRL_TPR_THRESHOLD %u\n", u32Val));
4012 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &u32Val); AssertRC(rc);
4013 Log4(("VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT %u (guest MSRs)\n", u32Val));
4014 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &u32Val); AssertRC(rc);
4015 Log4(("VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT %u (host MSRs)\n", u32Val));
4016 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &u32Val); AssertRC(rc);
4017 Log4(("VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT %u (guest MSRs)\n", u32Val));
4018 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val); AssertRC(rc);
4019 Log4(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP %#RX32\n", u32Val));
4020 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, &u32Val); AssertRC(rc);
4021 Log4(("VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK %#RX32\n", u32Val));
4022 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, &u32Val); AssertRC(rc);
4023 Log4(("VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH %#RX32\n", u32Val));
4024 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
4025 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
4026 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
4027 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
4028 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
4029 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
4030 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
4031 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
4032 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
4033 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
4034
4035 /* Guest bits. */
4036 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RIP, &u64Val); AssertRC(rc);
4037 Log4(("Old Guest Rip %#RX64 New %#RX64\n", pCtx->rip, u64Val));
4038 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RSP, &u64Val); AssertRC(rc);
4039 Log4(("Old Guest Rsp %#RX64 New %#RX64\n", pCtx->rsp, u64Val));
4040 rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &u32Val); AssertRC(rc);
4041 Log4(("Old Guest Rflags %#RX32 New %#RX32\n", pCtx->eflags.u32, u32Val));
4042 rc = VMXReadVmcs32(VMX_VMCS16_GUEST_FIELD_VPID, &u32Val); AssertRC(rc);
4043 Log4(("VMX_VMCS16_GUEST_FIELD_VPID %u\n", u32Val));
4044
4045 /* Host bits. */
4046 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR0, &uHCReg); AssertRC(rc);
4047 Log4(("Host CR0 %#RHr\n", uHCReg));
4048 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR3, &uHCReg); AssertRC(rc);
4049 Log4(("Host CR3 %#RHr\n", uHCReg));
4050 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR4, &uHCReg); AssertRC(rc);
4051 Log4(("Host CR4 %#RHr\n", uHCReg));
4052
4053 RTGDTR HostGdtr;
4054 PCX86DESCHC pDesc;
4055 ASMGetGDTR(&HostGdtr);
4056 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FIELD_CS, &u32Val); AssertRC(rc);
4057 Log4(("Host CS %#08x\n", u32Val));
4058 if (u32Val < HostGdtr.cbGdt)
4059 {
4060 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
4061 HMR0DumpDescriptor(pDesc, u32Val, "CS: ");
4062 }
4063
4064 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FIELD_DS, &u32Val); AssertRC(rc);
4065 Log4(("Host DS %#08x\n", u32Val));
4066 if (u32Val < HostGdtr.cbGdt)
4067 {
4068 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
4069 HMR0DumpDescriptor(pDesc, u32Val, "DS: ");
4070 }
4071
4072 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FIELD_ES, &u32Val); AssertRC(rc);
4073 Log4(("Host ES %#08x\n", u32Val));
4074 if (u32Val < HostGdtr.cbGdt)
4075 {
4076 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
4077 HMR0DumpDescriptor(pDesc, u32Val, "ES: ");
4078 }
4079
4080 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FIELD_FS, &u32Val); AssertRC(rc);
4081 Log4(("Host FS %#08x\n", u32Val));
4082 if (u32Val < HostGdtr.cbGdt)
4083 {
4084 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
4085 HMR0DumpDescriptor(pDesc, u32Val, "FS: ");
4086 }
4087
4088 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FIELD_GS, &u32Val); AssertRC(rc);
4089 Log4(("Host GS %#08x\n", u32Val));
4090 if (u32Val < HostGdtr.cbGdt)
4091 {
4092 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
4093 HMR0DumpDescriptor(pDesc, u32Val, "GS: ");
4094 }
4095
4096 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FIELD_SS, &u32Val); AssertRC(rc);
4097 Log4(("Host SS %#08x\n", u32Val));
4098 if (u32Val < HostGdtr.cbGdt)
4099 {
4100 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
4101 HMR0DumpDescriptor(pDesc, u32Val, "SS: ");
4102 }
4103
4104 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FIELD_TR, &u32Val); AssertRC(rc);
4105 Log4(("Host TR %#08x\n", u32Val));
4106 if (u32Val < HostGdtr.cbGdt)
4107 {
4108 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
4109 HMR0DumpDescriptor(pDesc, u32Val, "TR: ");
4110 }
4111
4112 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_TR_BASE, &uHCReg); AssertRC(rc);
4113 Log4(("Host TR Base %#RHv\n", uHCReg));
4114 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_GDTR_BASE, &uHCReg); AssertRC(rc);
4115 Log4(("Host GDTR Base %#RHv\n", uHCReg));
4116 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_IDTR_BASE, &uHCReg); AssertRC(rc);
4117 Log4(("Host IDTR Base %#RHv\n", uHCReg));
4118 rc = VMXReadVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, &u32Val); AssertRC(rc);
4119 Log4(("Host SYSENTER CS %#08x\n", u32Val));
4120 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_SYSENTER_EIP, &uHCReg); AssertRC(rc);
4121 Log4(("Host SYSENTER EIP %#RHv\n", uHCReg));
4122 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_SYSENTER_ESP, &uHCReg); AssertRC(rc);
4123 Log4(("Host SYSENTER ESP %#RHv\n", uHCReg));
4124 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_RSP, &uHCReg); AssertRC(rc);
4125 Log4(("Host RSP %#RHv\n", uHCReg));
4126 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_RIP, &uHCReg); AssertRC(rc);
4127 Log4(("Host RIP %#RHv\n", uHCReg));
4128# if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
4129 if (HMVMX_IS_64BIT_HOST_MODE())
4130 {
4131 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
4132 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
4133 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
4134 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
4135 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
4136 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
4137 }
4138# endif
4139#endif /* VBOX_STRICT */
4140 break;
4141 }
4142
4143 default:
4144 /* Impossible */
4145 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
4146 break;
4147 }
4148 NOREF(pVM);
4149}
4150
4151
4152#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
4153#ifndef VMX_USE_CACHED_VMCS_ACCESSES
4154# error "VMX_USE_CACHED_VMCS_ACCESSES not defined when it should be!"
4155#endif
4156#ifdef VBOX_STRICT
4157static bool hmR0VmxIsValidWriteField(uint32_t idxField)
4158{
4159 switch (idxField)
4160 {
4161 case VMX_VMCS_GUEST_RIP:
4162 case VMX_VMCS_GUEST_RSP:
4163 case VMX_VMCS_GUEST_SYSENTER_EIP:
4164 case VMX_VMCS_GUEST_SYSENTER_ESP:
4165 case VMX_VMCS_GUEST_GDTR_BASE:
4166 case VMX_VMCS_GUEST_IDTR_BASE:
4167 case VMX_VMCS_GUEST_CS_BASE:
4168 case VMX_VMCS_GUEST_DS_BASE:
4169 case VMX_VMCS_GUEST_ES_BASE:
4170 case VMX_VMCS_GUEST_FS_BASE:
4171 case VMX_VMCS_GUEST_GS_BASE:
4172 case VMX_VMCS_GUEST_SS_BASE:
4173 case VMX_VMCS_GUEST_LDTR_BASE:
4174 case VMX_VMCS_GUEST_TR_BASE:
4175 case VMX_VMCS_GUEST_CR3:
4176 return true;
4177 }
4178 return false;
4179}
4180
4181static bool hmR0VmxIsValidReadField(uint32_t idxField)
4182{
4183 switch (idxField)
4184 {
4185 /* Read-only fields. */
4186 case VMX_VMCS_RO_EXIT_QUALIFICATION:
4187 return true;
4188 }
4189 /* Remaining readable fields should also be writable. */
4190 return hmR0VmxIsValidWriteField(idxField);
4191}
4192#endif /* VBOX_STRICT */
4193
4194
4195/**
4196 * Executes the specified handler in 64-bit mode.
4197 *
4198 * @returns VBox status code.
4199 * @param pVM Pointer to the VM.
4200 * @param pVCpu Pointer to the VMCPU.
4201 * @param pCtx Pointer to the guest CPU context.
4202 * @param enmOp The operation to perform.
4203 * @param cbParam Number of parameters.
4204 * @param paParam Array of 32-bit parameters.
4205 */
4206VMMR0DECL(int) VMXR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, HM64ON32OP enmOp, uint32_t cbParam,
4207 uint32_t *paParam)
4208{
4209 int rc, rc2;
4210 PHMGLOBLCPUINFO pCpu;
4211 RTHCPHYS HCPhysCpuPage;
4212 RTCCUINTREG uOldEFlags;
4213
4214 AssertReturn(pVM->hm.s.pfnHost32ToGuest64R0, VERR_HM_NO_32_TO_64_SWITCHER);
4215 Assert(enmOp > HM64ON32OP_INVALID && enmOp < HM64ON32OP_END);
4216 Assert(pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Write.aField));
4217 Assert(pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Read.aField));
4218
4219#ifdef VBOX_STRICT
4220 for (uint32_t i = 0; i < pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries; i++)
4221 Assert(hmR0VmxIsValidWriteField(pVCpu->hm.s.vmx.VMCSCache.Write.aField[i]));
4222
4223 for (uint32_t i = 0; i <pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries; i++)
4224 Assert(hmR0VmxIsValidReadField(pVCpu->hm.s.vmx.VMCSCache.Read.aField[i]));
4225#endif
4226
4227 /* Disable interrupts. */
4228 uOldEFlags = ASMIntDisableFlags();
4229
4230#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
4231 RTCPUID idHostCpu = RTMpCpuId();
4232 CPUMR0SetLApic(pVM, idHostCpu);
4233#endif
4234
4235 pCpu = HMR0GetCurrentCpu();
4236 HCPhysCpuPage = RTR0MemObjGetPagePhysAddr(pCpu->hMemObj, 0);
4237
4238 /* Clear VMCS. Marking it inactive, clearing implementation-specific data and writing VMCS data back to memory. */
4239 VMXClearVMCS(pVCpu->hm.s.vmx.HCPhysVmcs);
4240
4241 /* Leave VMX Root Mode. */
4242 VMXDisable();
4243
4244 ASMSetCR4(ASMGetCR4() & ~X86_CR4_VMXE);
4245
4246 CPUMSetHyperESP(pVCpu, VMMGetStackRC(pVCpu));
4247 CPUMSetHyperEIP(pVCpu, enmOp);
4248 for (int i = (int)cbParam - 1; i >= 0; i--)
4249 CPUMPushHyper(pVCpu, paParam[i]);
4250
4251 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatWorldSwitch3264, z);
4252
4253 /* Call the switcher. */
4254 rc = pVM->hm.s.pfnHost32ToGuest64R0(pVM, RT_OFFSETOF(VM, aCpus[pVCpu->idCpu].cpum) - RT_OFFSETOF(VM, cpum));
4255 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatWorldSwitch3264, z);
4256
4257 /** @todo replace with hmR0VmxEnterRootMode() and hmR0VmxLeaveRootMode(). */
4258 /* Make sure the VMX instructions don't cause #UD faults. */
4259 ASMSetCR4(ASMGetCR4() | X86_CR4_VMXE);
4260
4261 /* Re-enter VMX Root Mode */
4262 rc2 = VMXEnable(HCPhysCpuPage);
4263 if (RT_FAILURE(rc2))
4264 {
4265 ASMSetCR4(ASMGetCR4() & ~X86_CR4_VMXE);
4266 ASMSetFlags(uOldEFlags);
4267 return rc2;
4268 }
4269
4270 rc2 = VMXActivateVMCS(pVCpu->hm.s.vmx.HCPhysVmcs);
4271 AssertRC(rc2);
4272 Assert(!(ASMGetFlags() & X86_EFL_IF));
4273 ASMSetFlags(uOldEFlags);
4274 return rc;
4275}
4276
4277
4278/**
4279 * Prepares for and executes VMLAUNCH (64 bits guests) for 32-bit hosts
4280 * supporting 64-bit guests.
4281 *
4282 * @returns VBox status code.
4283 * @param fResume Whether to VMLAUNCH or VMRESUME.
4284 * @param pCtx Pointer to the guest-CPU context.
4285 * @param pCache Pointer to the VMCS cache.
4286 * @param pVM Pointer to the VM.
4287 * @param pVCpu Pointer to the VMCPU.
4288 */
4289DECLASM(int) VMXR0SwitcherStartVM64(RTHCUINT fResume, PCPUMCTX pCtx, PVMCSCACHE pCache, PVM pVM, PVMCPU pVCpu)
4290{
4291 uint32_t aParam[6];
4292 PHMGLOBLCPUINFO pCpu = NULL;
4293 RTHCPHYS HCPhysCpuPage = 0;
4294 int rc = VERR_INTERNAL_ERROR_5;
4295
4296 pCpu = HMR0GetCurrentCpu();
4297 HCPhysCpuPage = RTR0MemObjGetPagePhysAddr(pCpu->hMemObj, 0);
4298
4299#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4300 pCache->uPos = 1;
4301 pCache->interPD = PGMGetInterPaeCR3(pVM);
4302 pCache->pSwitcher = (uint64_t)pVM->hm.s.pfnHost32ToGuest64R0;
4303#endif
4304
4305#ifdef VBOX_STRICT
4306 pCache->TestIn.HCPhysCpuPage = 0;
4307 pCache->TestIn.HCPhysVmcs = 0;
4308 pCache->TestIn.pCache = 0;
4309 pCache->TestOut.HCPhysVmcs = 0;
4310 pCache->TestOut.pCache = 0;
4311 pCache->TestOut.pCtx = 0;
4312 pCache->TestOut.eflags = 0;
4313#endif
4314
4315 aParam[0] = (uint32_t)(HCPhysCpuPage); /* Param 1: VMXON physical address - Lo. */
4316 aParam[1] = (uint32_t)(HCPhysCpuPage >> 32); /* Param 1: VMXON physical address - Hi. */
4317 aParam[2] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs); /* Param 2: VMCS physical address - Lo. */
4318 aParam[3] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs >> 32); /* Param 2: VMCS physical address - Hi. */
4319 aParam[4] = VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache);
4320 aParam[5] = 0;
4321
4322#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4323 pCtx->dr[4] = pVM->hm.s.vmx.pScratchPhys + 16 + 8;
4324 *(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) = 1;
4325#endif
4326 rc = VMXR0Execute64BitsHandler(pVM, pVCpu, pCtx, HM64ON32OP_VMXRCStartVM64, 6, &aParam[0]);
4327
4328#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4329 Assert(*(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) == 5);
4330 Assert(pCtx->dr[4] == 10);
4331 *(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) = 0xff;
4332#endif
4333
4334#ifdef VBOX_STRICT
4335 AssertMsg(pCache->TestIn.HCPhysCpuPage == HCPhysCpuPage, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysCpuPage, HCPhysCpuPage));
4336 AssertMsg(pCache->TestIn.HCPhysVmcs == pVCpu->hm.s.vmx.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
4337 pVCpu->hm.s.vmx.HCPhysVmcs));
4338 AssertMsg(pCache->TestIn.HCPhysVmcs == pCache->TestOut.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
4339 pCache->TestOut.HCPhysVmcs));
4340 AssertMsg(pCache->TestIn.pCache == pCache->TestOut.pCache, ("%RGv vs %RGv\n", pCache->TestIn.pCache,
4341 pCache->TestOut.pCache));
4342 AssertMsg(pCache->TestIn.pCache == VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache),
4343 ("%RGv vs %RGv\n", pCache->TestIn.pCache, VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache)));
4344 AssertMsg(pCache->TestIn.pCtx == pCache->TestOut.pCtx, ("%RGv vs %RGv\n", pCache->TestIn.pCtx,
4345 pCache->TestOut.pCtx));
4346 Assert(!(pCache->TestOut.eflags & X86_EFL_IF));
4347#endif
4348 return rc;
4349}
4350
4351
4352/**
4353 * Initialize the VMCS-Read cache. The VMCS cache is used for 32-bit hosts
4354 * running 64-bit guests (except 32-bit Darwin which runs with 64-bit paging in
4355 * 32-bit mode) for 64-bit fields that cannot be accessed in 32-bit mode. Some
4356 * 64-bit fields -can- be accessed (those that have a 32-bit FULL & HIGH part).
4357 *
4358 * @returns VBox status code.
4359 * @param pVM Pointer to the VM.
4360 * @param pVCpu Pointer to the VMCPU.
4361 */
4362static int hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu)
4363{
4364#define VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, idxField) \
4365{ \
4366 Assert(pCache->Read.aField[idxField##_CACHE_IDX] == 0); \
4367 pCache->Read.aField[idxField##_CACHE_IDX] = idxField; \
4368 pCache->Read.aFieldVal[idxField##_CACHE_IDX] = 0; \
4369 ++cReadFields; \
4370}
4371
4372 AssertPtr(pVM);
4373 AssertPtr(pVCpu);
4374 PVMCSCACHE pCache = &pVCpu->hm.s.vmx.VMCSCache;
4375 uint32_t cReadFields = 0;
4376
4377 /*
4378 * Don't remove the #if 0'd fields in this code. They're listed here for consistency
4379 * and serve to indicate exceptions to the rules.
4380 */
4381
4382 /* Guest-natural selector base fields. */
4383#if 0
4384 /* These are 32-bit in practice. See Intel spec. 2.5 "Control Registers". */
4385 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR0);
4386 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR4);
4387#endif
4388 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_ES_BASE);
4389 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CS_BASE);
4390 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SS_BASE);
4391 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_DS_BASE);
4392 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_FS_BASE);
4393 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_GS_BASE);
4394 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_LDTR_BASE);
4395 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_TR_BASE);
4396 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_GDTR_BASE);
4397 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_IDTR_BASE);
4398 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_RSP);
4399 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_RIP);
4400#if 0
4401 /* Unused natural width guest-state fields. */
4402 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS);
4403 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR3); /* Handled in Nested Paging case */
4404#endif
4405 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SYSENTER_ESP);
4406 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SYSENTER_EIP);
4407
4408 /* 64-bit guest-state fields; unused as we use two 32-bit VMREADs for these 64-bit fields (using "FULL" and "HIGH" fields). */
4409#if 0
4410 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL);
4411 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_DEBUGCTL_FULL);
4412 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PAT_FULL);
4413 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_EFER_FULL);
4414 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL);
4415 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE0_FULL);
4416 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE1_FULL);
4417 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE2_FULL);
4418 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE3_FULL);
4419#endif
4420
4421 /* Natural width guest-state fields. */
4422 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_RO_EXIT_QUALIFICATION);
4423#if 0
4424 /* Currently unused field. */
4425 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_RO_EXIT_GUEST_LINEAR_ADDR);
4426#endif
4427
4428 if (pVM->hm.s.fNestedPaging)
4429 {
4430 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR3);
4431 AssertMsg(cReadFields == VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields,
4432 VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX));
4433 pCache->Read.cValidEntries = VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX;
4434 }
4435 else
4436 {
4437 AssertMsg(cReadFields == VMX_VMCS_MAX_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields, VMX_VMCS_MAX_CACHE_IDX));
4438 pCache->Read.cValidEntries = VMX_VMCS_MAX_CACHE_IDX;
4439 }
4440
4441#undef VMXLOCAL_INIT_READ_CACHE_FIELD
4442 return VINF_SUCCESS;
4443}
4444
4445
4446/**
4447 * Writes a field into the VMCS. This can either directly invoke a VMWRITE or
4448 * queue up the VMWRITE by using the VMCS write cache (on 32-bit hosts, except
4449 * darwin, running 64-bit guests).
4450 *
4451 * @returns VBox status code.
4452 * @param pVCpu Pointer to the VMCPU.
4453 * @param idxField The VMCS field encoding.
4454 * @param u64Val 16, 32 or 64 bits value.
4455 */
4456VMMR0DECL(int) VMXWriteVmcs64Ex(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
4457{
4458 int rc;
4459 switch (idxField)
4460 {
4461 /*
4462 * These fields consists of a "FULL" and a "HIGH" part which can be written to individually.
4463 */
4464 /* 64-bit Control fields. */
4465 case VMX_VMCS64_CTRL_IO_BITMAP_A_FULL:
4466 case VMX_VMCS64_CTRL_IO_BITMAP_B_FULL:
4467 case VMX_VMCS64_CTRL_MSR_BITMAP_FULL:
4468 case VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL:
4469 case VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL:
4470 case VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL:
4471 case VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL:
4472 case VMX_VMCS64_CTRL_TSC_OFFSET_FULL:
4473 case VMX_VMCS64_CTRL_VAPIC_PAGEADDR_FULL:
4474 case VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL:
4475 case VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL:
4476 case VMX_VMCS64_CTRL_EPTP_FULL:
4477 case VMX_VMCS64_CTRL_EPTP_LIST_FULL:
4478 /* 64-bit Guest-state fields. */
4479 case VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL:
4480 case VMX_VMCS64_GUEST_DEBUGCTL_FULL:
4481 case VMX_VMCS64_GUEST_PAT_FULL:
4482 case VMX_VMCS64_GUEST_EFER_FULL:
4483 case VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL:
4484 case VMX_VMCS64_GUEST_PDPTE0_FULL:
4485 case VMX_VMCS64_GUEST_PDPTE1_FULL:
4486 case VMX_VMCS64_GUEST_PDPTE2_FULL:
4487 case VMX_VMCS64_GUEST_PDPTE3_FULL:
4488 /* 64-bit Host-state fields. */
4489 case VMX_VMCS64_HOST_FIELD_PAT_FULL:
4490 case VMX_VMCS64_HOST_FIELD_EFER_FULL:
4491 case VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL:
4492 {
4493 rc = VMXWriteVmcs32(idxField, u64Val);
4494 rc |= VMXWriteVmcs32(idxField + 1, (uint32_t)(u64Val >> 32));
4495 break;
4496 }
4497
4498 /*
4499 * These fields do not have high and low parts. Queue up the VMWRITE by using the VMCS write-cache (for 64-bit
4500 * values). When we switch the host to 64-bit mode for running 64-bit guests, these VMWRITEs get executed then.
4501 */
4502 /* Natural-width Guest-state fields. */
4503 case VMX_VMCS_GUEST_CR3:
4504 case VMX_VMCS_GUEST_ES_BASE:
4505 case VMX_VMCS_GUEST_CS_BASE:
4506 case VMX_VMCS_GUEST_SS_BASE:
4507 case VMX_VMCS_GUEST_DS_BASE:
4508 case VMX_VMCS_GUEST_FS_BASE:
4509 case VMX_VMCS_GUEST_GS_BASE:
4510 case VMX_VMCS_GUEST_LDTR_BASE:
4511 case VMX_VMCS_GUEST_TR_BASE:
4512 case VMX_VMCS_GUEST_GDTR_BASE:
4513 case VMX_VMCS_GUEST_IDTR_BASE:
4514 case VMX_VMCS_GUEST_RSP:
4515 case VMX_VMCS_GUEST_RIP:
4516 case VMX_VMCS_GUEST_SYSENTER_ESP:
4517 case VMX_VMCS_GUEST_SYSENTER_EIP:
4518 {
4519 if (!(u64Val >> 32))
4520 {
4521 /* If this field is 64-bit, VT-x will zero out the top bits. */
4522 rc = VMXWriteVmcs32(idxField, (uint32_t)u64Val);
4523 }
4524 else
4525 {
4526 /* Assert that only the 32->64 switcher case should ever come here. */
4527 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests);
4528 rc = VMXWriteCachedVmcsEx(pVCpu, idxField, u64Val);
4529 }
4530 break;
4531 }
4532
4533 default:
4534 {
4535 AssertMsgFailed(("VMXWriteVmcs64Ex: Invalid field %#RX32 (pVCpu=%p u64Val=%#RX64)\n", idxField, pVCpu, u64Val));
4536 rc = VERR_INVALID_PARAMETER;
4537 break;
4538 }
4539 }
4540 AssertRCReturn(rc, rc);
4541 return rc;
4542}
4543
4544
4545/**
4546 * Queue up a VMWRITE by using the VMCS write cache. This is only used on 32-bit
4547 * hosts (except darwin) for 64-bit guests.
4548 *
4549 * @param pVCpu Pointer to the VMCPU.
4550 * @param idxField The VMCS field encoding.
4551 * @param u64Val 16, 32 or 64 bits value.
4552 */
4553VMMR0DECL(int) VMXWriteCachedVmcsEx(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
4554{
4555 AssertPtr(pVCpu);
4556 PVMCSCACHE pCache = &pVCpu->hm.s.vmx.VMCSCache;
4557
4558 AssertMsgReturn(pCache->Write.cValidEntries < VMCSCACHE_MAX_ENTRY - 1,
4559 ("entries=%u\n", pCache->Write.cValidEntries), VERR_ACCESS_DENIED);
4560
4561 /* Make sure there are no duplicates. */
4562 for (uint32_t i = 0; i < pCache->Write.cValidEntries; i++)
4563 {
4564 if (pCache->Write.aField[i] == idxField)
4565 {
4566 pCache->Write.aFieldVal[i] = u64Val;
4567 return VINF_SUCCESS;
4568 }
4569 }
4570
4571 pCache->Write.aField[pCache->Write.cValidEntries] = idxField;
4572 pCache->Write.aFieldVal[pCache->Write.cValidEntries] = u64Val;
4573 pCache->Write.cValidEntries++;
4574 return VINF_SUCCESS;
4575}
4576
4577/* Enable later when the assembly code uses these as callbacks. */
4578#if 0
4579/*
4580 * Loads the VMCS write-cache into the CPU (by executing VMWRITEs).
4581 *
4582 * @param pVCpu Pointer to the VMCPU.
4583 * @param pCache Pointer to the VMCS cache.
4584 *
4585 * @remarks No-long-jump zone!!!
4586 */
4587VMMR0DECL(void) VMXWriteCachedVmcsLoad(PVMCPU pVCpu, PVMCSCACHE pCache)
4588{
4589 AssertPtr(pCache);
4590 for (uint32_t i = 0; i < pCache->Write.cValidEntries; i++)
4591 {
4592 int rc = VMXWriteVmcs64(pCache->Write.aField[i], pCache->Write.aFieldVal[i]);
4593 AssertRC(rc);
4594 }
4595 pCache->Write.cValidEntries = 0;
4596}
4597
4598
4599/**
4600 * Stores the VMCS read-cache from the CPU (by executing VMREADs).
4601 *
4602 * @param pVCpu Pointer to the VMCPU.
4603 * @param pCache Pointer to the VMCS cache.
4604 *
4605 * @remarks No-long-jump zone!!!
4606 */
4607VMMR0DECL(void) VMXReadCachedVmcsStore(PVMCPU pVCpu, PVMCSCACHE pCache)
4608{
4609 AssertPtr(pCache);
4610 for (uint32_t i = 0; i < pCache->Read.cValidEntries; i++)
4611 {
4612 int rc = VMXReadVmcs64(pCache->Read.aField[i], &pCache->Read.aFieldVal[i]);
4613 AssertRC(rc);
4614 }
4615}
4616#endif
4617#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL) */
4618
4619
4620/**
4621 * Sets up the usage of TSC-offsetting and updates the VMCS. If offsetting is
4622 * not possible, cause VM-exits on RDTSC(P)s. Also sets up the VMX preemption
4623 * timer.
4624 *
4625 * @returns VBox status code.
4626 * @param pVCpu Pointer to the VMCPU.
4627 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4628 * out-of-sync. Make sure to update the required fields
4629 * before using them.
4630 * @remarks No-long-jump zone!!!
4631 */
4632static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4633{
4634 int rc = VERR_INTERNAL_ERROR_5;
4635 bool fOffsettedTsc = false;
4636 PVM pVM = pVCpu->CTX_SUFF(pVM);
4637 if (pVM->hm.s.vmx.fUsePreemptTimer)
4638 {
4639 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVCpu, &fOffsettedTsc, &pVCpu->hm.s.vmx.u64TSCOffset);
4640
4641 /* Make sure the returned values have sane upper and lower boundaries. */
4642 uint64_t u64CpuHz = SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage);
4643 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
4644 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
4645 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
4646
4647 uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
4648 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_PREEMPT_TIMER_VALUE, cPreemptionTickCount); AssertRC(rc);
4649 }
4650 else
4651 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset);
4652
4653 if (fOffsettedTsc)
4654 {
4655 uint64_t u64CurTSC = ASMReadTSC();
4656 if (u64CurTSC + pVCpu->hm.s.vmx.u64TSCOffset >= TMCpuTickGetLastSeen(pVCpu))
4657 {
4658 /* Note: VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT takes precedence over TSC_OFFSET, applies to RDTSCP too. */
4659 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, pVCpu->hm.s.vmx.u64TSCOffset); AssertRC(rc);
4660
4661 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
4662 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
4663 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
4664 }
4665 else
4666 {
4667 /* VM-exit on RDTSC(P) as we would otherwise pass decreasing TSC values to the guest. */
4668 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
4669 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
4670 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscInterceptOverFlow);
4671 }
4672 }
4673 else
4674 {
4675 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
4676 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
4677 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
4678 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
4679 }
4680}
4681
4682
4683/**
4684 * Determines if an exception is a contributory exception. Contributory
4685 * exceptions are ones which can cause double-faults. Page-fault is
4686 * intentionally not included here as it's a conditional contributory exception.
4687 *
4688 * @returns true if the exception is contributory, false otherwise.
4689 * @param uVector The exception vector.
4690 */
4691DECLINLINE(bool) hmR0VmxIsContributoryXcpt(const uint32_t uVector)
4692{
4693 switch (uVector)
4694 {
4695 case X86_XCPT_GP:
4696 case X86_XCPT_SS:
4697 case X86_XCPT_NP:
4698 case X86_XCPT_TS:
4699 case X86_XCPT_DE:
4700 return true;
4701 default:
4702 break;
4703 }
4704 return false;
4705}
4706
4707
4708/**
4709 * Sets an event as a pending event to be injected into the guest.
4710 *
4711 * @param pVCpu Pointer to the VMCPU.
4712 * @param u32IntrInfo The VM-entry interruption-information field.
4713 * @param cbInstr The VM-entry instruction length in bytes (for software
4714 * interrupts, exceptions and privileged software
4715 * exceptions).
4716 * @param u32ErrCode The VM-entry exception error code.
4717 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
4718 * page-fault.
4719 */
4720DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntrInfo, uint32_t cbInstr, uint32_t u32ErrCode,
4721 RTGCUINTPTR GCPtrFaultAddress)
4722{
4723 Assert(!pVCpu->hm.s.Event.fPending);
4724 pVCpu->hm.s.Event.fPending = true;
4725 pVCpu->hm.s.Event.u64IntrInfo = u32IntrInfo;
4726 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
4727 pVCpu->hm.s.Event.cbInstr = cbInstr;
4728 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
4729}
4730
4731
4732/**
4733 * Sets a double-fault (#DF) exception as pending-for-injection into the VM.
4734 *
4735 * @param pVCpu Pointer to the VMCPU.
4736 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4737 * out-of-sync. Make sure to update the required fields
4738 * before using them.
4739 */
4740DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4741{
4742 uint32_t u32IntrInfo = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
4743 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
4744 u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
4745 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
4746}
4747
4748
4749/**
4750 * Handle a condition that occurred while delivering an event through the guest
4751 * IDT.
4752 *
4753 * @returns VBox status code (informational error codes included).
4754 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
4755 * @retval VINF_VMX_DOUBLE_FAULT if a #DF condition was detected and we ought to
4756 * continue execution of the guest which will delivery the #DF.
4757 * @retval VINF_EM_RESET if we detected a triple-fault condition.
4758 *
4759 * @param pVCpu Pointer to the VMCPU.
4760 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4761 * out-of-sync. Make sure to update the required fields
4762 * before using them.
4763 * @param pVmxTransient Pointer to the VMX transient structure.
4764 *
4765 * @remarks No-long-jump zone!!!
4766 */
4767static int hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
4768{
4769 int rc = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
4770 AssertRC(rc);
4771 if (VMX_IDT_VECTORING_INFO_VALID(pVmxTransient->uIdtVectoringInfo))
4772 {
4773 rc = hmR0VmxReadExitIntrInfoVmcs(pVCpu, pVmxTransient);
4774 AssertRCReturn(rc, rc);
4775
4776 uint32_t uIntType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
4777 uint32_t uExitVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntrInfo);
4778 uint32_t uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
4779
4780 typedef enum
4781 {
4782 VMXREFLECTXCPT_XCPT, /* Reflect the exception to the guest or for further evaluation by VMM. */
4783 VMXREFLECTXCPT_DF, /* Reflect the exception as a double-fault to the guest. */
4784 VMXREFLECTXCPT_TF, /* Indicate a triple faulted state to the VMM. */
4785 VMXREFLECTXCPT_NONE /* Nothing to reflect. */
4786 } VMXREFLECTXCPT;
4787
4788 /* See Intel spec. 30.7.1.1 "Reflecting Exceptions to Guest Software". */
4789 VMXREFLECTXCPT enmReflect = VMXREFLECTXCPT_NONE;
4790 if (uIntType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT)
4791 {
4792 enmReflect = VMXREFLECTXCPT_XCPT;
4793#ifdef VBOX_STRICT
4794 if ( hmR0VmxIsContributoryXcpt(uIdtVector)
4795 && uExitVector == X86_XCPT_PF)
4796 {
4797 Log4(("IDT: Contributory #PF uCR2=%#RX64\n", pMixedCtx->cr2));
4798 }
4799#endif
4800 if ( uExitVector == X86_XCPT_PF
4801 && uIdtVector == X86_XCPT_PF)
4802 {
4803 pVmxTransient->fVectoringPF = true;
4804 Log4(("IDT: Vectoring #PF uCR2=%#RX64\n", pMixedCtx->cr2));
4805 }
4806 else if ( (pVCpu->hm.s.vmx.u32XcptBitmap & HMVMX_CONTRIBUTORY_XCPT_MASK)
4807 && hmR0VmxIsContributoryXcpt(uExitVector)
4808 && ( hmR0VmxIsContributoryXcpt(uIdtVector)
4809 || uIdtVector == X86_XCPT_PF))
4810 {
4811 enmReflect = VMXREFLECTXCPT_DF;
4812 }
4813 else if (uIdtVector == X86_XCPT_DF)
4814 enmReflect = VMXREFLECTXCPT_TF;
4815 }
4816 else if ( uIntType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT
4817 && uIntType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
4818 && uIntType != VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
4819 {
4820 /*
4821 * Ignore software interrupts (INT n), software exceptions (#BP, #OF) and privileged software exception
4822 * (whatever they are) as they reoccur when restarting the instruction.
4823 */
4824 enmReflect = VMXREFLECTXCPT_XCPT;
4825 }
4826
4827 switch (enmReflect)
4828 {
4829 case VMXREFLECTXCPT_XCPT:
4830 {
4831 uint32_t u32ErrCode = 0;
4832 if (VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVCpu->hm.s.Event.u64IntrInfo))
4833 {
4834 rc = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
4835 AssertRCReturn(rc, rc);
4836 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
4837 }
4838
4839 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF. See hmR0VmxExitXcptPF(). */
4840 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INTR_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
4841 0 /* cbInstr */, u32ErrCode, pMixedCtx->cr2);
4842 rc = VINF_SUCCESS;
4843 Log4(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntrInfo,
4844 pVCpu->hm.s.Event.u32ErrCode));
4845 break;
4846 }
4847
4848 case VMXREFLECTXCPT_DF:
4849 {
4850 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
4851 rc = VINF_VMX_DOUBLE_FAULT;
4852 Log4(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntrInfo,
4853 uIdtVector, uExitVector));
4854 break;
4855 }
4856
4857 case VMXREFLECTXCPT_TF:
4858 {
4859 Log4(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector, uExitVector));
4860 rc = VINF_EM_RESET;
4861 break;
4862 }
4863
4864 default:
4865 Assert(rc == VINF_SUCCESS);
4866 break;
4867 }
4868 }
4869 Assert(rc == VINF_SUCCESS || rc == VINF_VMX_DOUBLE_FAULT || rc == VINF_EM_RESET);
4870 return rc;
4871}
4872
4873
4874/**
4875 * Saves the guest's CR0 register from the VMCS into the guest-CPU context.
4876 *
4877 * @returns VBox status code.
4878 * @param pVCpu Pointer to the VMCPU.
4879 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
4880 * out-of-sync. Make sure to update the required fields
4881 * before using them.
4882 *
4883 * @remarks No-long-jump zone!!!
4884 */
4885static int hmR0VmxSaveGuestCR0(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4886{
4887 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_CR0))
4888 {
4889 uint32_t uVal = 0;
4890 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &uVal);
4891 AssertRCReturn(rc, rc);
4892 uint32_t uShadow = 0;
4893 rc = VMXReadVmcs32(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uShadow);
4894 AssertRCReturn(rc, rc);
4895
4896 uVal = (uShadow & pVCpu->hm.s.vmx.u32CR0Mask) | (uVal & ~pVCpu->hm.s.vmx.u32CR0Mask);
4897 CPUMSetGuestCR0(pVCpu, uVal);
4898 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_CR0;
4899 }
4900 return VINF_SUCCESS;
4901}
4902
4903
4904/**
4905 * Saves the guest's CR4 register from the VMCS into the guest-CPU context.
4906 *
4907 * @returns VBox status code.
4908 * @param pVCpu Pointer to the VMCPU.
4909 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
4910 * out-of-sync. Make sure to update the required fields
4911 * before using them.
4912 *
4913 * @remarks No-long-jump zone!!!
4914 */
4915static int hmR0VmxSaveGuestCR4(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4916{
4917 int rc = VINF_SUCCESS;
4918 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_CR4))
4919 {
4920 uint32_t uVal = 0;
4921 uint32_t uShadow = 0;
4922 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &uVal);
4923 AssertRCReturn(rc, rc);
4924 rc = VMXReadVmcs32(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uShadow);
4925 AssertRCReturn(rc, rc);
4926
4927 uVal = (uShadow & pVCpu->hm.s.vmx.u32CR4Mask) | (uVal & ~pVCpu->hm.s.vmx.u32CR4Mask);
4928 CPUMSetGuestCR4(pVCpu, uVal);
4929 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_CR4;
4930 }
4931 return rc;
4932}
4933
4934
4935/**
4936 * Saves the guest's RIP register from the VMCS into the guest-CPU context.
4937 *
4938 * @returns VBox status code.
4939 * @param pVCpu Pointer to the VMCPU.
4940 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
4941 * out-of-sync. Make sure to update the required fields
4942 * before using them.
4943 *
4944 * @remarks No-long-jump zone!!!
4945 */
4946static int hmR0VmxSaveGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4947{
4948 int rc = VINF_SUCCESS;
4949 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_RIP))
4950 {
4951 uint64_t u64Val = 0;
4952 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RIP, &u64Val);
4953 AssertRCReturn(rc, rc);
4954
4955 pMixedCtx->rip = u64Val;
4956 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_RIP;
4957 }
4958 return rc;
4959}
4960
4961
4962/**
4963 * Saves the guest's RSP register from the VMCS into the guest-CPU context.
4964 *
4965 * @returns VBox status code.
4966 * @param pVCpu Pointer to the VMCPU.
4967 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
4968 * out-of-sync. Make sure to update the required fields
4969 * before using them.
4970 *
4971 * @remarks No-long-jump zone!!!
4972 */
4973static int hmR0VmxSaveGuestRsp(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4974{
4975 int rc = VINF_SUCCESS;
4976 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_RSP))
4977 {
4978 uint64_t u64Val = 0;
4979 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RSP, &u64Val);
4980 AssertRCReturn(rc, rc);
4981
4982 pMixedCtx->rsp = u64Val;
4983 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_RSP;
4984 }
4985 return rc;
4986}
4987
4988
4989/**
4990 * Saves the guest's RFLAGS from the VMCS into the guest-CPU context.
4991 *
4992 * @returns VBox status code.
4993 * @param pVCpu Pointer to the VMCPU.
4994 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
4995 * out-of-sync. Make sure to update the required fields
4996 * before using them.
4997 *
4998 * @remarks No-long-jump zone!!!
4999 */
5000static int hmR0VmxSaveGuestRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5001{
5002 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_RFLAGS))
5003 {
5004 uint32_t uVal = 0;
5005 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &uVal);
5006 AssertRCReturn(rc, rc);
5007
5008 pMixedCtx->eflags.u32 = uVal;
5009 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active) /* Undo our real-on-v86-mode changes to eflags if necessary. */
5010 {
5011 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
5012 Log4(("Saving real-mode EFLAGS VT-x view=%#RX32\n", pMixedCtx->eflags.u32));
5013
5014 pMixedCtx->eflags.Bits.u1VM = 0;
5015 pMixedCtx->eflags.Bits.u2IOPL = pVCpu->hm.s.vmx.RealMode.eflags.Bits.u2IOPL;
5016 }
5017
5018 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_RFLAGS;
5019 }
5020 return VINF_SUCCESS;
5021}
5022
5023
5024/**
5025 * Wrapper for saving the guest's RIP, RSP and RFLAGS from the VMCS into the
5026 * guest-CPU context.
5027 */
5028DECLINLINE(int) hmR0VmxSaveGuestRipRspRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5029{
5030 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
5031 rc |= hmR0VmxSaveGuestRsp(pVCpu, pMixedCtx);
5032 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
5033 return rc;
5034}
5035
5036
5037/**
5038 * Saves the guest's interruptibility-state ("interrupt shadow" as AMD calls it)
5039 * from the guest-state area in the VMCS.
5040 *
5041 * @param pVCpu Pointer to the VMCPU.
5042 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5043 * out-of-sync. Make sure to update the required fields
5044 * before using them.
5045 *
5046 * @remarks No-long-jump zone!!!
5047 */
5048static void hmR0VmxSaveGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5049{
5050 uint32_t uIntrState = 0;
5051 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
5052 AssertRC(rc);
5053
5054 if (!uIntrState)
5055 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
5056 else
5057 {
5058 Assert( uIntrState == VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI
5059 || uIntrState == VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
5060 rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
5061 AssertRC(rc);
5062 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx); /* for hmR0VmxGetGuestIntrState(). */
5063 AssertRC(rc);
5064
5065 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
5066 Assert(VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
5067 }
5068}
5069
5070
5071/**
5072 * Saves the guest's activity state.
5073 *
5074 * @returns VBox status code.
5075 * @param pVCpu Pointer to the VMCPU.
5076 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5077 * out-of-sync. Make sure to update the required fields
5078 * before using them.
5079 *
5080 * @remarks No-long-jump zone!!!
5081 */
5082static int hmR0VmxSaveGuestActivityState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5083{
5084 /* Nothing to do for now until we make use of different guest-CPU activity state. Just update the flag. */
5085 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_ACTIVITY_STATE;
5086 return VINF_SUCCESS;
5087}
5088
5089
5090/**
5091 * Saves the guest SYSENTER MSRs (SYSENTER_CS, SYSENTER_EIP, SYSENTER_ESP) from
5092 * the current VMCS into the guest-CPU context.
5093 *
5094 * @returns VBox status code.
5095 * @param pVCpu Pointer to the VMCPU.
5096 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5097 * out-of-sync. Make sure to update the required fields
5098 * before using them.
5099 *
5100 * @remarks No-long-jump zone!!!
5101 */
5102static int hmR0VmxSaveGuestSysenterMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5103{
5104 int rc = VINF_SUCCESS;
5105 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR))
5106 {
5107 uint32_t u32Val = 0;
5108 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRCReturn(rc, rc);
5109 pMixedCtx->SysEnter.cs = u32Val;
5110 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR;
5111 }
5112
5113 uint64_t u64Val = 0;
5114 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR))
5115 {
5116 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, &u64Val); AssertRCReturn(rc, rc);
5117 pMixedCtx->SysEnter.eip = u64Val;
5118 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR;
5119 }
5120 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR))
5121 {
5122 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, &u64Val); AssertRCReturn(rc, rc);
5123 pMixedCtx->SysEnter.esp = u64Val;
5124 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR;
5125 }
5126 return rc;
5127}
5128
5129
5130/**
5131 * Saves the guest FS_BASE MSRs from the current VMCS into the guest-CPU
5132 * context.
5133 *
5134 * @returns VBox status code.
5135 * @param pVCpu Pointer to the VMCPU.
5136 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5137 * out-of-sync. Make sure to update the required fields
5138 * before using them.
5139 *
5140 * @remarks No-long-jump zone!!!
5141 */
5142static int hmR0VmxSaveGuestFSBaseMsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5143{
5144 int rc = VINF_SUCCESS;
5145 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_FS_BASE_MSR))
5146 {
5147 uint64_t u64Val = 0;
5148 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_FS_BASE, &u64Val); AssertRCReturn(rc, rc);
5149 pMixedCtx->fs.u64Base = u64Val;
5150 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_FS_BASE_MSR;
5151 }
5152 return rc;
5153}
5154
5155
5156/**
5157 * Saves the guest GS_BASE MSRs from the current VMCS into the guest-CPU
5158 * context.
5159 *
5160 * @returns VBox status code.
5161 * @param pVCpu Pointer to the VMCPU.
5162 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5163 * out-of-sync. Make sure to update the required fields
5164 * before using them.
5165 *
5166 * @remarks No-long-jump zone!!!
5167 */
5168static int hmR0VmxSaveGuestGSBaseMsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5169{
5170 int rc = VINF_SUCCESS;
5171 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_GS_BASE_MSR))
5172 {
5173 uint64_t u64Val = 0;
5174 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_GS_BASE, &u64Val); AssertRCReturn(rc, rc);
5175 pMixedCtx->gs.u64Base = u64Val;
5176 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_GS_BASE_MSR;
5177 }
5178 return rc;
5179}
5180
5181
5182/**
5183 * Saves the auto load/store'd guest MSRs from the current VMCS into the
5184 * guest-CPU context. Currently these are LSTAR, STAR, SFMASK, KERNEL-GS BASE
5185 * and TSC_AUX.
5186 *
5187 * @returns VBox status code.
5188 * @param pVCpu Pointer to the VMCPU.
5189 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5190 * out-of-sync. Make sure to update the required fields
5191 * before using them.
5192 *
5193 * @remarks No-long-jump zone!!!
5194 */
5195static int hmR0VmxSaveGuestAutoLoadStoreMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5196{
5197 if (pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS)
5198 return VINF_SUCCESS;
5199
5200#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
5201 for (uint32_t i = 0; i < pVCpu->hm.s.vmx.cGuestMsrs; i++)
5202 {
5203 PVMXMSR pMsr = (PVMXMSR)pVCpu->hm.s.vmx.pvGuestMsr;
5204 pMsr += i;
5205 switch (pMsr->u32IndexMSR)
5206 {
5207 case MSR_K8_LSTAR: pMixedCtx->msrLSTAR = pMsr->u64Value; break;
5208 case MSR_K6_STAR: pMixedCtx->msrSTAR = pMsr->u64Value; break;
5209 case MSR_K8_SF_MASK: pMixedCtx->msrSFMASK = pMsr->u64Value; break;
5210 case MSR_K8_TSC_AUX: CPUMSetGuestMsr(pVCpu, MSR_K8_TSC_AUX, pMsr->u64Value); break;
5211 case MSR_K8_KERNEL_GS_BASE: pMixedCtx->msrKERNELGSBASE = pMsr->u64Value; break;
5212 case MSR_K6_EFER: /* EFER can't be changed without causing a VM-exit. */ break;
5213 default:
5214 {
5215 AssertFailed();
5216 return VERR_HM_UNEXPECTED_LD_ST_MSR;
5217 }
5218 }
5219 }
5220#endif
5221
5222 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS;
5223 return VINF_SUCCESS;
5224}
5225
5226
5227/**
5228 * Saves the guest control registers from the current VMCS into the guest-CPU
5229 * context.
5230 *
5231 * @returns VBox status code.
5232 * @param pVCpu Pointer to the VMCPU.
5233 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5234 * out-of-sync. Make sure to update the required fields
5235 * before using them.
5236 *
5237 * @remarks No-long-jump zone!!!
5238 */
5239static int hmR0VmxSaveGuestControlRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5240{
5241 /* Guest CR0. Guest FPU. */
5242 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
5243 AssertRCReturn(rc, rc);
5244
5245 /* Guest CR4. */
5246 rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
5247 AssertRCReturn(rc, rc);
5248
5249 /* Guest CR2 - updated always during the world-switch or in #PF. */
5250 /* Guest CR3. Only changes with Nested Paging. This must be done -after- saving CR0 and CR4 from the guest! */
5251 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_CR3))
5252 {
5253 Assert(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_CR0);
5254 Assert(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_CR4);
5255
5256 PVM pVM = pVCpu->CTX_SUFF(pVM);
5257 if ( pVM->hm.s.vmx.fUnrestrictedGuest
5258 || ( pVM->hm.s.fNestedPaging
5259 && CPUMIsGuestPagingEnabledEx(pMixedCtx)))
5260 {
5261 uint64_t u64Val = 0;
5262 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_CR3, &u64Val);
5263 if (pMixedCtx->cr3 != u64Val)
5264 {
5265 CPUMSetGuestCR3(pVCpu, u64Val);
5266 if (VMMRZCallRing3IsEnabled(pVCpu))
5267 {
5268 PGMUpdateCR3(pVCpu, u64Val);
5269 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
5270 }
5271 else
5272 {
5273 /* Set the force flag to inform PGM about it when necessary. It is cleared by PGMUpdateCR3().*/
5274 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
5275 }
5276 }
5277
5278 /* If the guest is in PAE mode, sync back the PDPE's into the guest state. */
5279 if (CPUMIsGuestInPAEModeEx(pMixedCtx)) /* Reads CR0, CR4 and EFER MSR (EFER is always up-to-date). */
5280 {
5281 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u); AssertRCReturn(rc, rc);
5282 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u); AssertRCReturn(rc, rc);
5283 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u); AssertRCReturn(rc, rc);
5284 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u); AssertRCReturn(rc, rc);
5285
5286 if (VMMRZCallRing3IsEnabled(pVCpu))
5287 {
5288 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5289 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
5290 }
5291 else
5292 {
5293 /* Set the force flag to inform PGM about it when necessary. It is cleared by PGMGstUpdatePaePdpes(). */
5294 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
5295 }
5296 }
5297 }
5298
5299 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_CR3;
5300 }
5301
5302 /*
5303 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
5304 * -> VMMRZCallRing3Disable() -> hmR0VmxSaveGuestState() -> Set VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
5305 * -> continue with VM-exit handling -> hmR0VmxSaveGuestControlRegs() and here we are.
5306 *
5307 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
5308 */
5309 if (VMMRZCallRing3IsEnabled(pVCpu))
5310 {
5311 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
5312 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
5313
5314 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
5315 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5316
5317 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
5318 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
5319 }
5320
5321 return rc;
5322}
5323
5324
5325/**
5326 * Reads a guest segment register from the current VMCS into the guest-CPU
5327 * context.
5328 *
5329 * @returns VBox status code.
5330 * @param pVCpu Pointer to the VMCPU.
5331 * @param idxSel Index of the selector in the VMCS.
5332 * @param idxLimit Index of the segment limit in the VMCS.
5333 * @param idxBase Index of the segment base in the VMCS.
5334 * @param idxAccess Index of the access rights of the segment in the VMCS.
5335 * @param pSelReg Pointer to the segment selector.
5336 *
5337 * @remarks No-long-jump zone!!!
5338 * @remarks Never call this function directly!!! Use the VMXLOCAL_READ_SEG()
5339 * macro as that takes care of whether to read from the VMCS cache or
5340 * not.
5341 */
5342DECLINLINE(int) hmR0VmxReadSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase, uint32_t idxAccess,
5343 PCPUMSELREG pSelReg)
5344{
5345 uint32_t u32Val = 0;
5346 int rc = VMXReadVmcs32(idxSel, &u32Val);
5347 AssertRCReturn(rc, rc);
5348 pSelReg->Sel = (uint16_t)u32Val;
5349 pSelReg->ValidSel = (uint16_t)u32Val;
5350 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
5351
5352 rc = VMXReadVmcs32(idxLimit, &u32Val);
5353 AssertRCReturn(rc, rc);
5354 pSelReg->u32Limit = u32Val;
5355
5356 uint64_t u64Val = 0;
5357 rc = VMXReadVmcsGstNByIdxVal(idxBase, &u64Val);
5358 AssertRCReturn(rc, rc);
5359 pSelReg->u64Base = u64Val;
5360
5361 rc = VMXReadVmcs32(idxAccess, &u32Val);
5362 AssertRCReturn(rc, rc);
5363 pSelReg->Attr.u = u32Val;
5364
5365 /*
5366 * If VT-x marks the segment as unusable, the rest of the attributes are undefined with certain exceptions (some bits in
5367 * CS, SS). Regardless, we have to clear the bits here and only retain the unusable bit because the unusable bit is specific
5368 * to VT-x, everyone else relies on the attribute being zero and have no clue what the unusable bit is.
5369 *
5370 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
5371 */
5372 if (pSelReg->Attr.u & HMVMX_SEL_UNUSABLE)
5373 {
5374 Assert(idxSel != VMX_VMCS16_GUEST_FIELD_TR); /* TR is the only selector that can never be unusable. */
5375 pSelReg->Attr.u = HMVMX_SEL_UNUSABLE;
5376 }
5377 return VINF_SUCCESS;
5378}
5379
5380
5381#ifdef VMX_USE_CACHED_VMCS_ACCESSES
5382#define VMXLOCAL_READ_SEG(Sel, CtxSel) \
5383 hmR0VmxReadSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_##Sel, VMX_VMCS32_GUEST_##Sel##_LIMIT, \
5384 VMX_VMCS_GUEST_##Sel##_BASE_CACHE_IDX, VMX_VMCS32_GUEST_##Sel##_ACCESS_RIGHTS, &pMixedCtx->CtxSel)
5385#else
5386#define VMXLOCAL_READ_SEG(Sel, CtxSel) \
5387 hmR0VmxReadSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_##Sel, VMX_VMCS32_GUEST_##Sel##_LIMIT, \
5388 VMX_VMCS_GUEST_##Sel##_BASE, VMX_VMCS32_GUEST_##Sel##_ACCESS_RIGHTS, &pMixedCtx->CtxSel)
5389#endif
5390
5391
5392/**
5393 * Saves the guest segment registers from the current VMCS into the guest-CPU
5394 * context.
5395 *
5396 * @returns VBox status code.
5397 * @param pVCpu Pointer to the VMCPU.
5398 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5399 * out-of-sync. Make sure to update the required fields
5400 * before using them.
5401 *
5402 * @remarks No-long-jump zone!!!
5403 */
5404static int hmR0VmxSaveGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5405{
5406 /* Guest segment registers. */
5407 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_SEGMENT_REGS))
5408 {
5409 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx); AssertRCReturn(rc, rc);
5410 rc = VMXLOCAL_READ_SEG(CS, cs); AssertRCReturn(rc, rc);
5411 rc = VMXLOCAL_READ_SEG(SS, ss); AssertRCReturn(rc, rc);
5412 rc = VMXLOCAL_READ_SEG(DS, ds); AssertRCReturn(rc, rc);
5413 rc = VMXLOCAL_READ_SEG(ES, es); AssertRCReturn(rc, rc);
5414 rc = VMXLOCAL_READ_SEG(FS, fs); AssertRCReturn(rc, rc);
5415 rc = VMXLOCAL_READ_SEG(GS, gs); AssertRCReturn(rc, rc);
5416
5417 /* Restore segment attributes for real-on-v86 mode hack. */
5418 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
5419 {
5420 pMixedCtx->cs.Attr.u = pVCpu->hm.s.vmx.RealMode.uAttrCS.u;
5421 pMixedCtx->ss.Attr.u = pVCpu->hm.s.vmx.RealMode.uAttrSS.u;
5422 pMixedCtx->ds.Attr.u = pVCpu->hm.s.vmx.RealMode.uAttrDS.u;
5423 pMixedCtx->es.Attr.u = pVCpu->hm.s.vmx.RealMode.uAttrES.u;
5424 pMixedCtx->fs.Attr.u = pVCpu->hm.s.vmx.RealMode.uAttrFS.u;
5425 pMixedCtx->gs.Attr.u = pVCpu->hm.s.vmx.RealMode.uAttrGS.u;
5426 }
5427 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_SEGMENT_REGS;
5428 }
5429
5430 return VINF_SUCCESS;
5431}
5432
5433
5434/**
5435 * Saves the guest descriptor table registers and task register from the current
5436 * VMCS into the guest-CPU context.
5437 *
5438 * @returns VBox status code.
5439 * @param pVCpu Pointer to the VMCPU.
5440 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5441 * out-of-sync. Make sure to update the required fields
5442 * before using them.
5443 *
5444 * @remarks No-long-jump zone!!!
5445 */
5446static int hmR0VmxSaveGuestTableRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5447{
5448 int rc = VINF_SUCCESS;
5449
5450 /* Guest LDTR. */
5451 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_LDTR))
5452 {
5453 rc = VMXLOCAL_READ_SEG(LDTR, ldtr);
5454 AssertRCReturn(rc, rc);
5455 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_LDTR;
5456 }
5457
5458 /* Guest GDTR. */
5459 uint64_t u64Val = 0;
5460 uint32_t u32Val = 0;
5461 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_GDTR))
5462 {
5463 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_GDTR_BASE, &u64Val); AssertRCReturn(rc, rc);
5464 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRCReturn(rc, rc);
5465 pMixedCtx->gdtr.pGdt = u64Val;
5466 pMixedCtx->gdtr.cbGdt = u32Val;
5467 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_GDTR;
5468 }
5469
5470 /* Guest IDTR. */
5471 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_IDTR))
5472 {
5473 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_IDTR_BASE, &u64Val); AssertRCReturn(rc, rc);
5474 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRCReturn(rc, rc);
5475 pMixedCtx->idtr.pIdt = u64Val;
5476 pMixedCtx->idtr.cbIdt = u32Val;
5477 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_IDTR;
5478 }
5479
5480 /* Guest TR. */
5481 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_TR))
5482 {
5483 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
5484 AssertRCReturn(rc, rc);
5485
5486 /* For real-mode emulation using virtual-8086 mode we have the fake TSS (pRealModeTSS) in TR, don't save the fake one. */
5487 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
5488 {
5489 rc = VMXLOCAL_READ_SEG(TR, tr);
5490 AssertRCReturn(rc, rc);
5491 }
5492 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_TR;
5493 }
5494 return rc;
5495}
5496
5497#undef VMXLOCAL_READ_SEG
5498
5499
5500/**
5501 * Saves the guest debug registers from the current VMCS into the guest-CPU
5502 * context.
5503 *
5504 * @returns VBox status code.
5505 * @param pVCpu Pointer to the VMCPU.
5506 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5507 * out-of-sync. Make sure to update the required fields
5508 * before using them.
5509 *
5510 * @remarks No-long-jump zone!!!
5511 */
5512static int hmR0VmxSaveGuestDebugRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5513{
5514 int rc = VINF_SUCCESS;
5515 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_DEBUG))
5516 {
5517 /* Upper 32-bits are always zero. See Intel spec. 2.7.3 "Loading and Storing Debug Registers". */
5518 uint32_t u32Val;
5519 rc = VMXReadVmcs32(VMX_VMCS_GUEST_DR7, &u32Val); AssertRCReturn(rc, rc);
5520 pMixedCtx->dr[7] = u32Val;
5521
5522 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_DEBUG;
5523 }
5524 return rc;
5525}
5526
5527
5528/**
5529 * Saves the guest APIC state from the currentl VMCS into the guest-CPU context.
5530 *
5531 * @returns VBox status code.
5532 * @param pVCpu Pointer to the VMCPU.
5533 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5534 * out-of-sync. Make sure to update the required fields
5535 * before using them.
5536 *
5537 * @remarks No-long-jump zone!!!
5538 */
5539static int hmR0VmxSaveGuestApicState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5540{
5541 /* Updating TPR is already done in hmR0VmxPostRunGuest(). Just update the flag. */
5542 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_APIC_STATE;
5543 return VINF_SUCCESS;
5544}
5545
5546
5547/**
5548 * Saves the entire guest state from the currently active VMCS into the
5549 * guest-CPU context. This essentially VMREADs all guest-data.
5550 *
5551 * @returns VBox status code.
5552 * @param pVCpu Pointer to the VMCPU.
5553 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5554 * out-of-sync. Make sure to update the required fields
5555 * before using them.
5556 */
5557static int hmR0VmxSaveGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5558{
5559 Assert(pVCpu);
5560 Assert(pMixedCtx);
5561
5562 if (pVCpu->hm.s.vmx.fUpdatedGuestState == HMVMX_UPDATED_GUEST_ALL)
5563 return VINF_SUCCESS;
5564
5565 /* Though we can longjmp to ring-3 due to log-flushes here and get recalled again on the ring-3 callback path,
5566 there is no real need to. */
5567 if (VMMRZCallRing3IsEnabled(pVCpu))
5568 VMMR0LogFlushDisable(pVCpu);
5569 else
5570 Assert(VMMR0IsLogFlushDisabled(pVCpu));
5571 Log4Func(("\n"));
5572
5573 int rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
5574 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestRipRspRflags failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5575
5576 rc = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
5577 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestControlRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5578
5579 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
5580 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSegmentRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5581
5582 rc = hmR0VmxSaveGuestTableRegs(pVCpu, pMixedCtx);
5583 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestTableRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5584
5585 rc = hmR0VmxSaveGuestDebugRegs(pVCpu, pMixedCtx);
5586 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestDebugRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5587
5588 rc = hmR0VmxSaveGuestSysenterMsrs(pVCpu, pMixedCtx);
5589 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSysenterMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5590
5591 rc = hmR0VmxSaveGuestFSBaseMsr(pVCpu, pMixedCtx);
5592 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestFSBaseMsr failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5593
5594 rc = hmR0VmxSaveGuestGSBaseMsr(pVCpu, pMixedCtx);
5595 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestGSBaseMsr failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5596
5597 rc = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
5598 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestAutoLoadStoreMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5599
5600 rc = hmR0VmxSaveGuestActivityState(pVCpu, pMixedCtx);
5601 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestActivityState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5602
5603 rc = hmR0VmxSaveGuestApicState(pVCpu, pMixedCtx);
5604 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestDebugRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
5605
5606 AssertMsg(pVCpu->hm.s.vmx.fUpdatedGuestState == HMVMX_UPDATED_GUEST_ALL,
5607 ("Missed guest state bits while saving state; residue %RX32\n", pVCpu->hm.s.vmx.fUpdatedGuestState));
5608
5609 if (VMMRZCallRing3IsEnabled(pVCpu))
5610 VMMR0LogFlushEnable(pVCpu);
5611
5612 return rc;
5613}
5614
5615
5616/**
5617 * Check per-VM and per-VCPU force flag actions that require us to go back to
5618 * ring-3 for one reason or another.
5619 *
5620 * @returns VBox status code (information status code included).
5621 * @retval VINF_SUCCESS if we don't have any actions that require going back to
5622 * ring-3.
5623 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
5624 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
5625 * interrupts)
5626 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
5627 * all EMTs to be in ring-3.
5628 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
5629 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
5630 * to the EM loop.
5631 *
5632 * @param pVM Pointer to the VM.
5633 * @param pVCpu Pointer to the VMCPU.
5634 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5635 * out-of-sync. Make sure to update the required fields
5636 * before using them.
5637 */
5638static int hmR0VmxCheckForceFlags(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5639{
5640 Assert(VMMRZCallRing3IsEnabled(pVCpu));
5641
5642 int rc = VERR_INTERNAL_ERROR_5;
5643 if ( VM_FF_IS_PENDING(pVM, VM_FF_HM_TO_R3_MASK | VM_FF_REQUEST | VM_FF_PGM_POOL_FLUSH_PENDING | VM_FF_PDM_DMA)
5644 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
5645 | VMCPU_FF_REQUEST | VMCPU_FF_HM_UPDATE_CR3 | VMCPU_FF_HM_UPDATE_PAE_PDPES))
5646 {
5647 /* We need the control registers now, make sure the guest-CPU context is updated. */
5648 rc = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
5649 AssertRCReturn(rc, rc);
5650
5651 /* Pending HM CR3 sync. */
5652 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
5653 {
5654 rc = PGMUpdateCR3(pVCpu, pMixedCtx->cr3);
5655 Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3);
5656 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
5657 }
5658
5659 /* Pending HM PAE PDPEs. */
5660 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
5661 {
5662 rc = PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5663 AssertRC(rc);
5664 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
5665 }
5666
5667 /* Pending PGM C3 sync. */
5668 if (VMCPU_FF_IS_PENDING(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
5669 {
5670 rc = PGMSyncCR3(pVCpu, pMixedCtx->cr0, pMixedCtx->cr3, pMixedCtx->cr4, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
5671 if (rc != VINF_SUCCESS)
5672 {
5673 AssertRC(rc);
5674 Log4(("hmR0VmxCheckForceFlags: PGMSyncCR3 forcing us back to ring-3. rc=%d\n", rc));
5675 return rc;
5676 }
5677 }
5678
5679 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
5680 /* -XXX- what was that about single stepping? */
5681 if ( VM_FF_IS_PENDING(pVM, VM_FF_HM_TO_R3_MASK)
5682 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
5683 {
5684 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
5685 rc = RT_UNLIKELY(VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_NO_MEMORY : VINF_EM_RAW_TO_R3;
5686 Log4(("hmR0VmxCheckForceFlags: HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
5687 return rc;
5688 }
5689
5690 /* Pending VM request packets, such as hardware interrupts. */
5691 if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST)
5692 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
5693 {
5694 Log4(("hmR0VmxCheckForceFlags: Pending VM request forcing us back to ring-3\n"));
5695 return VINF_EM_PENDING_REQUEST;
5696 }
5697
5698 /* Pending PGM pool flushes. */
5699 if (VM_FF_IS_PENDING(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
5700 {
5701 Log4(("hmR0VmxCheckForceFlags: PGM pool flush pending forcing us back to ring-3\n"));
5702 return VINF_PGM_POOL_FLUSH_PENDING;
5703 }
5704
5705 /* Pending DMA requests. */
5706 if (VM_FF_IS_PENDING(pVM, VM_FF_PDM_DMA))
5707 {
5708 Log4(("hmR0VmxCheckForceFlags: Pending DMA request forcing us back to ring-3\n"));
5709 return VINF_EM_RAW_TO_R3;
5710 }
5711 }
5712
5713 /* Paranoia. */
5714 Assert(rc != VERR_EM_INTERPRETER);
5715 return VINF_SUCCESS;
5716}
5717
5718
5719/**
5720 * Converts any TRPM trap into a pending VMX event. This is typically used when
5721 * entering from ring-3 (not longjmp returns).
5722 *
5723 * @param pVCpu Pointer to the VMCPU.
5724 */
5725static void hmR0VmxTRPMTrapToPendingEvent(PVMCPU pVCpu)
5726{
5727 Assert(TRPMHasTrap(pVCpu));
5728 Assert(!pVCpu->hm.s.Event.fPending);
5729
5730 uint8_t uVector;
5731 TRPMEVENT enmTrpmEvent;
5732 RTGCUINT uErrCode;
5733 RTGCUINTPTR GCPtrFaultAddress;
5734 uint8_t cbInstr;
5735
5736 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
5737 AssertRC(rc);
5738
5739 /* Refer Intel spec. 24.8.3 "VM-entry Controls for Event Injection" for the format of u32IntrInfo. */
5740 uint32_t u32IntrInfo = uVector | VMX_EXIT_INTERRUPTION_INFO_VALID;
5741 if (enmTrpmEvent == TRPM_TRAP)
5742 {
5743 switch (uVector)
5744 {
5745 case X86_XCPT_BP:
5746 case X86_XCPT_OF:
5747 {
5748 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
5749 break;
5750 }
5751
5752 case X86_XCPT_PF:
5753 case X86_XCPT_DF:
5754 case X86_XCPT_TS:
5755 case X86_XCPT_NP:
5756 case X86_XCPT_SS:
5757 case X86_XCPT_GP:
5758 case X86_XCPT_AC:
5759 u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
5760 /* no break! */
5761 default:
5762 {
5763 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
5764 break;
5765 }
5766 }
5767 }
5768 else if (enmTrpmEvent == TRPM_HARDWARE_INT)
5769 {
5770 if (uVector != X86_XCPT_NMI)
5771 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
5772 else
5773 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
5774 }
5775 else if (enmTrpmEvent == TRPM_SOFTWARE_INT)
5776 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
5777 else
5778 AssertMsgFailed(("Invalid TRPM event type %d\n", enmTrpmEvent));
5779
5780 rc = TRPMResetTrap(pVCpu);
5781 AssertRC(rc);
5782 Log4(("TRPM->HM event: u32IntrInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
5783 u32IntrInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
5784 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, cbInstr, uErrCode, GCPtrFaultAddress);
5785}
5786
5787
5788/**
5789 * Converts any pending VMX event into a TRPM trap. Typically used when leaving
5790 * VT-x to execute any instruction.
5791 *
5792 * @param pvCpu Pointer to the VMCPU.
5793 */
5794static void hmR0VmxPendingEventToTRPMTrap(PVMCPU pVCpu)
5795{
5796 Assert(pVCpu->hm.s.Event.fPending);
5797
5798 uint32_t uVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVCpu->hm.s.Event.u64IntrInfo);
5799 uint32_t uVector = VMX_IDT_VECTORING_INFO_VECTOR(pVCpu->hm.s.Event.u64IntrInfo);
5800 bool fErrorCodeValid = !!VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVCpu->hm.s.Event.u64IntrInfo);
5801 uint32_t uErrorCode = pVCpu->hm.s.Event.u32ErrCode;
5802
5803 /* If a trap was already pending, we did something wrong! */
5804 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
5805
5806 TRPMEVENT enmTrapType;
5807 switch (uVectorType)
5808 {
5809 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
5810 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
5811 enmTrapType = TRPM_HARDWARE_INT;
5812 break;
5813 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
5814 enmTrapType = TRPM_SOFTWARE_INT;
5815 break;
5816 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
5817 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT: /* #BP and #OF */
5818 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
5819 enmTrapType = TRPM_TRAP;
5820 break;
5821 default:
5822 AssertMsgFailed(("Invalid trap type %#x\n", uVectorType));
5823 enmTrapType = TRPM_32BIT_HACK;
5824 break;
5825 }
5826
5827 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
5828
5829 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
5830 AssertRC(rc);
5831
5832 if (fErrorCodeValid)
5833 TRPMSetErrorCode(pVCpu, uErrorCode);
5834 if ( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
5835 && uVector == X86_XCPT_PF)
5836 {
5837 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
5838 }
5839 else if ( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
5840 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
5841 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
5842 {
5843 AssertMsg( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
5844 || (uVector == X86_XCPT_BP || uVector == X86_XCPT_OF),
5845 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
5846 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
5847 }
5848 pVCpu->hm.s.Event.fPending = false;
5849}
5850
5851
5852/**
5853 * Does the necessary state syncing before doing a longjmp to ring-3.
5854 *
5855 * @param pVM Pointer to the VM.
5856 * @param pVCpu Pointer to the VMCPU.
5857 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5858 * out-of-sync. Make sure to update the required fields
5859 * before using them.
5860 * @param rcExit The reason for exiting to ring-3. Can be
5861 * VINF_VMM_UNKNOWN_RING3_CALL.
5862 *
5863 * @remarks No-long-jmp zone!!!
5864 */
5865static void hmR0VmxLongJmpToRing3(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, int rcExit)
5866{
5867 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
5868 Assert(VMMR0IsLogFlushDisabled(pVCpu));
5869
5870 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
5871 Assert(pVCpu->hm.s.vmx.fUpdatedGuestState == HMVMX_UPDATED_GUEST_ALL);
5872 AssertRC(rc);
5873
5874 /* Restore FPU state if necessary and resync on next R0 reentry .*/
5875 if (CPUMIsGuestFPUStateActive(pVCpu))
5876 {
5877 CPUMR0SaveGuestFPU(pVM, pVCpu, pMixedCtx);
5878 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
5879 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_CR0;
5880 }
5881
5882 /* Restore debug registers if necessary and resync on next R0 reentry. */
5883 if (CPUMIsGuestDebugStateActive(pVCpu))
5884 {
5885 CPUMR0SaveGuestDebugState(pVM, pVCpu, pMixedCtx, true /* save DR6 */);
5886 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
5887 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_DEBUG;
5888 }
5889 else if (CPUMIsHyperDebugStateActive(pVCpu))
5890 {
5891 CPUMR0LoadHostDebugState(pVM, pVCpu);
5892 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
5893 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT);
5894 }
5895
5896 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
5897 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
5898 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
5899 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
5900 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
5901 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
5902 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
5903 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
5904 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
5905}
5906
5907
5908/**
5909 * An action requires us to go back to ring-3. This function does the necessary
5910 * steps before we can safely return to ring-3. This is not the same as longjmps
5911 * to ring-3, this is voluntary.
5912 *
5913 * @param pVM Pointer to the VM.
5914 * @param pVCpu Pointer to the VMCPU.
5915 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5916 * out-of-sync. Make sure to update the required fields
5917 * before using them.
5918 * @param rcExit The reason for exiting to ring-3. Can be
5919 * VINF_VMM_UNKNOWN_RING3_CALL.
5920 */
5921static void hmR0VmxExitToRing3(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, int rcExit)
5922{
5923 Assert(pVM);
5924 Assert(pVCpu);
5925 Assert(pMixedCtx);
5926 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5927
5928 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_GUEST_STATE))
5929 {
5930 /* We want to see what the guest-state was before VM-entry, don't resync here, as we won't continue guest execution. */
5931 return;
5932 }
5933 else if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
5934 {
5935 VMXGetActivateVMCS(&pVCpu->hm.s.vmx.lasterror.u64VMCSPhys);
5936 pVCpu->hm.s.vmx.lasterror.u32VMCSRevision = *(uint32_t *)pVCpu->hm.s.vmx.pvVmcs;
5937 pVCpu->hm.s.vmx.lasterror.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
5938 pVCpu->hm.s.vmx.lasterror.idCurrentCpu = RTMpCpuId();
5939 return;
5940 }
5941
5942 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
5943 VMMRZCallRing3Disable(pVCpu);
5944 Log4(("hmR0VmxExitToRing3: rcExit=%d\n", rcExit));
5945
5946 /* We need to do this only while truly exiting the "inner loop" back to ring-3 and -not- for any longjmp to ring3. */
5947 if (pVCpu->hm.s.Event.fPending)
5948 {
5949 hmR0VmxPendingEventToTRPMTrap(pVCpu);
5950 Assert(!pVCpu->hm.s.Event.fPending);
5951 }
5952
5953 /* Sync. the guest state. */
5954 hmR0VmxLongJmpToRing3(pVM, pVCpu, pMixedCtx, rcExit);
5955 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
5956
5957 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
5958 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
5959 | CPUM_CHANGED_LDTR
5960 | CPUM_CHANGED_GDTR
5961 | CPUM_CHANGED_IDTR
5962 | CPUM_CHANGED_TR
5963 | CPUM_CHANGED_HIDDEN_SEL_REGS);
5964
5965 /* On our way back from ring-3 the following needs to be done. */
5966 /** @todo This can change with preemption hooks. */
5967 if (rcExit == VINF_EM_RAW_INTERRUPT)
5968 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_HOST_CONTEXT;
5969 else
5970 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_HOST_CONTEXT | HM_CHANGED_ALL_GUEST;
5971
5972 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
5973 VMMRZCallRing3Enable(pVCpu);
5974}
5975
5976
5977/**
5978 * VMMRZCallRing3 callback wrapper which saves the guest state before we
5979 * longjump to ring-3 and possibly get preempted.
5980 *
5981 * @param pVCpu Pointer to the VMCPU.
5982 * @param enmOperation The operation causing the ring-3 longjump.
5983 * @param pvUser The user argument (pointer to the possibly
5984 * out-of-date guest-CPU context).
5985 *
5986 * @remarks Must never be called with @a enmOperation ==
5987 * VMMCALLRING3_VM_R0_ASSERTION.
5988 */
5989DECLCALLBACK(void) hmR0VmxCallRing3Callback(PVMCPU pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
5990{
5991 /* VMMRZCallRing3() already makes sure we never get called as a result of an longjmp due to an assertion, */
5992 Assert(pVCpu);
5993 Assert(pvUser);
5994 Assert(VMMRZCallRing3IsEnabled(pVCpu));
5995 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5996
5997 VMMRZCallRing3Disable(pVCpu);
5998 Assert(VMMR0IsLogFlushDisabled(pVCpu));
5999 Log4(("hmR0VmxCallRing3Callback->hmR0VmxLongJmpToRing3\n"));
6000 hmR0VmxLongJmpToRing3(pVCpu->CTX_SUFF(pVM), pVCpu, (PCPUMCTX)pvUser, VINF_VMM_UNKNOWN_RING3_CALL);
6001 VMMRZCallRing3Enable(pVCpu);
6002}
6003
6004
6005/**
6006 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
6007 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
6008 *
6009 * @returns VBox status code.
6010 * @param pVCpu Pointer to the VMCPU.
6011 */
6012DECLINLINE(void) hmR0VmxSetIntWindowExitVmcs(PVMCPU pVCpu)
6013{
6014 if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
6015 {
6016 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
6017 {
6018 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT;
6019 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
6020 AssertRC(rc);
6021 }
6022 } /* else we will deliver interrupts whenever the guest exits next and is in a state to receive events. */
6023}
6024
6025
6026/**
6027 * Injects any pending events into the guest if the guest is in a state to
6028 * receive them.
6029 *
6030 * @returns VBox status code (informational status codes included).
6031 * @param pVCpu Pointer to the VMCPU.
6032 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6033 * out-of-sync. Make sure to update the required fields
6034 * before using them.
6035 */
6036static int hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6037{
6038 /* Get the current interruptibility-state of the guest and then figure out what can be injected. */
6039 uint32_t uIntrState = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx);
6040 bool fBlockMovSS = !!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
6041 bool fBlockSti = !!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
6042
6043 Assert(!fBlockSti || (pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_RFLAGS));
6044 Assert( !(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI) /* We don't support block-by-NMI and SMI yet.*/
6045 && !(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI));
6046 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
6047 Assert(!TRPMHasTrap(pVCpu));
6048
6049 int rc = VINF_SUCCESS;
6050 if (pVCpu->hm.s.Event.fPending) /* First, inject any pending HM events. */
6051 {
6052 uint32_t uIntrType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hm.s.Event.u64IntrInfo);
6053 bool fInject = true;
6054 if (uIntrType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
6055 {
6056 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
6057 AssertRCReturn(rc, rc);
6058 const bool fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
6059 if ( fBlockInt
6060 || fBlockSti
6061 || fBlockMovSS)
6062 {
6063 fInject = false;
6064 }
6065 }
6066 else if ( uIntrType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
6067 && ( fBlockMovSS
6068 || fBlockSti))
6069 {
6070 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
6071 fInject = false;
6072 }
6073
6074 if (fInject)
6075 {
6076 Log4(("Injecting pending event\n"));
6077 rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, pVCpu->hm.s.Event.u64IntrInfo, pVCpu->hm.s.Event.cbInstr,
6078 pVCpu->hm.s.Event.u32ErrCode, pVCpu->hm.s.Event.GCPtrFaultAddress, &uIntrState);
6079 AssertRCReturn(rc, rc);
6080 pVCpu->hm.s.Event.fPending = false;
6081 STAM_COUNTER_INC(&pVCpu->hm.s.StatIntReinject);
6082 }
6083 else
6084 hmR0VmxSetIntWindowExitVmcs(pVCpu);
6085 } /** @todo SMI. SMIs take priority over NMIs. */
6086 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI)) /* NMI. NMIs take priority over regular interrupts . */
6087 {
6088 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
6089 if ( !fBlockMovSS
6090 && !fBlockSti)
6091 {
6092 Log4(("Injecting NMI\n"));
6093 uint32_t u32IntrInfo = X86_XCPT_NMI | VMX_EXIT_INTERRUPTION_INFO_VALID;
6094 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6095 rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */,
6096 0 /* GCPtrFaultAddress */, &uIntrState);
6097 AssertRCReturn(rc, rc);
6098 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
6099 }
6100 else
6101 hmR0VmxSetIntWindowExitVmcs(pVCpu);
6102 }
6103 else if (VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)))
6104 {
6105 /* Check if there are guest external interrupts (PIC/APIC) pending and inject them if the guest can receive them. */
6106 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
6107 AssertRCReturn(rc, rc);
6108 const bool fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
6109 if ( !fBlockInt
6110 && !fBlockSti
6111 && !fBlockMovSS)
6112 {
6113 uint8_t u8Interrupt;
6114 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
6115 if (RT_SUCCESS(rc))
6116 {
6117 Log4(("Injecting interrupt u8Interrupt=%#x\n", u8Interrupt));
6118 uint32_t u32IntrInfo = u8Interrupt | VMX_EXIT_INTERRUPTION_INFO_VALID;
6119 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6120 rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */,
6121 0 /* GCPtrFaultAddress */, &uIntrState);
6122 STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);
6123 }
6124 else
6125 {
6126 /** @todo Does this actually happen? If not turn it into an assertion. */
6127 Assert(!VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)));
6128 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
6129 rc = VINF_SUCCESS;
6130 }
6131 }
6132 else
6133 hmR0VmxSetIntWindowExitVmcs(pVCpu);
6134 }
6135
6136 /*
6137 * Delivery pending debug exception if the guest is single-stepping. The interruptibility-state could have been changed by
6138 * hmR0VmxInjectEventVmcs() (e.g. real-on-v86 injecting software interrupts), re-evaluate it and set the BS bit.
6139 */
6140 fBlockMovSS = !!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
6141 fBlockSti = !!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
6142 int rc2 = VINF_SUCCESS;
6143 if ( fBlockSti
6144 || fBlockMovSS)
6145 {
6146 if (!DBGFIsStepping(pVCpu))
6147 {
6148 Assert(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_RFLAGS);
6149 if (pMixedCtx->eflags.Bits.u1TF) /* We don't have any IA32_DEBUGCTL MSR for guests. Treat as all bits 0. */
6150 {
6151 /*
6152 * The pending-debug exceptions field is cleared on all VM-exits except VMX_EXIT_TPR_BELOW_THRESHOLD, VMX_EXIT_MTF
6153 * VMX_EXIT_APIC_WRITE, VMX_EXIT_VIRTUALIZED_EOI. See Intel spec. 27.3.4 "Saving Non-Register State".
6154 */
6155 rc2 = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_BS);
6156 AssertRCReturn(rc, rc);
6157 }
6158 }
6159 else
6160 {
6161 /* We are single-stepping in the hypervisor debugger, clear interrupt inhibition as setting the BS bit would mean
6162 delivering a #DB to the guest upon VM-entry when it shouldn't be. */
6163 uIntrState = 0;
6164 }
6165 }
6166
6167 /*
6168 * There's no need to clear the VM entry-interruption information field here if we're not injecting anything.
6169 * VT-x clears the valid bit on every VM-exit. See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
6170 */
6171 rc2 = hmR0VmxLoadGuestIntrState(pVCpu, uIntrState);
6172 AssertRC(rc2);
6173
6174 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RESET);
6175 return rc;
6176}
6177
6178
6179/**
6180 * Sets an invalid-opcode (#UD) exception as pending-for-injection into the VM.
6181 *
6182 * @param pVCpu Pointer to the VMCPU.
6183 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6184 * out-of-sync. Make sure to update the required fields
6185 * before using them.
6186 */
6187DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6188{
6189 uint32_t u32IntrInfo = X86_XCPT_UD | VMX_EXIT_INTERRUPTION_INFO_VALID;
6190 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6191}
6192
6193
6194/**
6195 * Injects a double-fault (#DF) exception into the VM.
6196 *
6197 * @returns VBox status code (informational status code included).
6198 * @param pVCpu Pointer to the VMCPU.
6199 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6200 * out-of-sync. Make sure to update the required fields
6201 * before using them.
6202 */
6203DECLINLINE(int) hmR0VmxInjectXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t *puIntrState)
6204{
6205 uint32_t u32IntrInfo = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
6206 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6207 u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
6208 return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */,
6209 puIntrState);
6210}
6211
6212
6213/**
6214 * Sets a debug (#DB) exception as pending-for-injection into the VM.
6215 *
6216 * @param pVCpu Pointer to the VMCPU.
6217 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6218 * out-of-sync. Make sure to update the required fields
6219 * before using them.
6220 */
6221DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6222{
6223 uint32_t u32IntrInfo = X86_XCPT_DB | VMX_EXIT_INTERRUPTION_INFO_VALID;
6224 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6225 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6226}
6227
6228
6229/**
6230 * Sets an overflow (#OF) exception as pending-for-injection into the VM.
6231 *
6232 * @param pVCpu Pointer to the VMCPU.
6233 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6234 * out-of-sync. Make sure to update the required fields
6235 * before using them.
6236 * @param cbInstr The value of RIP that is to be pushed on the guest
6237 * stack.
6238 */
6239DECLINLINE(void) hmR0VmxSetPendingXcptOF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
6240{
6241 uint32_t u32IntrInfo = X86_XCPT_OF | VMX_EXIT_INTERRUPTION_INFO_VALID;
6242 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6243 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6244}
6245
6246
6247/**
6248 * Injects a general-protection (#GP) fault into the VM.
6249 *
6250 * @returns VBox status code (informational status code included).
6251 * @param pVCpu Pointer to the VMCPU.
6252 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6253 * out-of-sync. Make sure to update the required fields
6254 * before using them.
6255 * @param u32ErrorCode The error code associated with the #GP.
6256 */
6257DECLINLINE(int) hmR0VmxInjectXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fErrorCodeValid, uint32_t u32ErrorCode,
6258 uint32_t *puIntrState)
6259{
6260 uint32_t u32IntrInfo = X86_XCPT_GP | VMX_EXIT_INTERRUPTION_INFO_VALID;
6261 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6262 if (fErrorCodeValid)
6263 u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
6264 return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */,
6265 puIntrState);
6266}
6267
6268
6269/**
6270 * Sets a software interrupt (INTn) as pending-for-injection into the VM.
6271 *
6272 * @param pVCpu Pointer to the VMCPU.
6273 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6274 * out-of-sync. Make sure to update the required fields
6275 * before using them.
6276 * @param uVector The software interrupt vector number.
6277 * @param cbInstr The value of RIP that is to be pushed on the guest
6278 * stack.
6279 */
6280DECLINLINE(void) hmR0VmxSetPendingIntN(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint16_t uVector, uint32_t cbInstr)
6281{
6282 uint32_t u32IntrInfo = uVector | VMX_EXIT_INTERRUPTION_INFO_VALID;
6283 if ( uVector == X86_XCPT_BP
6284 || uVector == X86_XCPT_OF)
6285 {
6286 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6287 }
6288 else
6289 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6290 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
6291}
6292
6293
6294/**
6295 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
6296 * stack.
6297 *
6298 * @returns VBox status code (information status code included).
6299 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
6300 * @param pVM Pointer to the VM.
6301 * @param pMixedCtx Pointer to the guest-CPU context.
6302 * @param uValue The value to push to the guest stack.
6303 */
6304DECLINLINE(int) hmR0VmxRealModeGuestStackPush(PVM pVM, PCPUMCTX pMixedCtx, uint16_t uValue)
6305{
6306 /*
6307 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
6308 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
6309 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
6310 */
6311 if (pMixedCtx->sp == 1)
6312 return VINF_EM_RESET;
6313 pMixedCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
6314 int rc = PGMPhysSimpleWriteGCPhys(pVM, pMixedCtx->ss.u64Base + pMixedCtx->sp, &uValue, sizeof(uint16_t));
6315 AssertRCReturn(rc, rc);
6316 return rc;
6317}
6318
6319
6320/**
6321 * Injects an event into the guest upon VM-entry by updating the relevant fields
6322 * in the VM-entry area in the VMCS.
6323 *
6324 * @returns VBox status code (informational error codes included).
6325 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
6326 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
6327 *
6328 * @param pVCpu Pointer to the VMCPU.
6329 * @param pMixedCtx Pointer to the guest-CPU context. The data may
6330 * be out-of-sync. Make sure to update the required
6331 * fields before using them.
6332 * @param u64IntrInfo The VM-entry interruption-information field.
6333 * @param cbInstr The VM-entry instruction length in bytes (for
6334 * software interrupts, exceptions and privileged
6335 * software exceptions).
6336 * @param u32ErrCode The VM-entry exception error code.
6337 * @param GCPtrFaultAddress The page-fault address for #PF exceptions.
6338 * @param puIntrState Pointer to the current guest interruptibility-state.
6339 * This interruptibility-state will be updated if
6340 * necessary. This cannot not be NULL.
6341 *
6342 * @remarks No-long-jump zone!!!
6343 * @remarks Requires CR0!
6344 */
6345static int hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntrInfo, uint32_t cbInstr,
6346 uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, uint32_t *puIntrState)
6347{
6348 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
6349 AssertMsg(u64IntrInfo >> 32 == 0, ("%#RX64\n", u64IntrInfo));
6350 Assert(puIntrState);
6351 uint32_t u32IntrInfo = (uint32_t)u64IntrInfo;
6352
6353 const uint32_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(u32IntrInfo);
6354 const uint32_t uIntrType = VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntrInfo);
6355
6356 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
6357 Assert( uIntrType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
6358 || !(*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS));
6359
6360 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
6361
6362 /* We require CR0 to check if the guest is in real-mode. */
6363 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6364 AssertRCReturn(rc, rc);
6365
6366 /*
6367 * Hardware interrupts & exceptions cannot be delivered through the software interrupt redirection bitmap to the real
6368 * mode task in virtual-8086 mode. We must jump to the interrupt handler in the (real-mode) guest.
6369 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode" for interrupt & exception classes.
6370 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
6371 */
6372 if (CPUMIsGuestInRealModeEx(pMixedCtx))
6373 {
6374 PVM pVM = pVCpu->CTX_SUFF(pVM);
6375 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
6376 {
6377 Assert(PDMVmmDevHeapIsEnabled(pVM));
6378 Assert(pVM->hm.s.vmx.pRealModeTSS);
6379
6380 /* We require RIP, RSP, RFLAGS, CS, IDTR. Save the required ones from the VMCS. */
6381 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
6382 rc |= hmR0VmxSaveGuestTableRegs(pVCpu, pMixedCtx);
6383 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
6384 AssertRCReturn(rc, rc);
6385 Assert(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_RIP);
6386
6387 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
6388 const size_t cbIdtEntry = 4;
6389 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pMixedCtx->idtr.cbIdt)
6390 {
6391 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
6392 if (uVector == X86_XCPT_DF)
6393 return VINF_EM_RESET;
6394 else if (uVector == X86_XCPT_GP)
6395 {
6396 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault. */
6397 return hmR0VmxInjectXcptDF(pVCpu, pMixedCtx, puIntrState);
6398 }
6399
6400 /* If we're injecting an interrupt/exception with no valid IDT entry, inject a general-protection fault. */
6401 /* No error codes for exceptions in real-mode. See Intel spec. 20.1.4 "Interrupt and Exception Handling" */
6402 return hmR0VmxInjectXcptGP(pVCpu, pMixedCtx, false /* fErrCodeValid */, 0 /* u32ErrCode */, puIntrState);
6403 }
6404
6405 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
6406 uint16_t uGuestIp = pMixedCtx->ip;
6407 if (VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntrInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT)
6408 {
6409 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
6410 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
6411 uGuestIp = pMixedCtx->ip + (uint16_t)cbInstr;
6412 }
6413 else if (VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntrInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT)
6414 uGuestIp = pMixedCtx->ip + (uint16_t)cbInstr;
6415
6416 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
6417 uint16_t offIdtEntry = 0;
6418 RTSEL selIdtEntry = 0;
6419 RTGCPHYS GCPhysIdtEntry = (RTGCPHYS)pMixedCtx->idtr.pIdt + uVector * cbIdtEntry;
6420 rc = PGMPhysSimpleReadGCPhys(pVM, &offIdtEntry, GCPhysIdtEntry, sizeof(offIdtEntry));
6421 rc |= PGMPhysSimpleReadGCPhys(pVM, &selIdtEntry, GCPhysIdtEntry + 2, sizeof(selIdtEntry));
6422 AssertRCReturn(rc, rc);
6423
6424 /* Construct the stack frame for the interrupt/exception handler. */
6425 rc = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, pMixedCtx->eflags.u32);
6426 rc |= hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, pMixedCtx->cs.Sel);
6427 rc |= hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, uGuestIp);
6428 AssertRCReturn(rc, rc);
6429
6430 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
6431 if (rc == VINF_SUCCESS)
6432 {
6433 pMixedCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
6434 pMixedCtx->rip = offIdtEntry;
6435 pMixedCtx->cs.Sel = selIdtEntry;
6436 pMixedCtx->cs.u64Base = selIdtEntry << cbIdtEntry;
6437 if ( VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntrInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
6438 && uVector == X86_XCPT_PF)
6439 {
6440 pMixedCtx->cr2 = GCPtrFaultAddress;
6441 }
6442 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_SEGMENT_REGS
6443 | HM_CHANGED_GUEST_RIP
6444 | HM_CHANGED_GUEST_RFLAGS
6445 | HM_CHANGED_GUEST_RSP;
6446
6447 /* We're clearing interrupts, which means no block-by-STI interrupt-inhibition. */
6448 if (*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
6449 {
6450 Assert( uIntrType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
6451 && uIntrType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
6452 Log4(("Clearing inhibition due to STI.\n"));
6453 *puIntrState &= ~VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
6454 }
6455 Log4(("Injecting real-mode: u32IntrInfo=%#x u32ErrCode=%#x instrlen=%#x\n", u32IntrInfo, u32ErrCode, cbInstr));
6456 }
6457 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RESET);
6458 return rc;
6459 }
6460 else
6461 {
6462 /*
6463 * For unrestricted execution enabled CPUs running real-mode guests, we must not set the deliver-error-code bit.
6464 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
6465 */
6466 u32IntrInfo &= ~VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
6467 }
6468 }
6469
6470 /* Validate. */
6471 Assert(VMX_EXIT_INTERRUPTION_INFO_IS_VALID(u32IntrInfo)); /* Bit 31 (Valid bit) must be set by caller. */
6472 Assert(!VMX_EXIT_INTERRUPTION_INFO_NMI_UNBLOCK(u32IntrInfo)); /* Bit 12 MBZ. */
6473 Assert(!(u32IntrInfo & 0x7ffff000)); /* Bits 30:12 MBZ. */
6474
6475 /* Inject. */
6476 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntrInfo);
6477 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(u32IntrInfo))
6478 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
6479 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
6480
6481 if ( VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntrInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
6482 && uVector == X86_XCPT_PF)
6483 {
6484 pMixedCtx->cr2 = GCPtrFaultAddress;
6485 }
6486
6487 Log4(("Injecting u32IntrInfo=%#x u32ErrCode=%#x cbInstr=%#x pMixedCtx->uCR2=%#RX64\n", u32IntrInfo, u32ErrCode, cbInstr,
6488 pMixedCtx->cr2));
6489
6490 AssertRCReturn(rc, rc);
6491 return rc;
6492}
6493
6494
6495/**
6496 * Enters the VT-x session.
6497 *
6498 * @returns VBox status code.
6499 * @param pVM Pointer to the VM.
6500 * @param pVCpu Pointer to the VMCPU.
6501 * @param pCpu Pointer to the CPU info struct.
6502 */
6503VMMR0DECL(int) VMXR0Enter(PVM pVM, PVMCPU pVCpu, PHMGLOBLCPUINFO pCpu)
6504{
6505 AssertPtr(pVM);
6506 AssertPtr(pVCpu);
6507 Assert(pVM->hm.s.vmx.fSupported);
6508 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
6509 NOREF(pCpu);
6510
6511 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
6512
6513 /* Make sure we're in VMX root mode. */
6514 RTCCUINTREG u32HostCR4 = ASMGetCR4();
6515 if (!(u32HostCR4 & X86_CR4_VMXE))
6516 {
6517 LogRel(("VMXR0Enter: X86_CR4_VMXE bit in CR4 is not set!\n"));
6518 return VERR_VMX_X86_CR4_VMXE_CLEARED;
6519 }
6520
6521 /* Load the active VMCS as the current one. */
6522 int rc = VMXActivateVMCS(pVCpu->hm.s.vmx.HCPhysVmcs);
6523 if (RT_FAILURE(rc))
6524 return rc;
6525
6526 /** @todo this will change with preemption hooks where can can VMRESUME as long
6527 * as we're no preempted. */
6528 pVCpu->hm.s.fResumeVM = false;
6529 return VINF_SUCCESS;
6530}
6531
6532
6533/**
6534 * Leaves the VT-x session.
6535 *
6536 * @returns VBox status code.
6537 * @param pVM Pointer to the VM.
6538 * @param pVCpu Pointer to the VMCPU.
6539 * @param pCtx Pointer to the guest-CPU context.
6540 */
6541VMMR0DECL(int) VMXR0Leave(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
6542{
6543 AssertPtr(pVCpu);
6544 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
6545 NOREF(pVM);
6546 NOREF(pCtx);
6547
6548 /** @todo this will change with preemption hooks where we only VMCLEAR when
6549 * we are actually going to be preempted, not all the time like we
6550 * currently do. */
6551
6552 /* Restore host-state bits that VT-x only restores partially. */
6553 if (pVCpu->hm.s.vmx.fRestoreHostFlags)
6554 {
6555#ifndef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
6556 /** @todo r=ramshankar: This is broken when
6557 * VBOX_WITH_VMMR0_DISABLE_PREEMPTION is not defined. As
6558 * VMXRestoreHostState() may unconditionally enables interrupts. */
6559#error "VMM: Fix Me! Make VMXRestoreHostState() function to skip cli/sti."
6560#else
6561 Assert(ASMIntAreEnabled());
6562 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
6563#endif
6564 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
6565 }
6566
6567 /*
6568 * Sync the current VMCS (writes back internal data back into the VMCS region in memory)
6569 * and mark the VMCS launch-state as "clear".
6570 */
6571 int rc = VMXClearVMCS(pVCpu->hm.s.vmx.HCPhysVmcs);
6572 return rc;
6573}
6574
6575
6576/**
6577 * Saves the host state in the VMCS host-state.
6578 * Sets up the VM-exit MSR-load area.
6579 *
6580 * The CPU state will be loaded from these fields on every successful VM-exit.
6581 *
6582 * @returns VBox status code.
6583 * @param pVM Pointer to the VM.
6584 * @param pVCpu Pointer to the VMCPU.
6585 *
6586 * @remarks No-long-jump zone!!!
6587 */
6588VMMR0DECL(int) VMXR0SaveHostState(PVM pVM, PVMCPU pVCpu)
6589{
6590 AssertPtr(pVM);
6591 AssertPtr(pVCpu);
6592 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
6593
6594 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
6595
6596 /* Nothing to do if the host-state-changed flag isn't set. This will later be optimized when preemption hooks are in place. */
6597 if (!(pVCpu->hm.s.fContextUseFlags & HM_CHANGED_HOST_CONTEXT))
6598 return VINF_SUCCESS;
6599
6600 int rc = hmR0VmxSaveHostControlRegs(pVM, pVCpu);
6601 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostControlRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6602
6603 rc = hmR0VmxSaveHostSegmentRegs(pVM, pVCpu);
6604 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostSegmentRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6605
6606 rc = hmR0VmxSaveHostMsrs(pVM, pVCpu);
6607 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostMsrs failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6608
6609 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_HOST_CONTEXT;
6610 return rc;
6611}
6612
6613
6614/**
6615 * Loads the guest state into the VMCS guest-state area. The CPU state will be
6616 * loaded from these fields on every successful VM-entry.
6617 *
6618 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas.
6619 * Sets up the VM-entry controls.
6620 * Sets up the appropriate VMX non-root function to execute guest code based on
6621 * the guest CPU mode.
6622 *
6623 * @returns VBox status code.
6624 * @param pVM Pointer to the VM.
6625 * @param pVCpu Pointer to the VMCPU.
6626 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6627 * out-of-sync. Make sure to update the required fields
6628 * before using them.
6629 *
6630 * @remarks No-long-jump zone!!!
6631 */
6632VMMR0DECL(int) VMXR0LoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6633{
6634 AssertPtr(pVM);
6635 AssertPtr(pVCpu);
6636 AssertPtr(pMixedCtx);
6637 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
6638
6639 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
6640
6641 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestState, x);
6642
6643 /* Determine real-on-v86 mode. */
6644 pVCpu->hm.s.vmx.RealMode.fRealOnV86Active = false;
6645 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
6646 && CPUMIsGuestInRealModeEx(pMixedCtx))
6647 {
6648 pVCpu->hm.s.vmx.RealMode.fRealOnV86Active = true;
6649 }
6650
6651 /*
6652 * Load the guest-state into the VMCS.
6653 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
6654 * Ideally, assert that the cross-dependent bits are up to date at the point of using it.
6655 */
6656 int rc = hmR0VmxLoadGuestEntryCtls(pVCpu, pMixedCtx);
6657 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestEntryCtls! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6658
6659 rc = hmR0VmxLoadGuestExitCtls(pVCpu, pMixedCtx);
6660 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupExitCtls failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6661
6662 rc = hmR0VmxLoadGuestActivityState(pVCpu, pMixedCtx);
6663 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestActivityState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6664
6665 rc = hmR0VmxLoadGuestControlRegs(pVCpu, pMixedCtx);
6666 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestControlRegs: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6667
6668 /* Must be done after CR0 is loaded (strict builds require CR0 for segment register validation checks). */
6669 rc = hmR0VmxLoadGuestSegmentRegs(pVCpu, pMixedCtx);
6670 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestSegmentRegs: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6671
6672 rc = hmR0VmxLoadGuestDebugRegs(pVCpu, pMixedCtx);
6673 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestDebugRegs: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6674
6675 rc = hmR0VmxLoadGuestMsrs(pVCpu, pMixedCtx);
6676 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestMsrs! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6677
6678 rc = hmR0VmxLoadGuestApicState(pVCpu, pMixedCtx);
6679 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestApicState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6680
6681 /* Must be done after hmR0VmxLoadGuestDebugRegs() as it may update eflags.TF for debugging purposes. */
6682 rc = hmR0VmxLoadGuestRipRspRflags(pVCpu, pMixedCtx);
6683 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestGprs! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6684
6685 rc = hmR0VmxSetupVMRunHandler(pVCpu, pMixedCtx);
6686 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupVMRunHandler! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
6687
6688 /* Clear the currently unused reserved bits. */
6689 pVCpu->hm.s.fContextUseFlags &= ~( HM_CHANGED_VMX_RESERVED1
6690 | HM_CHANGED_VMX_RESERVED2);
6691
6692 AssertMsg(!pVCpu->hm.s.fContextUseFlags,
6693 ("Missed updating flags while loading guest state. pVM=%p pVCpu=%p fContextUseFlags=%#RX32\n",
6694 pVM, pVCpu, pVCpu->hm.s.fContextUseFlags));
6695
6696 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
6697 return rc;
6698}
6699
6700
6701/**
6702 * Does the preparations before executing guest code in VT-x.
6703 *
6704 * This may cause longjmps to ring-3 and may even result in rescheduling to the
6705 * recompiler. We must be cautious what we do here regarding committing
6706 * guest-state information into the the VMCS assuming we assuredly execute the
6707 * guest in VT-x. If we fall back to the recompiler after updating VMCS and
6708 * clearing the common-state (TRPM/forceflags), we must undo those changes so
6709 * that the recompiler can (and should) use them when it resumes guest
6710 * execution. Otherwise such operations must be done when we can no longer
6711 * exit to ring-3.
6712 *
6713 * @returns VBox status code (informational status codes included).
6714 * @retval VINF_SUCCESS if we can proceed with running the guest.
6715 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a double-fault
6716 * into the guest.
6717 * @retval VINF_* scheduling changes, we have to go back to ring-3.
6718 *
6719 * @param pVM Pointer to the VM.
6720 * @param pVCpu Pointer to the VMCPU.
6721 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6722 * out-of-sync. Make sure to update the required fields
6723 * before using them.
6724 * @param pVmxTransient Pointer to the VMX transient structure.
6725 *
6726 * @remarks Called with preemption disabled.
6727 */
6728DECLINLINE(int) hmR0VmxPreRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
6729{
6730 Assert(VMMRZCallRing3IsEnabled(pVCpu));
6731
6732#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
6733 PGMRZDynMapFlushAutoSet(pVCpu);
6734#endif
6735
6736 /* Check force flag actions that might require us to go back to ring-3. */
6737 int rc = hmR0VmxCheckForceFlags(pVM, pVCpu, pMixedCtx);
6738 if (rc != VINF_SUCCESS)
6739 return rc;
6740
6741 /* Setup the Virtualized APIC accesses. pMixedCtx->msrApicBase is always up-to-date. It's not part of the VMCS. */
6742 if ( pVCpu->hm.s.vmx.u64MsrApicBase != pMixedCtx->msrApicBase
6743 && (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC))
6744 {
6745 Assert(pVM->hm.s.vmx.HCPhysApicAccess);
6746 RTGCPHYS GCPhysApicBase;
6747 GCPhysApicBase = pMixedCtx->msrApicBase;
6748 GCPhysApicBase &= PAGE_BASE_GC_MASK;
6749
6750 /* Unalias any existing mapping. */
6751 rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
6752 AssertRCReturn(rc, rc);
6753
6754 /* Map the HC APIC-access page into the GC space, this also updates the shadow page tables if necessary. */
6755 Log4(("Mapped HC APIC-access page into GC: GCPhysApicBase=%#RGv\n", GCPhysApicBase));
6756 rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
6757 AssertRCReturn(rc, rc);
6758
6759 pVCpu->hm.s.vmx.u64MsrApicBase = pMixedCtx->msrApicBase;
6760 }
6761
6762#ifdef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
6763 /* We disable interrupts so that we don't miss any interrupts that would flag preemption (IPI/timers etc.) */
6764 pVmxTransient->uEFlags = ASMIntDisableFlags();
6765 if (RTThreadPreemptIsPending(NIL_RTTHREAD))
6766 {
6767 ASMSetFlags(pVmxTransient->uEFlags);
6768 STAM_COUNTER_INC(&pVCpu->hm.s.StatPendingHostIrq);
6769 /* Don't use VINF_EM_RAW_INTERRUPT_HYPER as we can't assume the host does kernel preemption. Maybe some day? */
6770 return VINF_EM_RAW_INTERRUPT;
6771 }
6772 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
6773 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
6774#endif
6775
6776 /*
6777 * Evaluates and injects any pending events, toggling force-flags and updating the guest-interruptibility
6778 * state (interrupt shadow) in the VMCS. This -can- potentially be reworked to be done before disabling
6779 * interrupts and handle returning to ring-3 afterwards, but requires very careful state restoration.
6780 */
6781 /** @todo Rework event evaluation and injection to be completely separate. */
6782 if (TRPMHasTrap(pVCpu))
6783 hmR0VmxTRPMTrapToPendingEvent(pVCpu);
6784
6785 rc = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx);
6786 AssertRCReturn(rc, rc);
6787 return rc;
6788}
6789
6790
6791/**
6792 * Prepares to run guest code in VT-x and we've committed to doing so. This
6793 * means there is no backing out to ring-3 or anywhere else at this
6794 * point.
6795 *
6796 * @param pVM Pointer to the VM.
6797 * @param pVCpu Pointer to the VMCPU.
6798 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6799 * out-of-sync. Make sure to update the required fields
6800 * before using them.
6801 * @param pVmxTransient Pointer to the VMX transient structure.
6802 *
6803 * @remarks Called with preemption disabled.
6804 * @remarks No-long-jump zone!!!
6805 */
6806DECLINLINE(void) hmR0VmxPreRunGuestCommitted(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
6807{
6808 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
6809 Assert(VMMR0IsLogFlushDisabled(pVCpu));
6810
6811#ifndef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
6812 /** @todo I don't see the point of this, VMMR0EntryFast() already disables interrupts for the entire period. */
6813 pVmxTransient->uEFlags = ASMIntDisableFlags();
6814 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
6815#endif
6816
6817 /* Load the required guest state bits (for guest-state changes in the inner execution loop). */
6818 Assert(!(pVCpu->hm.s.fContextUseFlags & HM_CHANGED_HOST_CONTEXT));
6819 Log5(("LoadFlags=%#RX32\n", pVCpu->hm.s.fContextUseFlags));
6820#ifdef HMVMX_SYNC_FULL_GUEST_STATE
6821 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_ALL_GUEST;
6822#endif
6823 int rc = VINF_SUCCESS;
6824 if (pVCpu->hm.s.fContextUseFlags == HM_CHANGED_GUEST_RIP)
6825 {
6826 rc = hmR0VmxLoadGuestRip(pVCpu, pMixedCtx);
6827 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadMinimal);
6828 }
6829 else if (pVCpu->hm.s.fContextUseFlags)
6830 {
6831 rc = VMXR0LoadGuestState(pVM, pVCpu, pMixedCtx);
6832 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadFull);
6833 }
6834 AssertRC(rc);
6835 AssertMsg(!pVCpu->hm.s.fContextUseFlags, ("fContextUseFlags =%#x\n", pVCpu->hm.s.fContextUseFlags));
6836
6837 /* Cache the TPR-shadow for checking on every VM-exit if it might have changed. */
6838 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
6839 pVmxTransient->u8GuestTpr = pVCpu->hm.s.vmx.pbVirtApic[0x80];
6840
6841 if ( pVmxTransient->fUpdateTscOffsettingAndPreemptTimer
6842 || HMR0GetCurrentCpu()->idCpu != pVCpu->hm.s.idLastCpu)
6843 {
6844 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pMixedCtx);
6845 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = false;
6846 }
6847
6848 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB-shootdowns, set this across the world switch. */
6849 hmR0VmxFlushTaggedTlb(pVCpu); /* Invalidate the appropriate guest entries from the TLB. */
6850 Assert(HMR0GetCurrentCpu()->idCpu == pVCpu->hm.s.idLastCpu);
6851
6852 /*
6853 * TPR patching (only active for 32-bit guests on 64-bit capable CPUs) when the CPU does not supported virtualizing
6854 * APIC accesses feature (VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC).
6855 */
6856 if (pVM->hm.s.fTPRPatchingActive)
6857 {
6858 Assert(!CPUMIsGuestInLongMode(pVCpu));
6859
6860 /* Need guest's LSTAR MSR (which is part of the auto load/store MSRs in the VMCS), ensure we have the updated one. */
6861 rc = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
6862 AssertRC(rc);
6863
6864 /* The patch code uses the LSTAR as it's not used by a guest in 32-bit mode implicitly (i.e. SYSCALL is 64-bit only). */
6865 pVmxTransient->u64LStarMsr = ASMRdMsr(MSR_K8_LSTAR);
6866 ASMWrMsr(MSR_K8_LSTAR, pMixedCtx->msrLSTAR); /* pMixedCtx->msrLSTAR contains the guest's TPR,
6867 see hmR0VmxLoadGuestApicState(). */
6868 }
6869
6870#ifndef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
6871 /*
6872 * Save the current Host TSC_AUX and write the guest TSC_AUX to the host, so that
6873 * RDTSCPs (that don't cause exits) reads the guest MSR. See @bugref{3324}.
6874 */
6875 if ( (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP)
6876 && !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
6877 {
6878 pVCpu->hm.s.u64HostTscAux = ASMRdMsr(MSR_K8_TSC_AUX);
6879 uint64_t u64HostTscAux = 0;
6880 int rc2 = CPUMQueryGuestMsr(pVCpu, MSR_K8_TSC_AUX, &u64HostTscAux);
6881 AssertRC(rc2);
6882 ASMWrMsr(MSR_K8_TSC_AUX, u64HostTscAux);
6883 }
6884#endif
6885
6886 TMNotifyStartOfExecution(pVCpu); /* Finally, notify TM to resume its clocks as we're about
6887 to start executing. */
6888 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
6889}
6890
6891
6892/**
6893 * Performs some essential restoration of state after running guest code in
6894 * VT-x.
6895 *
6896 * @param pVM Pointer to the VM.
6897 * @param pVCpu Pointer to the VMCPU.
6898 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6899 * out-of-sync. Make sure to update the required fields
6900 * before using them.
6901 * @param pVmxTransient Pointer to the VMX transient structure.
6902 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
6903 *
6904 * @remarks Called with interrupts disabled.
6905 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
6906 * unconditionally when it is safe to do so.
6907 */
6908DECLINLINE(void) hmR0VmxPostRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, int rcVMRun)
6909{
6910 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
6911 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatExit1, x);
6912
6913 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB-shootdowns. */
6914 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for TLB-shootdowns. */
6915 pVCpu->hm.s.vmx.fUpdatedGuestState = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
6916 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
6917 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
6918
6919 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
6920 {
6921#ifndef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
6922 /* Restore host's TSC_AUX. */
6923 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP)
6924 ASMWrMsr(MSR_K8_TSC_AUX, pVCpu->hm.s.u64HostTscAux);
6925#endif
6926 /** @todo Find a way to fix hardcoding a guestimate. */
6927 TMCpuTickSetLastSeen(pVCpu, ASMReadTSC()
6928 + pVCpu->hm.s.vmx.u64TSCOffset - 0x400 /* guestimate of world switch overhead in clock ticks */);
6929 }
6930
6931 TMNotifyEndOfExecution(pVCpu); /* Notify TM that the guest is no longer running. */
6932 Assert(!(ASMGetFlags() & X86_EFL_IF));
6933 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
6934
6935 /* Restore the effects of TPR patching if any. */
6936 if (pVM->hm.s.fTPRPatchingActive)
6937 {
6938 int rc = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
6939 AssertRC(rc);
6940 pMixedCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR); /* MSR_K8_LSTAR contains the guest TPR. */
6941 ASMWrMsr(MSR_K8_LSTAR, pVmxTransient->u64LStarMsr);
6942 }
6943
6944 ASMSetFlags(pVmxTransient->uEFlags); /* Enable interrupts. */
6945 pVCpu->hm.s.fResumeVM = true; /* Use VMRESUME instead of VMLAUNCH in the next run. */
6946
6947 /* Save the basic VM-exit reason. Refer Intel spec. 24.9.1 "Basic VM-exit Information". */
6948 uint32_t uExitReason;
6949 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
6950 rc |= hmR0VmxReadEntryIntrInfoVmcs(pVmxTransient);
6951 AssertRC(rc);
6952 pVmxTransient->uExitReason = (uint16_t)VMX_EXIT_REASON_BASIC(uExitReason);
6953 pVmxTransient->fVMEntryFailed = !!VMX_ENTRY_INTERRUPTION_INFO_VALID(pVmxTransient->uEntryIntrInfo);
6954
6955 VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pMixedCtx);
6956 VMMRZCallRing3Enable(pVCpu); /* It is now safe to do longjmps to ring-3!!! */
6957
6958 /* If the VMLAUNCH/VMRESUME failed, we can bail out early. This does -not- cover VMX_EXIT_ERR_*. */
6959 if (RT_UNLIKELY(rcVMRun != VINF_SUCCESS))
6960 {
6961 Log4(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
6962 return;
6963 }
6964
6965 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
6966 {
6967 /* Update the guest interruptibility-state from the VMCS. */
6968 hmR0VmxSaveGuestIntrState(pVCpu, pMixedCtx);
6969#if defined(HMVMX_SYNC_FULL_GUEST_STATE) || defined(HMVMX_SAVE_FULL_GUEST_STATE)
6970 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
6971 AssertRC(rc);
6972#endif
6973 /*
6974 * If the TPR was raised by the guest, it wouldn't cause a VM-exit immediately. Instead we sync the TPR lazily whenever
6975 * we eventually get a VM-exit for any reason. This maybe expensive as PDMApicSetTPR() can longjmp to ring-3 and which is
6976 * why it's done here as it's easier and no less efficient to deal with it here than making hmR0VmxSaveGuestState()
6977 * cope with longjmps safely (see VMCPU_FF_HM_UPDATE_CR3 handling).
6978 */
6979 if ( (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
6980 && pVmxTransient->u8GuestTpr != pVCpu->hm.s.vmx.pbVirtApic[0x80])
6981 {
6982 rc = PDMApicSetTPR(pVCpu, pVCpu->hm.s.vmx.pbVirtApic[0x80]);
6983 AssertRC(rc);
6984 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_VMX_GUEST_APIC_STATE;
6985 }
6986 }
6987}
6988
6989
6990/**
6991 * Runs the guest code using VT-x.
6992 *
6993 * @returns VBox status code.
6994 * @param pVM Pointer to the VM.
6995 * @param pVCpu Pointer to the VMCPU.
6996 * @param pCtx Pointer to the guest-CPU context.
6997 *
6998 * @remarks Called with preemption disabled.
6999 */
7000VMMR0DECL(int) VMXR0RunGuestCode(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
7001{
7002 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7003 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7004
7005 VMXTRANSIENT VmxTransient;
7006 VmxTransient.fUpdateTscOffsettingAndPreemptTimer = true;
7007 int rc = VERR_INTERNAL_ERROR_5;
7008 uint32_t cLoops = 0;
7009
7010 for (;; cLoops++)
7011 {
7012 Assert(!HMR0SuspendPending());
7013 AssertMsg(pVCpu->hm.s.idEnteredCpu == RTMpCpuId(),
7014 ("Illegal migration! Entered on CPU %u Current %u cLoops=%u\n", (unsigned)pVCpu->hm.s.idEnteredCpu,
7015 (unsigned)RTMpCpuId(), cLoops));
7016
7017 /* Preparatory work for running guest code, this may return to ring-3 for some last minute updates. */
7018 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
7019 rc = hmR0VmxPreRunGuest(pVM, pVCpu, pCtx, &VmxTransient);
7020 if (rc != VINF_SUCCESS)
7021 break;
7022
7023 /*
7024 * No longjmps to ring-3 from this point on!!!
7025 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
7026 * This also disables flushing of the R0-logger instance (if any).
7027 */
7028 VMMRZCallRing3Disable(pVCpu);
7029 VMMRZCallRing3RemoveNotification(pVCpu);
7030 hmR0VmxPreRunGuestCommitted(pVM, pVCpu, pCtx, &VmxTransient);
7031
7032 rc = hmR0VmxRunGuest(pVM, pVCpu, pCtx);
7033 /* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
7034
7035 /*
7036 * Restore any residual host-state and save any bits shared between host and guest into the guest-CPU state.
7037 * This will also re-enable longjmps to ring-3 when it has reached a safe point!!!
7038 */
7039 hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, rc);
7040 if (RT_UNLIKELY(rc != VINF_SUCCESS)) /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
7041 {
7042 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
7043 hmR0VmxReportWorldSwitchError(pVM, pVCpu, rc, pCtx, &VmxTransient);
7044 return rc;
7045 }
7046
7047 /* Handle the VM-exit. */
7048 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
7049 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
7050 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
7051 HMVMX_START_EXIT_DISPATCH_PROF();
7052#ifdef HMVMX_USE_FUNCTION_TABLE
7053 rc = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, pCtx, &VmxTransient);
7054#else
7055 rc = hmR0VmxHandleExit(pVCpu, pCtx, &VmxTransient, VmxTransient.uExitReason);
7056#endif
7057 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
7058 if (rc != VINF_SUCCESS)
7059 break;
7060 else if (cLoops > pVM->hm.s.cMaxResumeLoops)
7061 {
7062 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMaxResume);
7063 rc = VINF_EM_RAW_INTERRUPT;
7064 break;
7065 }
7066 }
7067
7068 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
7069 if (rc == VERR_EM_INTERPRETER)
7070 rc = VINF_EM_RAW_EMULATE_INSTR;
7071 else if (rc == VINF_EM_RESET)
7072 rc = VINF_EM_TRIPLE_FAULT;
7073 hmR0VmxExitToRing3(pVM, pVCpu, pCtx, rc);
7074 return rc;
7075}
7076
7077
7078#ifndef HMVMX_USE_FUNCTION_TABLE
7079DECLINLINE(int) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason)
7080{
7081 int rc;
7082 switch (rcReason)
7083 {
7084 case VMX_EXIT_EPT_MISCONFIG: rc = hmR0VmxExitEptMisconfig(pVCpu, pMixedCtx, pVmxTransient); break;
7085 case VMX_EXIT_EPT_VIOLATION: rc = hmR0VmxExitEptViolation(pVCpu, pMixedCtx, pVmxTransient); break;
7086 case VMX_EXIT_IO_INSTR: rc = hmR0VmxExitIoInstr(pVCpu, pMixedCtx, pVmxTransient); break;
7087 case VMX_EXIT_CPUID: rc = hmR0VmxExitCpuid(pVCpu, pMixedCtx, pVmxTransient); break;
7088 case VMX_EXIT_RDTSC: rc = hmR0VmxExitRdtsc(pVCpu, pMixedCtx, pVmxTransient); break;
7089 case VMX_EXIT_RDTSCP: rc = hmR0VmxExitRdtscp(pVCpu, pMixedCtx, pVmxTransient); break;
7090 case VMX_EXIT_APIC_ACCESS: rc = hmR0VmxExitApicAccess(pVCpu, pMixedCtx, pVmxTransient); break;
7091 case VMX_EXIT_XCPT_NMI: rc = hmR0VmxExitXcptNmi(pVCpu, pMixedCtx, pVmxTransient); break;
7092 case VMX_EXIT_MOV_CRX: rc = hmR0VmxExitMovCRx(pVCpu, pMixedCtx, pVmxTransient); break;
7093 case VMX_EXIT_EXT_INT: rc = hmR0VmxExitExtInt(pVCpu, pMixedCtx, pVmxTransient); break;
7094 case VMX_EXIT_INT_WINDOW: rc = hmR0VmxExitIntWindow(pVCpu, pMixedCtx, pVmxTransient); break;
7095 case VMX_EXIT_MWAIT: rc = hmR0VmxExitMwait(pVCpu, pMixedCtx, pVmxTransient); break;
7096 case VMX_EXIT_MONITOR: rc = hmR0VmxExitMonitor(pVCpu, pMixedCtx, pVmxTransient); break;
7097 case VMX_EXIT_TASK_SWITCH: rc = hmR0VmxExitTaskSwitch(pVCpu, pMixedCtx, pVmxTransient); break;
7098 case VMX_EXIT_PREEMPT_TIMER: rc = hmR0VmxExitPreemptTimer(pVCpu, pMixedCtx, pVmxTransient); break;
7099 case VMX_EXIT_RDMSR: rc = hmR0VmxExitRdmsr(pVCpu, pMixedCtx, pVmxTransient); break;
7100 case VMX_EXIT_WRMSR: rc = hmR0VmxExitWrmsr(pVCpu, pMixedCtx, pVmxTransient); break;
7101 case VMX_EXIT_MOV_DRX: rc = hmR0VmxExitMovDRx(pVCpu, pMixedCtx, pVmxTransient); break;
7102 case VMX_EXIT_TPR_BELOW_THRESHOLD: rc = hmR0VmxExitTprBelowThreshold(pVCpu, pMixedCtx, pVmxTransient); break;
7103 case VMX_EXIT_HLT: rc = hmR0VmxExitHlt(pVCpu, pMixedCtx, pVmxTransient); break;
7104 case VMX_EXIT_INVD: rc = hmR0VmxExitInvd(pVCpu, pMixedCtx, pVmxTransient); break;
7105 case VMX_EXIT_INVLPG: rc = hmR0VmxExitInvlpg(pVCpu, pMixedCtx, pVmxTransient); break;
7106 case VMX_EXIT_RSM: rc = hmR0VmxExitRsm(pVCpu, pMixedCtx, pVmxTransient); break;
7107 case VMX_EXIT_MTF: rc = hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient); break;
7108 case VMX_EXIT_PAUSE: rc = hmR0VmxExitPause(pVCpu, pMixedCtx, pVmxTransient); break;
7109 case VMX_EXIT_XDTR_ACCESS: rc = hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient); break;
7110 case VMX_EXIT_TR_ACCESS: rc = hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient); break;
7111 case VMX_EXIT_WBINVD: rc = hmR0VmxExitWbinvd(pVCpu, pMixedCtx, pVmxTransient); break;
7112 case VMX_EXIT_XSETBV: rc = hmR0VmxExitXsetbv(pVCpu, pMixedCtx, pVmxTransient); break;
7113 case VMX_EXIT_RDRAND: rc = hmR0VmxExitRdrand(pVCpu, pMixedCtx, pVmxTransient); break;
7114 case VMX_EXIT_INVPCID: rc = hmR0VmxExitInvpcid(pVCpu, pMixedCtx, pVmxTransient); break;
7115 case VMX_EXIT_GETSEC: rc = hmR0VmxExitGetsec(pVCpu, pMixedCtx, pVmxTransient); break;
7116 case VMX_EXIT_RDPMC: rc = hmR0VmxExitRdpmc(pVCpu, pMixedCtx, pVmxTransient); break;
7117
7118 case VMX_EXIT_TRIPLE_FAULT: rc = hmR0VmxExitTripleFault(pVCpu, pMixedCtx, pVmxTransient); break;
7119 case VMX_EXIT_NMI_WINDOW: rc = hmR0VmxExitNmiWindow(pVCpu, pMixedCtx, pVmxTransient); break;
7120 case VMX_EXIT_INIT_SIGNAL: rc = hmR0VmxExitInitSignal(pVCpu, pMixedCtx, pVmxTransient); break;
7121 case VMX_EXIT_SIPI: rc = hmR0VmxExitSipi(pVCpu, pMixedCtx, pVmxTransient); break;
7122 case VMX_EXIT_IO_SMI: rc = hmR0VmxExitIoSmi(pVCpu, pMixedCtx, pVmxTransient); break;
7123 case VMX_EXIT_SMI: rc = hmR0VmxExitSmi(pVCpu, pMixedCtx, pVmxTransient); break;
7124 case VMX_EXIT_ERR_MSR_LOAD: rc = hmR0VmxExitErrMsrLoad(pVCpu, pMixedCtx, pVmxTransient); break;
7125 case VMX_EXIT_ERR_INVALID_GUEST_STATE: rc = hmR0VmxExitErrInvalidGuestState(pVCpu, pMixedCtx, pVmxTransient); break;
7126 case VMX_EXIT_ERR_MACHINE_CHECK: rc = hmR0VmxExitErrMachineCheck(pVCpu, pMixedCtx, pVmxTransient); break;
7127
7128 case VMX_EXIT_VMCALL:
7129 case VMX_EXIT_VMCLEAR:
7130 case VMX_EXIT_VMLAUNCH:
7131 case VMX_EXIT_VMPTRLD:
7132 case VMX_EXIT_VMPTRST:
7133 case VMX_EXIT_VMREAD:
7134 case VMX_EXIT_VMRESUME:
7135 case VMX_EXIT_VMWRITE:
7136 case VMX_EXIT_VMXOFF:
7137 case VMX_EXIT_VMXON:
7138 case VMX_EXIT_INVEPT:
7139 case VMX_EXIT_INVVPID:
7140 case VMX_EXIT_VMFUNC:
7141 rc = hmR0VmxExitSetPendingXcptUD(pVCpu, pMixedCtx, pVmxTransient);
7142 break;
7143 default:
7144 rc = hmR0VmxExitErrUndefined(pVCpu, pMixedCtx, pVmxTransient);
7145 break;
7146 }
7147 return rc;
7148}
7149#endif
7150
7151#ifdef DEBUG
7152/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
7153# define VMX_ASSERT_PREEMPT_CPUID_VAR() \
7154 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
7155# define VMX_ASSERT_PREEMPT_CPUID() \
7156 do \
7157 { \
7158 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
7159 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
7160 } while (0)
7161
7162# define VMX_VALIDATE_EXIT_HANDLER_PARAMS() \
7163 do { \
7164 AssertPtr(pVCpu); \
7165 AssertPtr(pMixedCtx); \
7166 AssertPtr(pVmxTransient); \
7167 Assert(pVmxTransient->fVMEntryFailed == false); \
7168 Assert(ASMIntAreEnabled()); \
7169 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD)); \
7170 VMX_ASSERT_PREEMPT_CPUID_VAR(); \
7171 Log4Func(("vcpu[%u] vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n", \
7172 (unsigned)pVCpu->idCpu)); \
7173 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD)); \
7174 if (VMMR0IsLogFlushDisabled(pVCpu)) \
7175 VMX_ASSERT_PREEMPT_CPUID(); \
7176 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
7177 } while (0)
7178# define VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() \
7179 do { \
7180 Log4Func(("\n")); \
7181 } while(0)
7182#else /* Release builds */
7183# define VMX_VALIDATE_EXIT_HANDLER_PARAMS() do { HMVMX_STOP_EXIT_DISPATCH_PROF(); } while(0)
7184# define VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() do { } while(0)
7185#endif
7186
7187
7188/**
7189 * Advances the guest RIP after reading it from the VMCS.
7190 *
7191 * @returns VBox status code.
7192 * @param pVCpu Pointer to the VMCPU.
7193 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
7194 * out-of-sync. Make sure to update the required fields
7195 * before using them.
7196 * @param pVmxTransient Pointer to the VMX transient structure.
7197 *
7198 * @remarks No-long-jump zone!!!
7199 */
7200DECLINLINE(int) hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7201{
7202 int rc = hmR0VmxReadExitInstrLenVmcs(pVCpu, pVmxTransient);
7203 rc |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
7204 AssertRCReturn(rc, rc);
7205
7206 pMixedCtx->rip += pVmxTransient->cbInstr;
7207 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP;
7208 return rc;
7209}
7210
7211
7212/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
7213/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
7214/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
7215/**
7216 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
7217 */
7218HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7219{
7220 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7221 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
7222 /* 32-bit Windows hosts (4 cores) has trouble with this; causes higher interrupt latency. */
7223#if HC_ARCH_BITS == 64 && defined(VBOX_WITH_VMMR0_DISABLE_PREEMPTION)
7224 Assert(ASMIntAreEnabled());
7225 return VINF_SUCCESS;
7226#else
7227 return VINF_EM_RAW_INTERRUPT;
7228#endif
7229}
7230
7231
7232/**
7233 * VM-exit handler for exceptions and NMIs (VMX_EXIT_XCPT_NMI).
7234 */
7235HMVMX_EXIT_DECL hmR0VmxExitXcptNmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7236{
7237 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7238 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
7239
7240 int rc = hmR0VmxReadExitIntrInfoVmcs(pVCpu, pVmxTransient);
7241 AssertRCReturn(rc, rc);
7242
7243 uint32_t uIntrType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntrInfo);
7244 Assert( !(pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT)
7245 && uIntrType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
7246
7247 if (uIntrType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
7248 {
7249 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
7250 return VINF_EM_RAW_INTERRUPT;
7251 }
7252
7253 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
7254 rc = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
7255 if (RT_UNLIKELY(rc == VINF_VMX_DOUBLE_FAULT))
7256 {
7257 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
7258 return VINF_SUCCESS;
7259 }
7260 else if (RT_UNLIKELY(rc == VINF_EM_RESET))
7261 {
7262 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
7263 return rc;
7264 }
7265
7266 uint32_t uExitIntrInfo = pVmxTransient->uExitIntrInfo;
7267 uint32_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(uExitIntrInfo);
7268 switch (uIntrType)
7269 {
7270 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT: /* Software exception. (#BP or #OF) */
7271 Assert(uVector == X86_XCPT_DB || uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
7272 /* no break */
7273 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT:
7274 {
7275 switch (uVector)
7276 {
7277 case X86_XCPT_PF: rc = hmR0VmxExitXcptPF(pVCpu, pMixedCtx, pVmxTransient); break;
7278 case X86_XCPT_GP: rc = hmR0VmxExitXcptGP(pVCpu, pMixedCtx, pVmxTransient); break;
7279 case X86_XCPT_NM: rc = hmR0VmxExitXcptNM(pVCpu, pMixedCtx, pVmxTransient); break;
7280 case X86_XCPT_MF: rc = hmR0VmxExitXcptMF(pVCpu, pMixedCtx, pVmxTransient); break;
7281 case X86_XCPT_DB: rc = hmR0VmxExitXcptDB(pVCpu, pMixedCtx, pVmxTransient); break;
7282 case X86_XCPT_BP: rc = hmR0VmxExitXcptBP(pVCpu, pMixedCtx, pVmxTransient); break;
7283#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
7284 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF);
7285 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
7286 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE);
7287 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
7288 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD);
7289 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
7290 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS);
7291 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
7292 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP);
7293 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
7294#endif
7295 default:
7296 {
7297 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7298 AssertRCReturn(rc, rc);
7299
7300 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
7301 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
7302 {
7303 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
7304 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
7305 rc = hmR0VmxReadExitInstrLenVmcs(pVCpu, pVmxTransient);
7306 rc |= hmR0VmxReadExitIntrErrorCodeVmcs(pVCpu, pVmxTransient);
7307 AssertRCReturn(rc, rc);
7308 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(uExitIntrInfo),
7309 pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode,
7310 0 /* GCPtrFaultAddress */);
7311 AssertRCReturn(rc, rc);
7312 }
7313 else
7314 {
7315 AssertMsgFailed(("Unexpected VM-exit caused by exception %#x\n", uVector));
7316 rc = VERR_VMX_UNEXPECTED_EXCEPTION;
7317 }
7318 break;
7319 }
7320 }
7321 break;
7322 }
7323
7324 case VMX_EXIT_INTERRUPTION_INFO_TYPE_DB_XCPT:
7325 default:
7326 {
7327 rc = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_CODE;
7328 AssertMsgFailed(("Unexpected interruption code %#x\n", VMX_EXIT_INTERRUPTION_INFO_TYPE(uExitIntrInfo)));
7329 break;
7330 }
7331 }
7332 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
7333 return rc;
7334}
7335
7336
7337/**
7338 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
7339 */
7340HMVMX_EXIT_DECL hmR0VmxExitIntWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7341{
7342 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7343
7344 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
7345 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT);
7346 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT;
7347 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7348 AssertRCReturn(rc, rc);
7349
7350 /* Deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectEvent() and resume guest execution. */
7351 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
7352 return VINF_SUCCESS;
7353}
7354
7355
7356/**
7357 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
7358 */
7359HMVMX_EXIT_DECL hmR0VmxExitNmiWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7360{
7361 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7362 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
7363 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7364}
7365
7366
7367/**
7368 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
7369 */
7370HMVMX_EXIT_DECL hmR0VmxExitWbinvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7371{
7372 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7373 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWbinvd);
7374 return hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7375}
7376
7377
7378/**
7379 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
7380 */
7381HMVMX_EXIT_DECL hmR0VmxExitInvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7382{
7383 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7384 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvd);
7385 return hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7386}
7387
7388
7389/**
7390 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
7391 */
7392HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7393{
7394 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7395 PVM pVM = pVCpu->CTX_SUFF(pVM);
7396 int rc = EMInterpretCpuId(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
7397 if (RT_LIKELY(rc == VINF_SUCCESS))
7398 {
7399 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7400 Assert(pVmxTransient->cbInstr == 2);
7401 }
7402 else
7403 {
7404 AssertMsgFailed(("hmR0VmxExitCpuid: EMInterpretCpuId failed with %Rrc\n", rc));
7405 rc = VERR_EM_INTERPRETER;
7406 }
7407 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCpuid);
7408 return rc;
7409}
7410
7411
7412/**
7413 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
7414 */
7415HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7416{
7417 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7418 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
7419 AssertRCReturn(rc, rc);
7420
7421 if (pMixedCtx->cr4 & X86_CR4_SMXE)
7422 return VINF_EM_RAW_EMULATE_INSTR;
7423
7424 AssertMsgFailed(("hmR0VmxExitGetsec: unexpected VM-exit when CR4.SMXE is 0.\n"));
7425 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7426}
7427
7428
7429/**
7430 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
7431 */
7432HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7433{
7434 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7435 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx); /** @todo review if CR4 is really required by EM. */
7436 AssertRCReturn(rc, rc);
7437
7438 PVM pVM = pVCpu->CTX_SUFF(pVM);
7439 rc = EMInterpretRdtsc(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
7440 if (RT_LIKELY(rc == VINF_SUCCESS))
7441 {
7442 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7443 Assert(pVmxTransient->cbInstr == 2);
7444 /* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
7445 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING)
7446 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
7447 }
7448 else
7449 {
7450 AssertMsgFailed(("hmR0VmxExitRdtsc: EMInterpretRdtsc failed with %Rrc\n", rc));
7451 rc = VERR_EM_INTERPRETER;
7452 }
7453 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
7454 return rc;
7455}
7456
7457
7458/**
7459 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
7460 */
7461HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7462{
7463 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7464 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx); /** @todo review if CR4 is really required by EM. */
7465 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx); /* For MSR_K8_TSC_AUX */
7466 AssertRCReturn(rc, rc);
7467
7468 PVM pVM = pVCpu->CTX_SUFF(pVM);
7469 rc = EMInterpretRdtscp(pVM, pVCpu, pMixedCtx);
7470 if (RT_LIKELY(rc == VINF_SUCCESS))
7471 {
7472 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7473 Assert(pVmxTransient->cbInstr == 3);
7474 /* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
7475 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING)
7476 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
7477 }
7478 else
7479 {
7480 AssertMsgFailed(("hmR0VmxExitRdtscp: EMInterpretRdtscp failed with %Rrc\n", rc));
7481 rc = VERR_EM_INTERPRETER;
7482 }
7483 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
7484 return rc;
7485}
7486
7487
7488/**
7489 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
7490 */
7491HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7492{
7493 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7494 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx); /** @todo review if CR4 is really required by EM. */
7495 rc |= hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx); /** @todo review if CR0 is really required by EM. */
7496 AssertRCReturn(rc, rc);
7497
7498 PVM pVM = pVCpu->CTX_SUFF(pVM);
7499 rc = EMInterpretRdpmc(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
7500 if (RT_LIKELY(rc == VINF_SUCCESS))
7501 {
7502 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7503 Assert(pVmxTransient->cbInstr == 2);
7504 }
7505 else
7506 {
7507 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
7508 rc = VERR_EM_INTERPRETER;
7509 }
7510 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdpmc);
7511 return rc;
7512}
7513
7514
7515/**
7516 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
7517 */
7518HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7519{
7520 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7521 PVM pVM = pVCpu->CTX_SUFF(pVM);
7522 Assert(!pVM->hm.s.fNestedPaging);
7523
7524 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
7525 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
7526 AssertRCReturn(rc, rc);
7527
7528 VBOXSTRICTRC rc2 = EMInterpretInvlpg(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), pVmxTransient->uExitQualification);
7529 rc = VBOXSTRICTRC_VAL(rc2);
7530 if (RT_LIKELY(rc == VINF_SUCCESS))
7531 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7532 else
7533 {
7534 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitInvlpg: EMInterpretInvlpg %#RX64 failed with %Rrc\n",
7535 pVmxTransient->uExitQualification, rc));
7536 }
7537 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvlpg);
7538 return rc;
7539}
7540
7541
7542/**
7543 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
7544 */
7545HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7546{
7547 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7548 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7549 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7550 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
7551 AssertRCReturn(rc, rc);
7552
7553 PVM pVM = pVCpu->CTX_SUFF(pVM);
7554 rc = EMInterpretMonitor(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
7555 if (RT_LIKELY(rc == VINF_SUCCESS))
7556 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7557 else
7558 {
7559 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMonitor: EMInterpretMonitor failed with %Rrc\n", rc));
7560 rc = VERR_EM_INTERPRETER;
7561 }
7562 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMonitor);
7563 return rc;
7564}
7565
7566
7567/**
7568 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
7569 */
7570HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7571{
7572 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7573 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7574 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7575 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
7576 AssertRCReturn(rc, rc);
7577
7578 PVM pVM = pVCpu->CTX_SUFF(pVM);
7579 VBOXSTRICTRC rc2 = EMInterpretMWait(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
7580 rc = VBOXSTRICTRC_VAL(rc2);
7581 if (RT_LIKELY( rc == VINF_SUCCESS
7582 || rc == VINF_EM_HALT))
7583 {
7584 int rc3 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7585 AssertRCReturn(rc3, rc3);
7586
7587 if ( rc == VINF_EM_HALT
7588 && EMShouldContinueAfterHalt(pVCpu, pMixedCtx))
7589 {
7590 rc = VINF_SUCCESS;
7591 }
7592 }
7593 else
7594 {
7595 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMwait: EMInterpretMWait failed with %Rrc\n", rc));
7596 rc = VERR_EM_INTERPRETER;
7597 }
7598 AssertMsg(rc == VINF_SUCCESS || rc == VINF_EM_HALT || rc == VERR_EM_INTERPRETER,
7599 ("hmR0VmxExitMwait: failed, invalid error code %Rrc\n", rc));
7600 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMwait);
7601 return rc;
7602}
7603
7604
7605/**
7606 * VM-exit handler for RSM (VMX_EXIT_RSM). Unconditional VM-exit.
7607 */
7608HMVMX_EXIT_DECL hmR0VmxExitRsm(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7609{
7610 /*
7611 * Execution of RSM outside of SMM mode causes #UD regardless of VMX root or VMX non-root mode. In theory, we should never
7612 * get this VM-exit. This can happen only if dual-monitor treatment of SMI and VMX is enabled, which can (only?) be done by
7613 * executing VMCALL in VMX root operation. If we get here something funny is going on.
7614 * See Intel spec. "33.15.5 Enabling the Dual-Monitor Treatment".
7615 */
7616 AssertMsgFailed(("Unexpected RSM VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
7617 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7618}
7619
7620
7621/**
7622 * VM-exit handler for SMI (VMX_EXIT_SMI). Unconditional VM-exit.
7623 */
7624HMVMX_EXIT_DECL hmR0VmxExitSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7625{
7626 /*
7627 * This can only happen if we support dual-monitor treatment of SMI, which can be activated by executing VMCALL in VMX
7628 * root operation. If we get there there is something funny going on.
7629 * See Intel spec. "33.15.6 Activating the Dual-Monitor Treatment" and Intel spec. 25.3 "Other Causes of VM-Exits"
7630 */
7631 AssertMsgFailed(("Unexpected SMI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
7632 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7633}
7634
7635
7636/**
7637 * VM-exit handler for IO SMI (VMX_EXIT_IO_SMI). Unconditional VM-exit.
7638 */
7639HMVMX_EXIT_DECL hmR0VmxExitIoSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7640{
7641 /* Same treatment as VMX_EXIT_SMI. See comment in hmR0VmxExitSmi(). */
7642 AssertMsgFailed(("Unexpected IO SMI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
7643 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7644}
7645
7646
7647/**
7648 * VM-exit handler for SIPI (VMX_EXIT_SIPI). Conditional VM-exit.
7649 */
7650HMVMX_EXIT_DECL hmR0VmxExitSipi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7651{
7652 /*
7653 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest activity state is used. We currently
7654 * don't make use of it (see hmR0VmxLoadGuestActivityState()) as our guests don't have direct access to the host LAPIC.
7655 * See Intel spec. 25.3 "Other Causes of VM-exits".
7656 */
7657 AssertMsgFailed(("Unexpected SIPI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
7658 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7659}
7660
7661
7662/**
7663 * VM-exit handler for INIT signal (VMX_EXIT_INIT_SIGNAL). Unconditional
7664 * VM-exit.
7665 */
7666HMVMX_EXIT_DECL hmR0VmxExitInitSignal(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7667{
7668 /*
7669 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM. See Intel spec. "33.14.1 Default Treatment of
7670 * SMI Delivery" and "29.3 VMX Instructions" for "VMXON". It is -NOT- blocked in VMX non-root operation so we can potentially
7671 * still get these exits. See Intel spec. "23.8 Restrictions on VMX operation".
7672 */
7673 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7674 return VINF_SUCCESS; /** @todo r=ramshankar: correct?. */
7675}
7676
7677
7678/**
7679 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
7680 * VM-exit.
7681 */
7682HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7683{
7684 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7685 return VINF_EM_RESET;
7686}
7687
7688
7689/**
7690 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
7691 */
7692HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7693{
7694 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7695 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT);
7696 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
7697 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7698 AssertRCReturn(rc, rc);
7699
7700 pMixedCtx->rip++;
7701 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP;
7702 if (EMShouldContinueAfterHalt(pVCpu, pMixedCtx)) /* Requires eflags. */
7703 rc = VINF_SUCCESS;
7704 else
7705 rc = VINF_EM_HALT;
7706
7707 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
7708 return rc;
7709}
7710
7711
7712/**
7713 * VM-exit handler for instructions that result in a #UD exception delivered to the guest.
7714 */
7715HMVMX_EXIT_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7716{
7717 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7718 hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
7719 return VINF_SUCCESS;
7720}
7721
7722
7723/**
7724 * VM-exit handler for expiry of the VMX preemption timer.
7725 */
7726HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7727{
7728 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7729
7730 /* If the preemption-timer has expired, reinitialize the preemption timer on next VM-entry. */
7731 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
7732
7733 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
7734 PVM pVM = pVCpu->CTX_SUFF(pVM);
7735 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
7736 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
7737 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
7738}
7739
7740
7741/**
7742 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
7743 */
7744HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7745{
7746 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7747
7748 /* We expose XSETBV to the guest, fallback to the recompiler for emulation. */
7749 /** @todo check if XSETBV is supported by the recompiler. */
7750 return VERR_EM_INTERPRETER;
7751}
7752
7753
7754/**
7755 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
7756 */
7757HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7758{
7759 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7760
7761 /* The guest should not invalidate the host CPU's TLBs, fallback to recompiler. */
7762 /** @todo implement EMInterpretInvpcid() */
7763 return VERR_EM_INTERPRETER;
7764}
7765
7766
7767/**
7768 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE).
7769 * Error VM-exit.
7770 */
7771HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7772{
7773 uint32_t uIntrState;
7774 HMVMXHCUINTREG uHCReg;
7775 uint64_t u64Val;
7776 uint32_t u32Val;
7777
7778 int rc = hmR0VmxReadEntryIntrInfoVmcs(pVmxTransient);
7779 rc |= hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
7780 rc |= hmR0VmxReadEntryInstrLenVmcs(pVCpu, pVmxTransient);
7781 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
7782 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
7783 AssertRCReturn(rc, rc);
7784
7785 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntrInfo));
7786 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
7787 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
7788 Log4(("VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE %#RX32\n", uIntrState));
7789
7790 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32Val); AssertRC(rc);
7791 Log4(("VMX_VMCS_GUEST_CR0 %#RX32\n", u32Val));
7792 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
7793 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
7794 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
7795 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
7796 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
7797 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
7798 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
7799 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
7800 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
7801 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
7802
7803 PVM pVM = pVCpu->CTX_SUFF(pVM);
7804 HMDumpRegs(pVM, pVCpu, pMixedCtx);
7805
7806 return VERR_VMX_INVALID_GUEST_STATE;
7807}
7808
7809
7810/**
7811 * VM-exit handler for VM-entry failure due to an MSR-load
7812 * (VMX_EXIT_ERR_MSR_LOAD). Error VM-exit.
7813 */
7814HMVMX_EXIT_DECL hmR0VmxExitErrMsrLoad(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7815{
7816 AssertMsgFailed(("Unexpected MSR-load exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
7817 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7818}
7819
7820
7821/**
7822 * VM-exit handler for VM-entry failure due to a machine-check event
7823 * (VMX_EXIT_ERR_MACHINE_CHECK). Error VM-exit.
7824 */
7825HMVMX_EXIT_DECL hmR0VmxExitErrMachineCheck(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7826{
7827 AssertMsgFailed(("Unexpected machine-check event exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
7828 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7829}
7830
7831
7832/**
7833 * VM-exit handler for all undefined reasons. Should never ever happen.. in
7834 * theory.
7835 */
7836HMVMX_EXIT_DECL hmR0VmxExitErrUndefined(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7837{
7838 AssertMsgFailed(("Huh!? Undefined VM-exit reason %d. pVCpu=%p pMixedCtx=%p\n", pVmxTransient->uExitReason, pVCpu, pMixedCtx));
7839 return VERR_VMX_UNDEFINED_EXIT_CODE;
7840}
7841
7842
7843/**
7844 * VM-exit handler for XDTR (LGDT, SGDT, LIDT, SIDT) accesses
7845 * (VMX_EXIT_XDTR_ACCESS) and LDT and TR access (LLDT, LTR, SLDT, STR).
7846 * Conditional VM-exit.
7847 */
7848HMVMX_EXIT_DECL hmR0VmxExitXdtrAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7849{
7850 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7851
7852 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT. */
7853 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitXdtrAccess);
7854 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT)
7855 return VERR_EM_INTERPRETER;
7856 AssertMsgFailed(("Unexpected XDTR access. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
7857 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7858}
7859
7860
7861/**
7862 * VM-exit handler for RDRAND (VMX_EXIT_RDRAND). Conditional VM-exit.
7863 */
7864HMVMX_EXIT_DECL hmR0VmxExitRdrand(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7865{
7866 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7867
7868 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT. */
7869 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdrand);
7870 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT)
7871 return VERR_EM_INTERPRETER;
7872 AssertMsgFailed(("Unexpected RDRAND exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
7873 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7874}
7875
7876
7877/**
7878 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
7879 */
7880HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7881{
7882 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7883
7884 /* EMInterpretRdmsr() requires CR0, Eflags and SS segment register. */
7885 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7886 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7887 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
7888 AssertRCReturn(rc, rc);
7889
7890 PVM pVM = pVCpu->CTX_SUFF(pVM);
7891 rc = EMInterpretRdmsr(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
7892 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER,
7893 ("hmR0VmxExitRdmsr: failed, invalid error code %Rrc\n", rc));
7894 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
7895
7896 if (RT_LIKELY(rc == VINF_SUCCESS))
7897 {
7898 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7899 Assert(pVmxTransient->cbInstr == 2);
7900 }
7901 return rc;
7902}
7903
7904
7905/**
7906 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
7907 */
7908HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
7909{
7910 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
7911 PVM pVM = pVCpu->CTX_SUFF(pVM);
7912 int rc = VINF_SUCCESS;
7913
7914 /* If TPR patching is active, LSTAR holds the guest TPR, writes to it must be propagated to the APIC. */
7915 if ( pVM->hm.s.fTPRPatchingActive
7916 && pMixedCtx->ecx == MSR_K8_LSTAR)
7917 {
7918 Assert(!CPUMIsGuestInLongModeEx(pMixedCtx)); /* Requires EFER but it's always up-to-date. */
7919 if ((pMixedCtx->eax & 0xff) != pVmxTransient->u8GuestTpr)
7920 {
7921 rc = PDMApicSetTPR(pVCpu, pMixedCtx->eax & 0xff);
7922 AssertRC(rc);
7923 }
7924
7925 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7926 Assert(pVmxTransient->cbInstr == 2);
7927 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
7928 return VINF_SUCCESS;
7929 }
7930
7931 /* EMInterpretWrmsr() requires CR0, EFLAGS and SS segment register. */
7932 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7933 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7934 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
7935 AssertRCReturn(rc, rc);
7936 Log4(("ecx=%#RX32\n", pMixedCtx->ecx));
7937
7938 rc = EMInterpretWrmsr(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
7939 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER, ("hmR0VmxExitWrmsr: failed, invalid error code %Rrc\n", rc));
7940 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
7941
7942 if (RT_LIKELY(rc == VINF_SUCCESS))
7943 {
7944 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
7945
7946 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
7947 if ( pMixedCtx->ecx >= MSR_IA32_X2APIC_START
7948 && pMixedCtx->ecx <= MSR_IA32_X2APIC_END)
7949 {
7950 Assert(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_APIC_STATE);
7951 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_VMX_GUEST_APIC_STATE;
7952 }
7953 else if (pMixedCtx->ecx == MSR_K6_EFER) /* EFER is the only MSR we auto-load but don't allow write-passthrough. */
7954 {
7955 rc = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
7956 AssertRCReturn(rc, rc);
7957 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_VMX_GUEST_AUTO_MSRS;
7958 }
7959 else if (pMixedCtx->ecx == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
7960 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
7961
7962 /* Update MSRs that are part of the VMCS when MSR-bitmaps are not supported. */
7963 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
7964 {
7965 switch (pMixedCtx->ecx)
7966 {
7967 case MSR_IA32_SYSENTER_CS: pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_SYSENTER_CS_MSR; break;
7968 case MSR_IA32_SYSENTER_EIP: pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_SYSENTER_EIP_MSR; break;
7969 case MSR_IA32_SYSENTER_ESP: pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_SYSENTER_ESP_MSR; break;
7970 case MSR_K8_FS_BASE: /* no break */
7971 case MSR_K8_GS_BASE: pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_SEGMENT_REGS; break;
7972 case MSR_K8_KERNEL_GS_BASE: pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_VMX_GUEST_AUTO_MSRS; break;
7973 }
7974 }
7975#ifdef VBOX_STRICT
7976 else
7977 {
7978 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
7979 switch (pMixedCtx->ecx)
7980 {
7981 case MSR_IA32_SYSENTER_CS:
7982 case MSR_IA32_SYSENTER_EIP:
7983 case MSR_IA32_SYSENTER_ESP:
7984 case MSR_K8_FS_BASE:
7985 case MSR_K8_GS_BASE:
7986 {
7987 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", pMixedCtx->ecx));
7988 return VERR_VMX_UNEXPECTED_EXIT_CODE;
7989 }
7990
7991 case MSR_K8_LSTAR:
7992 case MSR_K6_STAR:
7993 case MSR_K8_SF_MASK:
7994 case MSR_K8_TSC_AUX:
7995 case MSR_K8_KERNEL_GS_BASE:
7996 {
7997 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
7998 pMixedCtx->ecx));
7999 return VERR_VMX_UNEXPECTED_EXIT_CODE;
8000 }
8001 }
8002 }
8003#endif /* VBOX_STRICT */
8004 }
8005 return rc;
8006}
8007
8008
8009/**
8010 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
8011 */
8012HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8013{
8014 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
8015
8016 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC_PAUSE_EXIT. */
8017 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPause);
8018 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_PAUSE_EXIT)
8019 return VERR_EM_INTERPRETER;
8020 AssertMsgFailed(("Unexpected PAUSE exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
8021 return VERR_VMX_UNEXPECTED_EXIT_CODE;
8022}
8023
8024
8025/**
8026 * VM-exit handler for when the TPR value is lowered below the specified
8027 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
8028 */
8029HMVMX_EXIT_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8030{
8031 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
8032 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW);
8033
8034 /*
8035 * The TPR has already been updated, see hmR0VMXPostRunGuest(). RIP is also updated as part of the VM-exit by VT-x. Update
8036 * the threshold in the VMCS, deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectEvent() and
8037 * resume guest execution.
8038 */
8039 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_VMX_GUEST_APIC_STATE;
8040 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
8041 return VINF_SUCCESS;
8042}
8043
8044
8045/**
8046 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
8047 * VM-exit.
8048 *
8049 * @retval VINF_SUCCESS when guest execution can continue.
8050 * @retval VINF_PGM_CHANGE_MODE when shadow paging mode changed, back to ring-3.
8051 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
8052 * @retval VERR_EM_INTERPRETER when something unexpected happened, fallback to
8053 * recompiler.
8054 */
8055HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8056{
8057 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
8058 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
8059 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
8060 AssertRCReturn(rc, rc);
8061
8062 const RTGCUINTPTR uExitQualification = pVmxTransient->uExitQualification;
8063 const uint32_t uAccessType = VMX_EXIT_QUALIFICATION_CRX_ACCESS(uExitQualification);
8064 PVM pVM = pVCpu->CTX_SUFF(pVM);
8065 switch (uAccessType)
8066 {
8067 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_WRITE: /* MOV to CRx */
8068 {
8069#if 0
8070 /* EMInterpretCRxWrite() references a lot of guest state (EFER, RFLAGS, Segment Registers, etc.) Sync entire state */
8071 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
8072#else
8073 rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
8074 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
8075 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
8076#endif
8077 AssertRCReturn(rc, rc);
8078
8079 rc = EMInterpretCRxWrite(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
8080 VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification),
8081 VMX_EXIT_QUALIFICATION_CRX_GENREG(uExitQualification));
8082 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
8083
8084 switch (VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification))
8085 {
8086 case 0: /* CR0 */
8087 Log4(("CRX CR0 write rc=%d CR0=%#RX64\n", rc, pMixedCtx->cr0));
8088 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_CR0;
8089 break;
8090 case 2: /* C2 **/
8091 /* Nothing to do here, CR2 it's not part of the VMCS. */
8092 break;
8093 case 3: /* CR3 */
8094 Assert(!pVM->hm.s.fNestedPaging || !CPUMIsGuestPagingEnabledEx(pMixedCtx));
8095 Log4(("CRX CR3 write rc=%d CR3=%#RX64\n", rc, pMixedCtx->cr3));
8096 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_CR3;
8097 break;
8098 case 4: /* CR4 */
8099 Log4(("CRX CR4 write rc=%d CR4=%#RX64\n", rc, pMixedCtx->cr4));
8100 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_CR4;
8101 break;
8102 case 8: /* CR8 */
8103 Assert(!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW));
8104 /* CR8 contains the APIC TPR. Was updated by EMInterpretCRxWrite(). */
8105 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_VMX_GUEST_APIC_STATE;
8106 break;
8107 default:
8108 AssertMsgFailed(("Invalid CRx register %#x\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)));
8109 break;
8110 }
8111
8112 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxWrite[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
8113 break;
8114 }
8115
8116 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ: /* MOV from CRx */
8117 {
8118 /* EMInterpretCRxRead() requires EFER MSR, CS. */
8119 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
8120 AssertRCReturn(rc, rc);
8121 Assert( !pVM->hm.s.fNestedPaging
8122 || !CPUMIsGuestPagingEnabledEx(pMixedCtx)
8123 || VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification) != 3);
8124
8125 /* CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
8126 Assert( VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification) != 8
8127 || !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW));
8128
8129 rc = EMInterpretCRxRead(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
8130 VMX_EXIT_QUALIFICATION_CRX_GENREG(uExitQualification),
8131 VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification));
8132 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
8133 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxRead[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
8134 Log4(("CRX CR%d Read access rc=%d\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification), rc));
8135 break;
8136 }
8137
8138 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_CLTS: /* CLTS (Clear Task-Switch Flag in CR0) */
8139 {
8140 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
8141 AssertRCReturn(rc, rc);
8142 rc = EMInterpretCLTS(pVM, pVCpu);
8143 AssertRCReturn(rc, rc);
8144 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_CR0;
8145 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
8146 Log4(("CRX CLTS write rc=%d\n", rc));
8147 break;
8148 }
8149
8150 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
8151 {
8152 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
8153 AssertRCReturn(rc, rc);
8154 rc = EMInterpretLMSW(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(uExitQualification));
8155 if (RT_LIKELY(rc == VINF_SUCCESS))
8156 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_CR0;
8157 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
8158 Log4(("CRX LMSW write rc=%d\n", rc));
8159 break;
8160 }
8161
8162 default:
8163 {
8164 AssertMsgFailed(("Invalid access-type in Mov CRx exit qualification %#x\n", uAccessType));
8165 rc = VERR_VMX_UNEXPECTED_EXCEPTION;
8166 }
8167 }
8168
8169 /* Validate possible error codes. */
8170 Assert(rc == VINF_SUCCESS || rc == VINF_PGM_CHANGE_MODE || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_SYNC_CR3
8171 || rc == VERR_VMX_UNEXPECTED_EXCEPTION);
8172 if (RT_SUCCESS(rc))
8173 {
8174 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
8175 AssertRCReturn(rc2, rc2);
8176 }
8177
8178 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
8179 return rc;
8180}
8181
8182
8183/**
8184 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
8185 * VM-exit.
8186 */
8187HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8188{
8189 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
8190 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
8191
8192 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
8193 rc |= hmR0VmxReadExitInstrLenVmcs(pVCpu, pVmxTransient);
8194 rc |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
8195 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx); /* Eflag checks in EMInterpretDisasCurrent(). */
8196 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx); /* CR0 checks & PGM* in EMInterpretDisasCurrent(). */
8197 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* SELM checks in EMInterpretDisasCurrent(). */
8198 /* EFER also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
8199 AssertRCReturn(rc, rc);
8200
8201 Log4(("CS:RIP=%04x:%#RX64\n", pMixedCtx->cs.Sel, pMixedCtx->rip));
8202
8203 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
8204 uint32_t uIOPort = VMX_EXIT_QUALIFICATION_IO_PORT(pVmxTransient->uExitQualification);
8205 uint32_t uIOWidth = VMX_EXIT_QUALIFICATION_IO_WIDTH(pVmxTransient->uExitQualification);
8206 bool fIOWrite = (VMX_EXIT_QUALIFICATION_IO_DIRECTION(pVmxTransient->uExitQualification)
8207 == VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT);
8208 bool fIOString = (VMX_EXIT_QUALIFICATION_IO_STRING(pVmxTransient->uExitQualification) == 1);
8209 Assert(uIOWidth == 0 || uIOWidth == 1 || uIOWidth == 3);
8210
8211 /* I/O operation lookup arrays. */
8212 static const uint32_t s_aIOSize[4] = { 1, 2, 0, 4 }; /* Size of the I/O Accesses. */
8213 static const uint32_t s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving the result (in AL/AX/EAX). */
8214
8215 const uint32_t cbSize = s_aIOSize[uIOWidth];
8216 const uint32_t cbInstr = pVmxTransient->cbInstr;
8217 PVM pVM = pVCpu->CTX_SUFF(pVM);
8218 if (fIOString)
8219 {
8220 /* INS/OUTS - I/O String instruction. */
8221 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
8222 /** @todo for now manually disassemble later optimize by getting the fields from
8223 * the VMCS. VMX_VMCS_RO_EXIT_GUEST_LINEAR_ADDR contains the flat pointer
8224 * operand of the instruction. VMX_VMCS32_RO_EXIT_INSTR_INFO contains
8225 * segment prefix info. */
8226 rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL);
8227 if (RT_SUCCESS(rc))
8228 {
8229 if (fIOWrite)
8230 {
8231 VBOXSTRICTRC rc2 = IOMInterpretOUTSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix,
8232 (DISCPUMODE)pDis->uAddrMode, cbSize);
8233 rc = VBOXSTRICTRC_VAL(rc2);
8234 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringWrite);
8235 }
8236 else
8237 {
8238 VBOXSTRICTRC rc2 = IOMInterpretINSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix,
8239 (DISCPUMODE)pDis->uAddrMode, cbSize);
8240 rc = VBOXSTRICTRC_VAL(rc2);
8241 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringRead);
8242 }
8243 }
8244 else
8245 {
8246 AssertMsg(rc == VERR_EM_INTERPRETER, ("rc=%Rrc RIP %#RX64\n", rc, pMixedCtx->rip));
8247 rc = VINF_EM_RAW_EMULATE_INSTR;
8248 }
8249 }
8250 else
8251 {
8252 /* IN/OUT - I/O instruction. */
8253 const uint32_t uAndVal = s_aIOOpAnd[uIOWidth];
8254 Assert(!VMX_EXIT_QUALIFICATION_IO_REP(pVmxTransient->uExitQualification));
8255 if (fIOWrite)
8256 {
8257 VBOXSTRICTRC rc2 = IOMIOPortWrite(pVM, pVCpu, uIOPort, pMixedCtx->eax & uAndVal, cbSize);
8258 rc = VBOXSTRICTRC_VAL(rc2);
8259 if (rc == VINF_IOM_R3_IOPORT_WRITE)
8260 HMR0SavePendingIOPortWrite(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbSize);
8261 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
8262 }
8263 else
8264 {
8265 uint32_t u32Result = 0;
8266 VBOXSTRICTRC rc2 = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbSize);
8267 rc = VBOXSTRICTRC_VAL(rc2);
8268 if (IOM_SUCCESS(rc))
8269 {
8270 /* Save result of I/O IN instr. in AL/AX/EAX. */
8271 pMixedCtx->eax = (pMixedCtx->eax & ~uAndVal) | (u32Result & uAndVal);
8272 }
8273 else if (rc == VINF_IOM_R3_IOPORT_READ)
8274 HMR0SavePendingIOPortRead(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbSize);
8275 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
8276 }
8277 }
8278
8279 if (IOM_SUCCESS(rc))
8280 {
8281 pMixedCtx->rip += cbInstr;
8282 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP;
8283 if (RT_LIKELY(rc == VINF_SUCCESS))
8284 {
8285 rc = hmR0VmxSaveGuestDebugRegs(pVCpu, pMixedCtx); /* For DR7. */
8286 AssertRCReturn(rc, rc);
8287
8288 /* If any IO breakpoints are armed, then we should check if a debug trap needs to be generated. */
8289 if (pMixedCtx->dr[7] & X86_DR7_ENABLED_MASK)
8290 {
8291 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
8292 for (unsigned i = 0; i < 4; i++)
8293 {
8294 uint32_t uBPLen = s_aIOSize[X86_DR7_GET_LEN(pMixedCtx->dr[7], i)];
8295 if ( ( uIOPort >= pMixedCtx->dr[i]
8296 && uIOPort < pMixedCtx->dr[i] + uBPLen)
8297 && (pMixedCtx->dr[7] & (X86_DR7_L(i) | X86_DR7_G(i)))
8298 && (pMixedCtx->dr[7] & X86_DR7_RW(i, X86_DR7_RW_IO)) == X86_DR7_RW(i, X86_DR7_RW_IO))
8299 {
8300 Assert(CPUMIsGuestDebugStateActive(pVCpu));
8301 uint64_t uDR6 = ASMGetDR6();
8302
8303 /* Clear all breakpoint status flags and set the one we just hit. */
8304 uDR6 &= ~(X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3);
8305 uDR6 |= (uint64_t)RT_BIT(i);
8306
8307 /*
8308 * Note: AMD64 Architecture Programmer's Manual 13.1:
8309 * Bits 15:13 of the DR6 register is never cleared by the processor and must
8310 * be cleared by software after the contents have been read.
8311 */
8312 ASMSetDR6(uDR6);
8313
8314 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
8315 pMixedCtx->dr[7] &= ~X86_DR7_GD;
8316
8317 /* Paranoia. */
8318 pMixedCtx->dr[7] &= UINT64_C(0xffffffff); /* Upper 32 bits MBZ. */
8319 pMixedCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* MBZ. */
8320 pMixedCtx->dr[7] |= 0x400; /* MB1. */
8321
8322 /* Resync DR7 */
8323 /** @todo probably cheaper to just reload DR7, nothing else needs changing. */
8324 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_DEBUG;
8325
8326 /* Set #DB to be injected into the VM and continue guest execution. */
8327 hmR0VmxSetPendingXcptDB(pVCpu, pMixedCtx);
8328 break;
8329 }
8330 }
8331 }
8332 }
8333 }
8334
8335#ifdef DEBUG
8336 if (rc == VINF_IOM_R3_IOPORT_READ)
8337 Assert(!fIOWrite);
8338 else if (rc == VINF_IOM_R3_IOPORT_WRITE)
8339 Assert(fIOWrite);
8340 else
8341 {
8342 AssertMsg( RT_FAILURE(rc)
8343 || rc == VINF_SUCCESS
8344 || rc == VINF_EM_RAW_EMULATE_INSTR
8345 || rc == VINF_EM_RAW_GUEST_TRAP
8346 || rc == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", rc));
8347 }
8348#endif
8349
8350 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
8351 return rc;
8352}
8353
8354
8355/**
8356 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
8357 * VM-exit.
8358 */
8359HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8360{
8361 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
8362
8363 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
8364 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
8365 AssertRCReturn(rc, rc);
8366 if (VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_IDT)
8367 {
8368 rc = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
8369 AssertRCReturn(rc, rc);
8370 if (VMX_IDT_VECTORING_INFO_VALID(pVmxTransient->uIdtVectoringInfo))
8371 {
8372 uint32_t uIntType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
8373
8374 /* Software interrupts and exceptions will be regenerated when the recompiler restarts the instruction. */
8375 if ( uIntType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT
8376 && uIntType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
8377 && uIntType != VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
8378 {
8379 uint32_t uVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
8380 bool fErrorCodeValid = !!VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo);
8381
8382 /* Save it as a pending event and it'll be converted to a TRPM event on the way out to ring-3. */
8383 Assert(!pVCpu->hm.s.Event.fPending);
8384 pVCpu->hm.s.Event.fPending = true;
8385 pVCpu->hm.s.Event.u64IntrInfo = pVmxTransient->uIdtVectoringInfo;
8386 rc = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
8387 AssertRCReturn(rc, rc);
8388 if (fErrorCodeValid)
8389 pVCpu->hm.s.Event.u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
8390 else
8391 pVCpu->hm.s.Event.u32ErrCode = 0;
8392 if ( uIntType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
8393 && uVector == X86_XCPT_PF)
8394 {
8395 pVCpu->hm.s.Event.GCPtrFaultAddress = pMixedCtx->cr2;
8396 }
8397
8398 Log4(("Pending event on TaskSwitch uIntType=%#x uVector=%#x\n", uIntType, uVector));
8399 }
8400 }
8401 }
8402
8403 /** @todo Emulate task switch someday, currently just going back to ring-3 for
8404 * emulation. */
8405 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
8406 return VERR_EM_INTERPRETER;
8407}
8408
8409
8410/**
8411 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
8412 */
8413HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8414{
8415 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
8416 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG);
8417 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG;
8418 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
8419 AssertRCReturn(rc, rc);
8420 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMtf);
8421 return VINF_EM_DBG_STOP;
8422}
8423
8424
8425/**
8426 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
8427 */
8428HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8429{
8430 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
8431
8432 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
8433 int rc = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
8434 if (RT_UNLIKELY(rc == VINF_VMX_DOUBLE_FAULT))
8435 return VINF_SUCCESS;
8436 else if (RT_UNLIKELY(rc == VINF_EM_RESET))
8437 return rc;
8438
8439#if 0
8440 /** @todo Investigate if IOMMMIOPhysHandler() requires a lot of state, for now
8441 * just sync the whole thing. */
8442 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
8443#else
8444 /* Aggressive state sync. for now. */
8445 rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
8446 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
8447 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
8448#endif
8449 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
8450 AssertRCReturn(rc, rc);
8451
8452 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
8453 uint32_t uAccessType = VMX_EXIT_QUALIFICATION_APIC_ACCESS_TYPE(pVmxTransient->uExitQualification);
8454 switch (uAccessType)
8455 {
8456 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
8457 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
8458 {
8459 if ( (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
8460 && VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification) == 0x80)
8461 {
8462 AssertMsgFailed(("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
8463 }
8464
8465 RTGCPHYS GCPhys = pMixedCtx->msrApicBase; /* Always up-to-date, msrApicBase is not part of the VMCS. */
8466 GCPhys &= PAGE_BASE_GC_MASK;
8467 GCPhys += VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification);
8468 PVM pVM = pVCpu->CTX_SUFF(pVM);
8469 Log4(("ApicAccess uAccessType=%#x GCPhys=%#RGv Off=%#x\n", uAccessType, GCPhys,
8470 VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification)));
8471
8472 VBOXSTRICTRC rc2 = IOMMMIOPhysHandler(pVM, pVCpu,
8473 (uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ) ? 0 : X86_TRAP_PF_RW,
8474 CPUMCTX2CORE(pMixedCtx), GCPhys);
8475 rc = VBOXSTRICTRC_VAL(rc2);
8476 Log4(("ApicAccess rc=%d\n", rc));
8477 if ( rc == VINF_SUCCESS
8478 || rc == VERR_PAGE_TABLE_NOT_PRESENT
8479 || rc == VERR_PAGE_NOT_PRESENT)
8480 {
8481 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
8482 | HM_CHANGED_VMX_GUEST_APIC_STATE;
8483 rc = VINF_SUCCESS;
8484 }
8485 break;
8486 }
8487
8488 default:
8489 Log4(("ApicAccess uAccessType=%#x\n", uAccessType));
8490 rc = VINF_EM_RAW_EMULATE_INSTR;
8491 break;
8492 }
8493
8494 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
8495 return rc;
8496}
8497
8498
8499/**
8500 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
8501 * VM-exit.
8502 */
8503HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8504{
8505 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
8506
8507 /* We should -not- get this VM-exit if the guest is debugging. */
8508 if (CPUMIsGuestDebugStateActive(pVCpu))
8509 {
8510 AssertMsgFailed(("Unexpected MOV DRx exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
8511 return VERR_VMX_UNEXPECTED_EXIT_CODE;
8512 }
8513
8514 int rc = VERR_INTERNAL_ERROR_5;
8515 if ( !DBGFIsStepping(pVCpu)
8516 && !CPUMIsHyperDebugStateActive(pVCpu))
8517 {
8518 /* Don't intercept MOV DRx. */
8519 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
8520 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
8521 AssertRCReturn(rc, rc);
8522
8523 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
8524 PVM pVM = pVCpu->CTX_SUFF(pVM);
8525 rc = CPUMR0LoadGuestDebugState(pVM, pVCpu, pMixedCtx, true /* include DR6 */);
8526 AssertRC(rc);
8527 Assert(CPUMIsGuestDebugStateActive(pVCpu));
8528
8529#ifdef VBOX_WITH_STATISTICS
8530 rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
8531 AssertRCReturn(rc, rc);
8532 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
8533 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
8534 else
8535 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
8536#endif
8537 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
8538 return VINF_SUCCESS;
8539 }
8540
8541 /*
8542 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER, CS. EFER is always up-to-date, see
8543 * hmR0VmxSaveGuestAutoLoadStoreMsrs(). Update only the segment registers from the CPU.
8544 */
8545 rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
8546 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
8547 AssertRCReturn(rc, rc);
8548
8549 PVM pVM = pVCpu->CTX_SUFF(pVM);
8550 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
8551 {
8552 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
8553 VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification),
8554 VMX_EXIT_QUALIFICATION_DRX_GENREG(pVmxTransient->uExitQualification));
8555 if (RT_SUCCESS(rc))
8556 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_DEBUG;
8557 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
8558 }
8559 else
8560 {
8561 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
8562 VMX_EXIT_QUALIFICATION_DRX_GENREG(pVmxTransient->uExitQualification),
8563 VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification));
8564 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
8565 }
8566
8567 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
8568 if (RT_SUCCESS(rc))
8569 {
8570 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
8571 AssertRCReturn(rc2, rc2);
8572 }
8573 return rc;
8574}
8575
8576
8577/**
8578 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
8579 * Conditional VM-exit.
8580 */
8581HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8582{
8583 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
8584 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
8585
8586 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
8587 int rc = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
8588 if (RT_UNLIKELY(rc == VINF_VMX_DOUBLE_FAULT))
8589 return VINF_SUCCESS;
8590 else if (RT_UNLIKELY(rc == VINF_EM_RESET))
8591 return rc;
8592
8593 RTGCPHYS GCPhys = 0;
8594 rc = VMXReadVmcs64(VMX_VMCS64_EXIT_GUEST_PHYS_ADDR_FULL, &GCPhys);
8595
8596#if 0
8597 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx); /** @todo Can we do better? */
8598#else
8599 /* Aggressive state sync. for now. */
8600 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
8601 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
8602 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
8603#endif
8604 AssertRCReturn(rc, rc);
8605
8606 /*
8607 * If we succeed, resume guest execution.
8608 * If we fail in interpreting the instruction because we couldn't get the guest physical address
8609 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
8610 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
8611 * weird case. See @bugref{6043}.
8612 */
8613 PVM pVM = pVCpu->CTX_SUFF(pVM);
8614 VBOXSTRICTRC rc2 = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pMixedCtx), GCPhys, UINT32_MAX);
8615 rc = VBOXSTRICTRC_VAL(rc2);
8616 Log4(("EPT misconfig at %#RGv RIP=%#RX64 rc=%d\n", GCPhys, pMixedCtx->rip, rc));
8617 if ( rc == VINF_SUCCESS
8618 || rc == VERR_PAGE_TABLE_NOT_PRESENT
8619 || rc == VERR_PAGE_NOT_PRESENT)
8620 {
8621 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
8622 | HM_CHANGED_VMX_GUEST_APIC_STATE;
8623 return VINF_SUCCESS;
8624 }
8625 return rc;
8626}
8627
8628
8629/**
8630 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
8631 * VM-exit.
8632 */
8633HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8634{
8635 VMX_VALIDATE_EXIT_HANDLER_PARAMS();
8636 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
8637
8638 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
8639 int rc = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
8640 if (RT_UNLIKELY(rc == VINF_VMX_DOUBLE_FAULT))
8641 return VINF_SUCCESS;
8642 else if (RT_UNLIKELY(rc == VINF_EM_RESET))
8643 return rc;
8644
8645 RTGCPHYS GCPhys = 0;
8646 rc = VMXReadVmcs64(VMX_VMCS64_EXIT_GUEST_PHYS_ADDR_FULL, &GCPhys);
8647 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
8648#if 0
8649 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx); /** @todo Can we do better? */
8650#else
8651 /* Aggressive state sync. for now. */
8652 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
8653 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
8654 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
8655#endif
8656 AssertRCReturn(rc, rc);
8657
8658 /* Intel spec. Table 27-7 "Exit Qualifications for EPT violations". */
8659 AssertMsg(((pVmxTransient->uExitQualification >> 7) & 3) != 2, ("%#RX64", pVmxTransient->uExitQualification));
8660
8661 RTGCUINT uErrorCode = 0;
8662 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_INSTR_FETCH)
8663 uErrorCode |= X86_TRAP_PF_ID;
8664 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_DATA_WRITE)
8665 uErrorCode |= X86_TRAP_PF_RW;
8666 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_ENTRY_PRESENT)
8667 uErrorCode |= X86_TRAP_PF_P;
8668
8669 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
8670
8671 Log4(("EPT violation %#x at %#RX64 ErrorCode %#x CS:EIP=%04x:%#RX64\n", pVmxTransient->uExitQualification, GCPhys,
8672 uErrorCode, pMixedCtx->cs.Sel, pMixedCtx->rip));
8673
8674 /* Handle the pagefault trap for the nested shadow table. */
8675 PVM pVM = pVCpu->CTX_SUFF(pVM);
8676 rc = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pMixedCtx), GCPhys);
8677 TRPMResetTrap(pVCpu);
8678
8679 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
8680 if ( rc == VINF_SUCCESS
8681 || rc == VERR_PAGE_TABLE_NOT_PRESENT
8682 || rc == VERR_PAGE_NOT_PRESENT)
8683 {
8684 /* Successfully synced our shadow page tables or emulation MMIO instruction. */
8685 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
8686 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
8687 | HM_CHANGED_VMX_GUEST_APIC_STATE;
8688 return VINF_SUCCESS;
8689 }
8690
8691 Log4(("EPT return to ring-3 rc=%d\n"));
8692 return rc;
8693}
8694
8695
8696/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-= */
8697/* -=-=-=-=-=-=-=-=-=- VM-exit Exception Handlers -=-=-=-=-=-=-=-=-=-=- */
8698/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-= */
8699/**
8700 * VM-exit exception handler for #MF (Math Fault: floating point exception).
8701 */
8702static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8703{
8704 VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
8705 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
8706
8707 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
8708 AssertRCReturn(rc, rc);
8709
8710 if (!(pMixedCtx->cr0 & X86_CR0_NE))
8711 {
8712 /* Old-style FPU error reporting needs some extra work. */
8713 /** @todo don't fall back to the recompiler, but do it manually. */
8714 return VERR_EM_INTERPRETER;
8715 }
8716 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
8717 pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, 0 /* GCPtrFaultAddress */);
8718 return rc;
8719}
8720
8721
8722/**
8723 * VM-exit exception handler for #BP (Breakpoint exception).
8724 */
8725static int hmR0VmxExitXcptBP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8726{
8727 VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
8728 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
8729
8730 /** @todo Try optimize this by not saving the entire guest state unless
8731 * really needed. */
8732 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
8733 AssertRCReturn(rc, rc);
8734
8735 PVM pVM = pVCpu->CTX_SUFF(pVM);
8736 rc = DBGFRZTrap03Handler(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
8737 if (rc == VINF_EM_RAW_GUEST_TRAP)
8738 {
8739 rc = hmR0VmxReadExitIntrInfoVmcs(pVCpu, pVmxTransient);
8740 rc |= hmR0VmxReadExitInstrLenVmcs(pVCpu, pVmxTransient);
8741 rc |= hmR0VmxReadExitIntrErrorCodeVmcs(pVCpu, pVmxTransient);
8742 AssertRCReturn(rc, rc);
8743
8744 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
8745 pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, 0 /* GCPtrFaultAddress */);
8746 }
8747
8748 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_EM_DBG_BREAKPOINT);
8749 return rc;
8750}
8751
8752
8753/**
8754 * VM-exit exception handler for #DB (Debug exception).
8755 */
8756static int hmR0VmxExitXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8757{
8758 VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
8759 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
8760
8761 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
8762 AssertRCReturn(rc, rc);
8763
8764 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
8765 uint64_t uDR6 = X86_DR6_INIT_VAL;
8766 uDR6 |= (pVmxTransient->uExitQualification
8767 & (X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3 | X86_DR6_BD | X86_DR6_BS));
8768 PVM pVM = pVCpu->CTX_SUFF(pVM);
8769 rc = DBGFRZTrap01Handler(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uDR6);
8770 if (rc == VINF_EM_RAW_GUEST_TRAP)
8771 {
8772 /* DR6, DR7.GD and IA32_DEBUGCTL.LBR are not updated yet. See Intel spec. 27.1 "Architectural State before a VM-Exit". */
8773 pMixedCtx->dr[6] = uDR6;
8774
8775 if (CPUMIsGuestDebugStateActive(pVCpu))
8776 ASMSetDR6(pMixedCtx->dr[6]);
8777
8778 rc = hmR0VmxSaveGuestDebugRegs(pVCpu, pMixedCtx);
8779
8780 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
8781 pMixedCtx->dr[7] &= ~X86_DR7_GD;
8782
8783 /* Paranoia. */
8784 pMixedCtx->dr[7] &= UINT64_C(0xffffffff); /* upper 32 bits MBZ. */
8785 pMixedCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* must be zero */
8786 pMixedCtx->dr[7] |= 0x400; /* must be one */
8787
8788 rc |= VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, (uint32_t)pMixedCtx->dr[7]);
8789 AssertRCReturn(rc,rc);
8790
8791 int rc2 = hmR0VmxReadExitIntrInfoVmcs(pVCpu, pVmxTransient);
8792 rc2 |= hmR0VmxReadExitInstrLenVmcs(pVCpu, pVmxTransient);
8793 rc2 |= hmR0VmxReadExitIntrErrorCodeVmcs(pVCpu, pVmxTransient);
8794 AssertRCReturn(rc2, rc2);
8795 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
8796 pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, 0 /* GCPtrFaultAddress */);
8797 rc = VINF_SUCCESS;
8798 }
8799
8800 return rc;
8801}
8802
8803
8804/**
8805 * VM-exit exception handler for #NM (Device-not-available exception: floating
8806 * point exception).
8807 */
8808static int hmR0VmxExitXcptNM(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8809{
8810 VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
8811
8812#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
8813 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
8814#endif
8815
8816 /* We require CR0 and EFER. EFER is always up-to-date. */
8817 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
8818 AssertRCReturn(rc, rc);
8819
8820 /* Lazy FPU loading; load the guest-FPU state transparently and continue execution of the guest. */
8821 PVM pVM = pVCpu->CTX_SUFF(pVM);
8822 rc = CPUMR0LoadGuestFPU(pVM, pVCpu, pMixedCtx);
8823 if (rc == VINF_SUCCESS)
8824 {
8825 Assert(CPUMIsGuestFPUStateActive(pVCpu));
8826 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_CR0;
8827 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowNM);
8828 return VINF_SUCCESS;
8829 }
8830
8831 /* Forward #NM to the guest. */
8832 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
8833 rc = hmR0VmxReadExitIntrInfoVmcs(pVCpu, pVmxTransient);
8834 AssertRCReturn(rc, rc);
8835 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
8836 pVmxTransient->cbInstr, 0 /* error code */, 0 /* GCPtrFaultAddress */);
8837 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNM);
8838 return rc;
8839}
8840
8841
8842/**
8843 * VM-exit exception handler for #GP (General-protection exception).
8844 *
8845 * @remarks Requires pVmxTransient->uExitIntrInfo to be up-to-date.
8846 */
8847static int hmR0VmxExitXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8848{
8849 VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
8850 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
8851
8852 int rc = VERR_INTERNAL_ERROR_5;
8853 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
8854 {
8855#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
8856 /* If the guest is not in real-mode or we have unrestricted execution support, reflect #GP to the guest. */
8857 rc = hmR0VmxReadExitIntrInfoVmcs(pVCpu, pVmxTransient);
8858 rc |= hmR0VmxReadExitIntrErrorCodeVmcs(pVCpu, pVmxTransient);
8859 rc |= hmR0VmxReadExitInstrLenVmcs(pVCpu, pVmxTransient);
8860 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
8861 AssertRCReturn(rc, rc);
8862 Log4(("#GP Gst: RIP %#RX64 ErrorCode=%#x CR0=%#RX64 CPL=%u\n", pMixedCtx->rip, pVmxTransient->uExitIntrErrorCode,
8863 pMixedCtx->cr0, CPUMGetGuestCPL(pVCpu)));
8864 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
8865 pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, 0 /* GCPtrFaultAddress */);
8866 return rc;
8867#else
8868 /* We don't intercept #GP. */
8869 AssertMsgFailed(("Unexpected VM-exit caused by #GP exception\n"));
8870 return VERR_VMX_UNEXPECTED_EXCEPTION;
8871#endif
8872 }
8873
8874 Assert(CPUMIsGuestInRealModeEx(pMixedCtx));
8875 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
8876
8877 /* EMInterpretDisasCurrent() requires a lot of the state, save the entire state. */
8878 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
8879 AssertRCReturn(rc, rc);
8880
8881 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
8882 uint32_t cbOp = 0;
8883 PVM pVM = pVCpu->CTX_SUFF(pVM);
8884 rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, &cbOp);
8885 if (RT_SUCCESS(rc))
8886 {
8887 rc = VINF_SUCCESS;
8888 Assert(cbOp == pDis->cbInstr);
8889 Log4(("#GP Disas OpCode=%u CS:EIP %04x:%#RX64\n", pDis->pCurInstr->uOpcode, pMixedCtx->cs.Sel, pMixedCtx->rip));
8890 switch (pDis->pCurInstr->uOpcode)
8891 {
8892 case OP_CLI:
8893 {
8894 pMixedCtx->eflags.Bits.u1IF = 0;
8895 pMixedCtx->rip += pDis->cbInstr;
8896 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS;
8897 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCli);
8898 break;
8899 }
8900
8901 case OP_STI:
8902 {
8903 pMixedCtx->eflags.Bits.u1IF = 1;
8904 pMixedCtx->rip += pDis->cbInstr;
8905 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
8906 Assert(VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
8907 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS;
8908 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitSti);
8909 break;
8910 }
8911
8912 case OP_HLT:
8913 {
8914 rc = VINF_EM_HALT;
8915 pMixedCtx->rip += pDis->cbInstr;
8916 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP;
8917 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
8918 break;
8919 }
8920
8921 case OP_POPF:
8922 {
8923 Log4(("POPF CS:RIP %04x:%#RX64\n", pMixedCtx->cs.Sel, pMixedCtx->rip));
8924 uint32_t cbParm = 0;
8925 uint32_t uMask = 0;
8926 if (pDis->fPrefix & DISPREFIX_OPSIZE)
8927 {
8928 cbParm = 4;
8929 uMask = 0xffffffff;
8930 }
8931 else
8932 {
8933 cbParm = 2;
8934 uMask = 0xffff;
8935 }
8936
8937 /* Get the stack pointer & pop the contents of the stack onto EFlags. */
8938 RTGCPTR GCPtrStack = 0;
8939 X86EFLAGS uEflags;
8940 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
8941 &GCPtrStack);
8942 if (RT_SUCCESS(rc))
8943 {
8944 Assert(sizeof(uEflags.u32) >= cbParm);
8945 uEflags.u32 = 0;
8946 rc = PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &uEflags.u32, cbParm);
8947 }
8948 if (RT_FAILURE(rc))
8949 {
8950 rc = VERR_EM_INTERPRETER;
8951 break;
8952 }
8953 Log4(("POPF %x -> %#RX64 mask=%x RIP=%#RX64\n", uEflags.u, pMixedCtx->rsp, uMask, pMixedCtx->rip));
8954 pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ~(X86_EFL_POPF_BITS & uMask))
8955 | (uEflags.u32 & X86_EFL_POPF_BITS & uMask);
8956 /* The RF bit is always cleared by POPF; see Intel Instruction reference for POPF. */
8957 pMixedCtx->eflags.Bits.u1RF = 0;
8958 pMixedCtx->esp += cbParm;
8959 pMixedCtx->esp &= uMask;
8960 pMixedCtx->rip += pDis->cbInstr;
8961 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS;
8962 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPopf);
8963 break;
8964 }
8965
8966 case OP_PUSHF:
8967 {
8968 uint32_t cbParm = 0;
8969 uint32_t uMask = 0;
8970 if (pDis->fPrefix & DISPREFIX_OPSIZE)
8971 {
8972 cbParm = 4;
8973 uMask = 0xffffffff;
8974 }
8975 else
8976 {
8977 cbParm = 2;
8978 uMask = 0xffff;
8979 }
8980
8981 /* Get the stack pointer & push the contents of eflags onto the stack. */
8982 RTGCPTR GCPtrStack = 0;
8983 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), (pMixedCtx->esp - cbParm) & uMask,
8984 SELMTOFLAT_FLAGS_CPL0, &GCPtrStack);
8985 if (RT_FAILURE(rc))
8986 {
8987 rc = VERR_EM_INTERPRETER;
8988 break;
8989 }
8990 X86EFLAGS uEflags;
8991 uEflags = pMixedCtx->eflags;
8992 /* The RF & VM bits are cleared on image stored on stack; see Intel Instruction reference for PUSHF. */
8993 uEflags.Bits.u1RF = 0;
8994 uEflags.Bits.u1VM = 0;
8995
8996 rc = PGMPhysWrite(pVM, (RTGCPHYS)GCPtrStack, &uEflags.u, cbParm);
8997 if (RT_FAILURE(rc))
8998 {
8999 rc = VERR_EM_INTERPRETER;
9000 break;
9001 }
9002 Log4(("PUSHF %x -> %#RGv\n", uEflags.u, GCPtrStack));
9003 pMixedCtx->esp -= cbParm;
9004 pMixedCtx->esp &= uMask;
9005 pMixedCtx->rip += pDis->cbInstr;
9006 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP;
9007 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPushf);
9008 break;
9009 }
9010
9011 case OP_IRET:
9012 {
9013 /** @todo Handle 32-bit operand sizes and check stack limits. See Intel
9014 * instruction reference. */
9015 RTGCPTR GCPtrStack = 0;
9016 uint32_t uMask = 0xffff;
9017 uint16_t aIretFrame[3];
9018 if (pDis->fPrefix & (DISPREFIX_OPSIZE | DISPREFIX_ADDRSIZE))
9019 {
9020 rc = VERR_EM_INTERPRETER;
9021 break;
9022 }
9023 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
9024 &GCPtrStack);
9025 if (RT_SUCCESS(rc))
9026 rc = PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &aIretFrame[0], sizeof(aIretFrame));
9027 if (RT_FAILURE(rc))
9028 {
9029 rc = VERR_EM_INTERPRETER;
9030 break;
9031 }
9032 pMixedCtx->eip = 0;
9033 pMixedCtx->ip = aIretFrame[0];
9034 pMixedCtx->cs.Sel = aIretFrame[1];
9035 pMixedCtx->cs.ValidSel = aIretFrame[1];
9036 pMixedCtx->cs.u64Base = (uint64_t)pMixedCtx->cs.Sel << 4;
9037 pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ~(X86_EFL_POPF_BITS & uMask))
9038 | (aIretFrame[2] & X86_EFL_POPF_BITS & uMask);
9039 pMixedCtx->sp += sizeof(aIretFrame);
9040 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_SEGMENT_REGS | HM_CHANGED_GUEST_RSP
9041 | HM_CHANGED_GUEST_RFLAGS;
9042 Log4(("IRET %#RX32 to %04x:%x\n", GCPtrStack, pMixedCtx->cs.Sel, pMixedCtx->ip));
9043 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIret);
9044 break;
9045 }
9046
9047 case OP_INT:
9048 {
9049 uint16_t uVector = pDis->Param1.uValue & 0xff;
9050 hmR0VmxSetPendingIntN(pVCpu, pMixedCtx, uVector, pDis->cbInstr);
9051 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
9052 break;
9053 }
9054
9055 case OP_INTO:
9056 {
9057 if (pMixedCtx->eflags.Bits.u1OF)
9058 {
9059 hmR0VmxSetPendingXcptOF(pVCpu, pMixedCtx, pDis->cbInstr);
9060 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
9061 }
9062 break;
9063 }
9064
9065 default:
9066 {
9067 VBOXSTRICTRC rc2 = EMInterpretInstructionDisasState(pVCpu, pDis, CPUMCTX2CORE(pMixedCtx), 0 /* pvFault */,
9068 EMCODETYPE_SUPERVISOR);
9069 rc = VBOXSTRICTRC_VAL(rc2);
9070 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_ALL_GUEST;
9071 Log4(("#GP rc=%Rrc\n", rc));
9072 break;
9073 }
9074 }
9075 }
9076 else
9077 rc = VERR_EM_INTERPRETER;
9078
9079 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_EM_HALT,
9080 ("#GP Unexpected rc=%Rrc\n", rc));
9081 return rc;
9082}
9083
9084
9085/**
9086 * VM-exit exception handler wrapper for generic exceptions. Simply re-injects
9087 * the exception reported in the VMX transient structure back into the VM.
9088 *
9089 * @remarks Requires uExitIntrInfo in the VMX transient structure to be
9090 * up-to-date.
9091 */
9092static int hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
9093{
9094 VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
9095
9096 /* Re-inject the exception into the guest. This cannot be a double-fault condition which would have been handled in
9097 hmR0VmxCheckExitDueToEventDelivery(). */
9098 int rc = hmR0VmxReadExitIntrErrorCodeVmcs(pVCpu, pVmxTransient);
9099 rc |= hmR0VmxReadExitInstrLenVmcs(pVCpu, pVmxTransient);
9100 AssertRCReturn(rc, rc);
9101 Assert(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO);
9102 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
9103 pVmxTransient->cbInstr, pVmxTransient->uExitIntrErrorCode, 0 /* GCPtrFaultAddress */);
9104 return VINF_SUCCESS;
9105}
9106
9107
9108/**
9109 * VM-exit exception handler for #PF (Page-fault exception).
9110 */
9111static int hmR0VmxExitXcptPF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
9112{
9113 VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
9114 PVM pVM = pVCpu->CTX_SUFF(pVM);
9115 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9116 rc |= hmR0VmxReadExitIntrInfoVmcs(pVCpu, pVmxTransient);
9117 rc |= hmR0VmxReadExitIntrErrorCodeVmcs(pVCpu, pVmxTransient);
9118 AssertRCReturn(rc, rc);
9119
9120#if defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) || defined(HMVMX_ALWAYS_TRAP_PF)
9121 if (pVM->hm.s.fNestedPaging)
9122 {
9123 if (RT_LIKELY(!pVmxTransient->fVectoringPF))
9124 {
9125 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
9126 pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
9127 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
9128 0 /* cbInstr */, pVmxTransient->uExitIntrErrorCode, pVmxTransient->uExitQualification);
9129 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
9130 }
9131 else
9132 {
9133 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
9134 pVCpu->hm.s.Event.fPending = false; /* A vectoring #PF. */
9135 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
9136 Log4(("Pending #DF due to vectoring #PF. NP\n"));
9137 }
9138 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
9139 return rc;
9140 }
9141#else
9142 Assert(!pVM->hm.s.fNestedPaging);
9143#endif
9144
9145#ifdef VBOX_HM_WITH_GUEST_PATCHING
9146 rc = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
9147 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
9148 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
9149 AssertRCReturn(rc, rc);
9150 /* Shortcut for APIC TPR access, only for 32-bit guests. */
9151 if ( pVM->hm.s.fTRPPatchingAllowed
9152 && pVM->hm.s.pGuestPatchMem
9153 && (pVmxTransient->uExitQualification & 0xfff) == 0x80 /* TPR offset */
9154 && !(pVmxTransient->uExitIntrErrorCode & X86_TRAP_PF_P) /* Page not present */
9155 && CPUMGetGuestCPL(pVCpu) == 0 /* Requires CR0, EFLAGS, segments. */
9156 && !CPUMIsGuestInLongModeEx(pMixedCtx) /* Requires EFER. */
9157 && pVM->hm.s.cPatches < RT_ELEMENTS(pVM->hm.s.aPatches))
9158 {
9159 RTGCPHYS GCPhys;
9160 RTGCPHYS GCPhysApicBase = (pMixedCtx->msrApicBase & PAGE_BASE_GC_MASK);
9161 rc = PGMGstGetPage(pVCpu, (RTGCPTR)pVmxTransient->uExitQualification, NULL /* pfFlags */, &GCPhys);
9162 if ( rc == VINF_SUCCESS
9163 && GCPhys == GCPhysApicBase)
9164 {
9165 rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
9166 AssertRCReturn(rc, rc);
9167
9168 /* Only attempt to patch the instruction once. */
9169 PHMTPRPATCH pPatch = (PHMTPRPATCH)RTAvloU32Get(&pVM->hm.s.PatchTree, (AVLOU32KEY)pMixedCtx->eip);
9170 if (!pPatch)
9171 return VINF_EM_HM_PATCH_TPR_INSTR;
9172 }
9173 }
9174#endif
9175
9176 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
9177 AssertRCReturn(rc, rc);
9178
9179 Log4(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQualification,
9180 pMixedCtx->cs.Sel, pMixedCtx->rip, pVmxTransient->uExitIntrErrorCode, pMixedCtx->cr3));
9181
9182 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQualification, (RTGCUINT)pVmxTransient->uExitIntrErrorCode);
9183 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntrErrorCode, CPUMCTX2CORE(pMixedCtx),
9184 (RTGCPTR)pVmxTransient->uExitQualification);
9185
9186 Log4(("#PF: rc=%Rrc\n", rc));
9187 if (rc == VINF_SUCCESS)
9188 {
9189 /* Successfully synced shadow pages tables or emulated an MMIO instruction. */
9190 /** @todo this isn't quite right, what if guest does lgdt with some MMIO
9191 * memory? We don't update the whole state here... */
9192 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
9193 | HM_CHANGED_VMX_GUEST_APIC_STATE;
9194 TRPMResetTrap(pVCpu);
9195 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
9196 return rc;
9197 }
9198 else if (rc == VINF_EM_RAW_GUEST_TRAP)
9199 {
9200 if (!pVmxTransient->fVectoringPF)
9201 {
9202 /* It's a guest page fault and needs to be reflected to the guest. */
9203 uint32_t uGstErrorCode = TRPMGetErrorCode(pVCpu);
9204 TRPMResetTrap(pVCpu);
9205 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
9206 pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
9207 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
9208 0 /* cbInstr */, uGstErrorCode, pVmxTransient->uExitQualification);
9209 }
9210 else
9211 {
9212 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
9213 TRPMResetTrap(pVCpu);
9214 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF for replace it with #DF. */
9215 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
9216 Log4(("#PF: Pending #DF due to vectoring #PF\n"));
9217 }
9218
9219 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
9220 return VINF_SUCCESS;
9221 }
9222
9223 TRPMResetTrap(pVCpu);
9224 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
9225 return rc;
9226}
9227
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