VirtualBox

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

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

VMM/HMVMXR0: Disable flushing of the log while loading the guest-state (only while entering VT-x from ring-3, debug builds).

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