VirtualBox

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

Last change on this file since 64655 was 64655, checked in by vboxsync, 9 years ago

VMM,recompiler: Get rid of PDM APIC interfaces reducing one level of indirection, cleaned up some unused stuff in recompiler.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 583.7 KB
Line 
1/* $Id: HMVMXR0.cpp 64655 2016-11-14 10:46:07Z vboxsync $ */
2/** @file
3 * HM VMX (Intel VT-x) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2012-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_HM
23#include <iprt/x86.h>
24#include <iprt/asm-amd64-x86.h>
25#include <iprt/thread.h>
26
27#include <VBox/vmm/pdmapi.h>
28#include <VBox/vmm/dbgf.h>
29#include <VBox/vmm/iem.h>
30#include <VBox/vmm/iom.h>
31#include <VBox/vmm/selm.h>
32#include <VBox/vmm/tm.h>
33#include <VBox/vmm/gim.h>
34#include <VBox/vmm/apic.h>
35#ifdef VBOX_WITH_REM
36# include <VBox/vmm/rem.h>
37#endif
38#include "HMInternal.h"
39#include <VBox/vmm/vm.h>
40#include "HMVMXR0.h"
41#include "dtrace/VBoxVMM.h"
42
43#ifdef DEBUG_ramshankar
44# define HMVMX_ALWAYS_SAVE_GUEST_RFLAGS
45# define HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE
46# define HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
47# define HMVMX_ALWAYS_CHECK_GUEST_STATE
48# define HMVMX_ALWAYS_TRAP_ALL_XCPTS
49# define HMVMX_ALWAYS_TRAP_PF
50# define HMVMX_ALWAYS_SWAP_FPU_STATE
51# define HMVMX_ALWAYS_FLUSH_TLB
52# define HMVMX_ALWAYS_SWAP_EFER
53#endif
54
55
56/*********************************************************************************************************************************
57* Defined Constants And Macros *
58*********************************************************************************************************************************/
59/** Use the function table. */
60#define HMVMX_USE_FUNCTION_TABLE
61
62/** Determine which tagged-TLB flush handler to use. */
63#define HMVMX_FLUSH_TAGGED_TLB_EPT_VPID 0
64#define HMVMX_FLUSH_TAGGED_TLB_EPT 1
65#define HMVMX_FLUSH_TAGGED_TLB_VPID 2
66#define HMVMX_FLUSH_TAGGED_TLB_NONE 3
67
68/** @name Updated-guest-state flags.
69 * @{ */
70#define HMVMX_UPDATED_GUEST_RIP RT_BIT(0)
71#define HMVMX_UPDATED_GUEST_RSP RT_BIT(1)
72#define HMVMX_UPDATED_GUEST_RFLAGS RT_BIT(2)
73#define HMVMX_UPDATED_GUEST_CR0 RT_BIT(3)
74#define HMVMX_UPDATED_GUEST_CR3 RT_BIT(4)
75#define HMVMX_UPDATED_GUEST_CR4 RT_BIT(5)
76#define HMVMX_UPDATED_GUEST_GDTR RT_BIT(6)
77#define HMVMX_UPDATED_GUEST_IDTR RT_BIT(7)
78#define HMVMX_UPDATED_GUEST_LDTR RT_BIT(8)
79#define HMVMX_UPDATED_GUEST_TR RT_BIT(9)
80#define HMVMX_UPDATED_GUEST_SEGMENT_REGS RT_BIT(10)
81#define HMVMX_UPDATED_GUEST_DEBUG RT_BIT(11)
82#define HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR RT_BIT(12)
83#define HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR RT_BIT(13)
84#define HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR RT_BIT(14)
85#define HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS RT_BIT(15)
86#define HMVMX_UPDATED_GUEST_LAZY_MSRS RT_BIT(16)
87#define HMVMX_UPDATED_GUEST_ACTIVITY_STATE RT_BIT(17)
88#define HMVMX_UPDATED_GUEST_INTR_STATE RT_BIT(18)
89#define HMVMX_UPDATED_GUEST_APIC_STATE RT_BIT(19)
90#define HMVMX_UPDATED_GUEST_ALL ( HMVMX_UPDATED_GUEST_RIP \
91 | HMVMX_UPDATED_GUEST_RSP \
92 | HMVMX_UPDATED_GUEST_RFLAGS \
93 | HMVMX_UPDATED_GUEST_CR0 \
94 | HMVMX_UPDATED_GUEST_CR3 \
95 | HMVMX_UPDATED_GUEST_CR4 \
96 | HMVMX_UPDATED_GUEST_GDTR \
97 | HMVMX_UPDATED_GUEST_IDTR \
98 | HMVMX_UPDATED_GUEST_LDTR \
99 | HMVMX_UPDATED_GUEST_TR \
100 | HMVMX_UPDATED_GUEST_SEGMENT_REGS \
101 | HMVMX_UPDATED_GUEST_DEBUG \
102 | HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR \
103 | HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR \
104 | HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR \
105 | HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS \
106 | HMVMX_UPDATED_GUEST_LAZY_MSRS \
107 | HMVMX_UPDATED_GUEST_ACTIVITY_STATE \
108 | HMVMX_UPDATED_GUEST_INTR_STATE \
109 | HMVMX_UPDATED_GUEST_APIC_STATE)
110/** @} */
111
112/** @name
113 * Flags to skip redundant reads of some common VMCS fields that are not part of
114 * the guest-CPU state but are in the transient structure.
115 */
116#define HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO RT_BIT(0)
117#define HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE RT_BIT(1)
118#define HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION RT_BIT(2)
119#define HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN RT_BIT(3)
120#define HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO RT_BIT(4)
121#define HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE RT_BIT(5)
122#define HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_INFO RT_BIT(6)
123/** @} */
124
125/** @name
126 * States of the VMCS.
127 *
128 * This does not reflect all possible VMCS states but currently only those
129 * needed for maintaining the VMCS consistently even when thread-context hooks
130 * are used. Maybe later this can be extended (i.e. Nested Virtualization).
131 */
132#define HMVMX_VMCS_STATE_CLEAR RT_BIT(0)
133#define HMVMX_VMCS_STATE_ACTIVE RT_BIT(1)
134#define HMVMX_VMCS_STATE_LAUNCHED RT_BIT(2)
135/** @} */
136
137/**
138 * Exception bitmap mask for real-mode guests (real-on-v86).
139 *
140 * We need to intercept all exceptions manually except:
141 * - \#NM, \#MF handled in hmR0VmxLoadSharedCR0().
142 * - \#AC and \#DB are always intercepted to prevent the CPU from deadlocking
143 * due to bugs in Intel CPUs.
144 * - \#PF need not be intercepted even in real-mode if we have Nested Paging
145 * support.
146 */
147#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) /* always: | RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI) \
148 | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
149 | RT_BIT(X86_XCPT_UD) /* RT_BIT(X86_XCPT_NM) */ | RT_BIT(X86_XCPT_DF) \
150 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
151 | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
152 /* RT_BIT(X86_XCPT_MF) always: | RT_BIT(X86_XCPT_AC) */ | RT_BIT(X86_XCPT_MC) \
153 | RT_BIT(X86_XCPT_XF))
154
155/**
156 * Exception bitmap mask for all contributory exceptions.
157 *
158 * Page fault is deliberately excluded here as it's conditional as to whether
159 * it's contributory or benign. Page faults are handled separately.
160 */
161#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) \
162 | RT_BIT(X86_XCPT_DE))
163
164/** Maximum VM-instruction error number. */
165#define HMVMX_INSTR_ERROR_MAX 28
166
167/** Profiling macro. */
168#ifdef HM_PROFILE_EXIT_DISPATCH
169# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitDispatch, ed)
170# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitDispatch, ed)
171#else
172# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
173# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
174#endif
175
176/** Assert that preemption is disabled or covered by thread-context hooks. */
177#define HMVMX_ASSERT_PREEMPT_SAFE() Assert( VMMR0ThreadCtxHookIsEnabled(pVCpu) \
178 || !RTThreadPreemptIsEnabled(NIL_RTTHREAD));
179
180/** Assert that we haven't migrated CPUs when thread-context hooks are not
181 * used. */
182#define HMVMX_ASSERT_CPU_SAFE() AssertMsg( VMMR0ThreadCtxHookIsEnabled(pVCpu) \
183 || pVCpu->hm.s.idEnteredCpu == RTMpCpuId(), \
184 ("Illegal migration! Entered on CPU %u Current %u\n", \
185 pVCpu->hm.s.idEnteredCpu, RTMpCpuId())); \
186
187/** Helper macro for VM-exit handlers called unexpectedly. */
188#define HMVMX_RETURN_UNEXPECTED_EXIT() \
189 do { \
190 pVCpu->hm.s.u32HMError = pVmxTransient->uExitReason; \
191 return VERR_VMX_UNEXPECTED_EXIT; \
192 } while (0)
193
194
195/*********************************************************************************************************************************
196* Structures and Typedefs *
197*********************************************************************************************************************************/
198/**
199 * VMX transient state.
200 *
201 * A state structure for holding miscellaneous information across
202 * VMX non-root operation and restored after the transition.
203 */
204typedef struct VMXTRANSIENT
205{
206 /** The host's rflags/eflags. */
207 RTCCUINTREG fEFlags;
208#if HC_ARCH_BITS == 32
209 uint32_t u32Alignment0;
210#endif
211 /** The guest's TPR value used for TPR shadowing. */
212 uint8_t u8GuestTpr;
213 /** Alignment. */
214 uint8_t abAlignment0[7];
215
216 /** The basic VM-exit reason. */
217 uint16_t uExitReason;
218 /** Alignment. */
219 uint16_t u16Alignment0;
220 /** The VM-exit interruption error code. */
221 uint32_t uExitIntErrorCode;
222 /** The VM-exit exit code qualification. */
223 uint64_t uExitQualification;
224
225 /** The VM-exit interruption-information field. */
226 uint32_t uExitIntInfo;
227 /** The VM-exit instruction-length field. */
228 uint32_t cbInstr;
229 /** The VM-exit instruction-information field. */
230 union
231 {
232 /** Plain unsigned int representation. */
233 uint32_t u;
234 /** INS and OUTS information. */
235 struct
236 {
237 uint32_t u7Reserved0 : 7;
238 /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */
239 uint32_t u3AddrSize : 3;
240 uint32_t u5Reserved1 : 5;
241 /** The segment register (X86_SREG_XXX). */
242 uint32_t iSegReg : 3;
243 uint32_t uReserved2 : 14;
244 } StrIo;
245 } ExitInstrInfo;
246 /** Whether the VM-entry failed or not. */
247 bool fVMEntryFailed;
248 /** Alignment. */
249 uint8_t abAlignment1[3];
250
251 /** The VM-entry interruption-information field. */
252 uint32_t uEntryIntInfo;
253 /** The VM-entry exception error code field. */
254 uint32_t uEntryXcptErrorCode;
255 /** The VM-entry instruction length field. */
256 uint32_t cbEntryInstr;
257
258 /** IDT-vectoring information field. */
259 uint32_t uIdtVectoringInfo;
260 /** IDT-vectoring error code. */
261 uint32_t uIdtVectoringErrorCode;
262
263 /** Mask of currently read VMCS fields; HMVMX_UPDATED_TRANSIENT_*. */
264 uint32_t fVmcsFieldsRead;
265
266 /** Whether the guest FPU was active at the time of VM-exit. */
267 bool fWasGuestFPUStateActive;
268 /** Whether the guest debug state was active at the time of VM-exit. */
269 bool fWasGuestDebugStateActive;
270 /** Whether the hyper debug state was active at the time of VM-exit. */
271 bool fWasHyperDebugStateActive;
272 /** Whether TSC-offsetting should be setup before VM-entry. */
273 bool fUpdateTscOffsettingAndPreemptTimer;
274 /** Whether the VM-exit was caused by a page-fault during delivery of a
275 * contributory exception or a page-fault. */
276 bool fVectoringDoublePF;
277 /** Whether the VM-exit was caused by a page-fault during delivery of an
278 * external interrupt or NMI. */
279 bool fVectoringPF;
280} VMXTRANSIENT;
281AssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, sizeof(uint64_t));
282AssertCompileMemberAlignment(VMXTRANSIENT, uExitIntInfo, sizeof(uint64_t));
283AssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntInfo, sizeof(uint64_t));
284AssertCompileMemberAlignment(VMXTRANSIENT, fWasGuestFPUStateActive, sizeof(uint64_t));
285AssertCompileMemberSize(VMXTRANSIENT, ExitInstrInfo, sizeof(uint32_t));
286/** Pointer to VMX transient state. */
287typedef VMXTRANSIENT *PVMXTRANSIENT;
288
289
290/**
291 * MSR-bitmap read permissions.
292 */
293typedef enum VMXMSREXITREAD
294{
295 /** Reading this MSR causes a VM-exit. */
296 VMXMSREXIT_INTERCEPT_READ = 0xb,
297 /** Reading this MSR does not cause a VM-exit. */
298 VMXMSREXIT_PASSTHRU_READ
299} VMXMSREXITREAD;
300/** Pointer to MSR-bitmap read permissions. */
301typedef VMXMSREXITREAD* PVMXMSREXITREAD;
302
303/**
304 * MSR-bitmap write permissions.
305 */
306typedef enum VMXMSREXITWRITE
307{
308 /** Writing to this MSR causes a VM-exit. */
309 VMXMSREXIT_INTERCEPT_WRITE = 0xd,
310 /** Writing to this MSR does not cause a VM-exit. */
311 VMXMSREXIT_PASSTHRU_WRITE
312} VMXMSREXITWRITE;
313/** Pointer to MSR-bitmap write permissions. */
314typedef VMXMSREXITWRITE* PVMXMSREXITWRITE;
315
316
317/**
318 * VMX VM-exit handler.
319 *
320 * @returns Strict VBox status code (i.e. informational status codes too).
321 * @param pVCpu The cross context virtual CPU structure.
322 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
323 * out-of-sync. Make sure to update the required
324 * fields before using them.
325 * @param pVmxTransient Pointer to the VMX-transient structure.
326 */
327#ifndef HMVMX_USE_FUNCTION_TABLE
328typedef DECLINLINE(VBOXSTRICTRC) FNVMXEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
329#else
330typedef DECLCALLBACK(VBOXSTRICTRC) FNVMXEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
331/** Pointer to VM-exit handler. */
332typedef FNVMXEXITHANDLER *PFNVMXEXITHANDLER;
333#endif
334
335/**
336 * VMX VM-exit handler, non-strict status code.
337 *
338 * This is generally the same as FNVMXEXITHANDLER, the NSRC bit is just FYI.
339 *
340 * @returns VBox status code, no informational status code returned.
341 * @param pVCpu The cross context virtual CPU structure.
342 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
343 * out-of-sync. Make sure to update the required
344 * fields before using them.
345 * @param pVmxTransient Pointer to the VMX-transient structure.
346 *
347 * @remarks This is not used on anything returning VERR_EM_INTERPRETER as the
348 * use of that status code will be replaced with VINF_EM_SOMETHING
349 * later when switching over to IEM.
350 */
351#ifndef HMVMX_USE_FUNCTION_TABLE
352typedef DECLINLINE(int) FNVMXEXITHANDLERNSRC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
353#else
354typedef FNVMXEXITHANDLER FNVMXEXITHANDLERNSRC;
355#endif
356
357
358/*********************************************************************************************************************************
359* Internal Functions *
360*********************************************************************************************************************************/
361static void hmR0VmxFlushEpt(PVMCPU pVCpu, VMXFLUSHEPT enmFlush);
362static void hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMXFLUSHVPID enmFlush, RTGCPTR GCPtr);
363static void hmR0VmxClearIntNmiWindowsVmcs(PVMCPU pVCpu);
364static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
365 uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress,
366 bool fStepping, uint32_t *puIntState);
367#if HC_ARCH_BITS == 32
368static int hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu);
369#endif
370#ifndef HMVMX_USE_FUNCTION_TABLE
371DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason);
372# define HMVMX_EXIT_DECL DECLINLINE(VBOXSTRICTRC)
373# define HMVMX_EXIT_NSRC_DECL DECLINLINE(int)
374#else
375# define HMVMX_EXIT_DECL static DECLCALLBACK(VBOXSTRICTRC)
376# define HMVMX_EXIT_NSRC_DECL HMVMX_EXIT_DECL
377#endif
378
379
380/** @name VM-exit handlers.
381 * @{
382 */
383static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmi;
384static FNVMXEXITHANDLER hmR0VmxExitExtInt;
385static FNVMXEXITHANDLER hmR0VmxExitTripleFault;
386static FNVMXEXITHANDLERNSRC hmR0VmxExitInitSignal;
387static FNVMXEXITHANDLERNSRC hmR0VmxExitSipi;
388static FNVMXEXITHANDLERNSRC hmR0VmxExitIoSmi;
389static FNVMXEXITHANDLERNSRC hmR0VmxExitSmi;
390static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindow;
391static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindow;
392static FNVMXEXITHANDLER hmR0VmxExitTaskSwitch;
393static FNVMXEXITHANDLER hmR0VmxExitCpuid;
394static FNVMXEXITHANDLER hmR0VmxExitGetsec;
395static FNVMXEXITHANDLER hmR0VmxExitHlt;
396static FNVMXEXITHANDLERNSRC hmR0VmxExitInvd;
397static FNVMXEXITHANDLER hmR0VmxExitInvlpg;
398static FNVMXEXITHANDLER hmR0VmxExitRdpmc;
399static FNVMXEXITHANDLER hmR0VmxExitVmcall;
400static FNVMXEXITHANDLER hmR0VmxExitRdtsc;
401static FNVMXEXITHANDLERNSRC hmR0VmxExitRsm;
402static FNVMXEXITHANDLERNSRC hmR0VmxExitSetPendingXcptUD;
403static FNVMXEXITHANDLER hmR0VmxExitMovCRx;
404static FNVMXEXITHANDLER hmR0VmxExitMovDRx;
405static FNVMXEXITHANDLER hmR0VmxExitIoInstr;
406static FNVMXEXITHANDLER hmR0VmxExitRdmsr;
407static FNVMXEXITHANDLER hmR0VmxExitWrmsr;
408static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestState;
409static FNVMXEXITHANDLERNSRC hmR0VmxExitErrMsrLoad;
410static FNVMXEXITHANDLERNSRC hmR0VmxExitErrUndefined;
411static FNVMXEXITHANDLER hmR0VmxExitMwait;
412static FNVMXEXITHANDLER hmR0VmxExitMtf;
413static FNVMXEXITHANDLER hmR0VmxExitMonitor;
414static FNVMXEXITHANDLER hmR0VmxExitPause;
415static FNVMXEXITHANDLERNSRC hmR0VmxExitErrMachineCheck;
416static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThreshold;
417static FNVMXEXITHANDLER hmR0VmxExitApicAccess;
418static FNVMXEXITHANDLER hmR0VmxExitXdtrAccess;
419static FNVMXEXITHANDLER hmR0VmxExitXdtrAccess;
420static FNVMXEXITHANDLER hmR0VmxExitEptViolation;
421static FNVMXEXITHANDLER hmR0VmxExitEptMisconfig;
422static FNVMXEXITHANDLER hmR0VmxExitRdtscp;
423static FNVMXEXITHANDLER hmR0VmxExitPreemptTimer;
424static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvd;
425static FNVMXEXITHANDLER hmR0VmxExitXsetbv;
426static FNVMXEXITHANDLER hmR0VmxExitRdrand;
427static FNVMXEXITHANDLER hmR0VmxExitInvpcid;
428/** @} */
429
430static int hmR0VmxExitXcptNM(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
431static int hmR0VmxExitXcptPF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
432static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
433static int hmR0VmxExitXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
434static int hmR0VmxExitXcptBP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
435static int hmR0VmxExitXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
436static int hmR0VmxExitXcptAC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
437static int hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
438static uint32_t hmR0VmxCheckGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx);
439
440
441/*********************************************************************************************************************************
442* Global Variables *
443*********************************************************************************************************************************/
444#ifdef HMVMX_USE_FUNCTION_TABLE
445
446/**
447 * VMX_EXIT dispatch table.
448 */
449static const PFNVMXEXITHANDLER g_apfnVMExitHandlers[VMX_EXIT_MAX + 1] =
450{
451 /* 00 VMX_EXIT_XCPT_OR_NMI */ hmR0VmxExitXcptOrNmi,
452 /* 01 VMX_EXIT_EXT_INT */ hmR0VmxExitExtInt,
453 /* 02 VMX_EXIT_TRIPLE_FAULT */ hmR0VmxExitTripleFault,
454 /* 03 VMX_EXIT_INIT_SIGNAL */ hmR0VmxExitInitSignal,
455 /* 04 VMX_EXIT_SIPI */ hmR0VmxExitSipi,
456 /* 05 VMX_EXIT_IO_SMI */ hmR0VmxExitIoSmi,
457 /* 06 VMX_EXIT_SMI */ hmR0VmxExitSmi,
458 /* 07 VMX_EXIT_INT_WINDOW */ hmR0VmxExitIntWindow,
459 /* 08 VMX_EXIT_NMI_WINDOW */ hmR0VmxExitNmiWindow,
460 /* 09 VMX_EXIT_TASK_SWITCH */ hmR0VmxExitTaskSwitch,
461 /* 10 VMX_EXIT_CPUID */ hmR0VmxExitCpuid,
462 /* 11 VMX_EXIT_GETSEC */ hmR0VmxExitGetsec,
463 /* 12 VMX_EXIT_HLT */ hmR0VmxExitHlt,
464 /* 13 VMX_EXIT_INVD */ hmR0VmxExitInvd,
465 /* 14 VMX_EXIT_INVLPG */ hmR0VmxExitInvlpg,
466 /* 15 VMX_EXIT_RDPMC */ hmR0VmxExitRdpmc,
467 /* 16 VMX_EXIT_RDTSC */ hmR0VmxExitRdtsc,
468 /* 17 VMX_EXIT_RSM */ hmR0VmxExitRsm,
469 /* 18 VMX_EXIT_VMCALL */ hmR0VmxExitVmcall,
470 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitSetPendingXcptUD,
471 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitSetPendingXcptUD,
472 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitSetPendingXcptUD,
473 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitSetPendingXcptUD,
474 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitSetPendingXcptUD,
475 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitSetPendingXcptUD,
476 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitSetPendingXcptUD,
477 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitSetPendingXcptUD,
478 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitSetPendingXcptUD,
479 /* 28 VMX_EXIT_MOV_CRX */ hmR0VmxExitMovCRx,
480 /* 29 VMX_EXIT_MOV_DRX */ hmR0VmxExitMovDRx,
481 /* 30 VMX_EXIT_IO_INSTR */ hmR0VmxExitIoInstr,
482 /* 31 VMX_EXIT_RDMSR */ hmR0VmxExitRdmsr,
483 /* 32 VMX_EXIT_WRMSR */ hmR0VmxExitWrmsr,
484 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ hmR0VmxExitErrInvalidGuestState,
485 /* 34 VMX_EXIT_ERR_MSR_LOAD */ hmR0VmxExitErrMsrLoad,
486 /* 35 UNDEFINED */ hmR0VmxExitErrUndefined,
487 /* 36 VMX_EXIT_MWAIT */ hmR0VmxExitMwait,
488 /* 37 VMX_EXIT_MTF */ hmR0VmxExitMtf,
489 /* 38 UNDEFINED */ hmR0VmxExitErrUndefined,
490 /* 39 VMX_EXIT_MONITOR */ hmR0VmxExitMonitor,
491 /* 40 UNDEFINED */ hmR0VmxExitPause,
492 /* 41 VMX_EXIT_PAUSE */ hmR0VmxExitErrMachineCheck,
493 /* 42 VMX_EXIT_ERR_MACHINE_CHECK */ hmR0VmxExitErrUndefined,
494 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ hmR0VmxExitTprBelowThreshold,
495 /* 44 VMX_EXIT_APIC_ACCESS */ hmR0VmxExitApicAccess,
496 /* 45 UNDEFINED */ hmR0VmxExitErrUndefined,
497 /* 46 VMX_EXIT_XDTR_ACCESS */ hmR0VmxExitXdtrAccess,
498 /* 47 VMX_EXIT_TR_ACCESS */ hmR0VmxExitXdtrAccess,
499 /* 48 VMX_EXIT_EPT_VIOLATION */ hmR0VmxExitEptViolation,
500 /* 49 VMX_EXIT_EPT_MISCONFIG */ hmR0VmxExitEptMisconfig,
501 /* 50 VMX_EXIT_INVEPT */ hmR0VmxExitSetPendingXcptUD,
502 /* 51 VMX_EXIT_RDTSCP */ hmR0VmxExitRdtscp,
503 /* 52 VMX_EXIT_PREEMPT_TIMER */ hmR0VmxExitPreemptTimer,
504 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitSetPendingXcptUD,
505 /* 54 VMX_EXIT_WBINVD */ hmR0VmxExitWbinvd,
506 /* 55 VMX_EXIT_XSETBV */ hmR0VmxExitXsetbv,
507 /* 56 VMX_EXIT_APIC_WRITE */ hmR0VmxExitErrUndefined,
508 /* 57 VMX_EXIT_RDRAND */ hmR0VmxExitRdrand,
509 /* 58 VMX_EXIT_INVPCID */ hmR0VmxExitInvpcid,
510 /* 59 VMX_EXIT_VMFUNC */ hmR0VmxExitSetPendingXcptUD,
511 /* 60 VMX_EXIT_RESERVED_60 */ hmR0VmxExitErrUndefined,
512 /* 61 VMX_EXIT_RDSEED */ hmR0VmxExitErrUndefined, /* only spurious exits, so undefined */
513 /* 62 VMX_EXIT_RESERVED_62 */ hmR0VmxExitErrUndefined,
514 /* 63 VMX_EXIT_XSAVES */ hmR0VmxExitSetPendingXcptUD,
515 /* 64 VMX_EXIT_XRSTORS */ hmR0VmxExitSetPendingXcptUD,
516};
517#endif /* HMVMX_USE_FUNCTION_TABLE */
518
519#ifdef VBOX_STRICT
520static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
521{
522 /* 0 */ "(Not Used)",
523 /* 1 */ "VMCALL executed in VMX root operation.",
524 /* 2 */ "VMCLEAR with invalid physical address.",
525 /* 3 */ "VMCLEAR with VMXON pointer.",
526 /* 4 */ "VMLAUNCH with non-clear VMCS.",
527 /* 5 */ "VMRESUME with non-launched VMCS.",
528 /* 6 */ "VMRESUME after VMXOFF",
529 /* 7 */ "VM-entry with invalid control fields.",
530 /* 8 */ "VM-entry with invalid host state fields.",
531 /* 9 */ "VMPTRLD with invalid physical address.",
532 /* 10 */ "VMPTRLD with VMXON pointer.",
533 /* 11 */ "VMPTRLD with incorrect revision identifier.",
534 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
535 /* 13 */ "VMWRITE to read-only VMCS component.",
536 /* 14 */ "(Not Used)",
537 /* 15 */ "VMXON executed in VMX root operation.",
538 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
539 /* 17 */ "VM-entry with non-launched executing VMCS.",
540 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
541 /* 19 */ "VMCALL with non-clear VMCS.",
542 /* 20 */ "VMCALL with invalid VM-exit control fields.",
543 /* 21 */ "(Not Used)",
544 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
545 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
546 /* 24 */ "VMCALL with invalid SMM-monitor features.",
547 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
548 /* 26 */ "VM-entry with events blocked by MOV SS.",
549 /* 27 */ "(Not Used)",
550 /* 28 */ "Invalid operand to INVEPT/INVVPID."
551};
552#endif /* VBOX_STRICT */
553
554
555
556/**
557 * Updates the VM's last error record.
558 *
559 * If there was a VMX instruction error, reads the error data from the VMCS and
560 * updates VCPU's last error record as well.
561 *
562 * @param pVM The cross context VM structure.
563 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
564 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
565 * VERR_VMX_INVALID_VMCS_FIELD.
566 * @param rc The error code.
567 */
568static void hmR0VmxUpdateErrorRecord(PVM pVM, PVMCPU pVCpu, int rc)
569{
570 AssertPtr(pVM);
571 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
572 || rc == VERR_VMX_UNABLE_TO_START_VM)
573 {
574 AssertPtrReturnVoid(pVCpu);
575 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
576 }
577 pVM->hm.s.lLastError = rc;
578}
579
580
581/**
582 * Reads the VM-entry interruption-information field from the VMCS into the VMX
583 * transient structure.
584 *
585 * @returns VBox status code.
586 * @param pVmxTransient Pointer to the VMX transient structure.
587 *
588 * @remarks No-long-jump zone!!!
589 */
590DECLINLINE(int) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
591{
592 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
593 AssertRCReturn(rc, rc);
594 return VINF_SUCCESS;
595}
596
597
598#ifdef VBOX_STRICT
599/**
600 * Reads the VM-entry exception error code field from the VMCS into
601 * the VMX transient structure.
602 *
603 * @returns VBox status code.
604 * @param pVmxTransient Pointer to the VMX transient structure.
605 *
606 * @remarks No-long-jump zone!!!
607 */
608DECLINLINE(int) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
609{
610 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
611 AssertRCReturn(rc, rc);
612 return VINF_SUCCESS;
613}
614#endif /* VBOX_STRICT */
615
616
617#ifdef VBOX_STRICT
618/**
619 * Reads the VM-entry exception error code field from the VMCS into
620 * the VMX transient structure.
621 *
622 * @returns VBox status code.
623 * @param pVmxTransient Pointer to the VMX transient structure.
624 *
625 * @remarks No-long-jump zone!!!
626 */
627DECLINLINE(int) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
628{
629 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
630 AssertRCReturn(rc, rc);
631 return VINF_SUCCESS;
632}
633#endif /* VBOX_STRICT */
634
635
636/**
637 * Reads the VM-exit interruption-information field from the VMCS into the VMX
638 * transient structure.
639 *
640 * @returns VBox status code.
641 * @param pVmxTransient Pointer to the VMX transient structure.
642 */
643DECLINLINE(int) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
644{
645 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO))
646 {
647 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
648 AssertRCReturn(rc, rc);
649 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO;
650 }
651 return VINF_SUCCESS;
652}
653
654
655/**
656 * Reads the VM-exit interruption error code from the VMCS into the VMX
657 * transient structure.
658 *
659 * @returns VBox status code.
660 * @param pVmxTransient Pointer to the VMX transient structure.
661 */
662DECLINLINE(int) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
663{
664 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE))
665 {
666 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
667 AssertRCReturn(rc, rc);
668 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE;
669 }
670 return VINF_SUCCESS;
671}
672
673
674/**
675 * Reads the VM-exit instruction length field from the VMCS into the VMX
676 * transient structure.
677 *
678 * @returns VBox status code.
679 * @param pVmxTransient Pointer to the VMX transient structure.
680 */
681DECLINLINE(int) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
682{
683 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN))
684 {
685 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbInstr);
686 AssertRCReturn(rc, rc);
687 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN;
688 }
689 return VINF_SUCCESS;
690}
691
692
693/**
694 * Reads the VM-exit instruction-information field from the VMCS into
695 * the VMX transient structure.
696 *
697 * @returns VBox status code.
698 * @param pVmxTransient Pointer to the VMX transient structure.
699 */
700DECLINLINE(int) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
701{
702 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_INFO))
703 {
704 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
705 AssertRCReturn(rc, rc);
706 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_INFO;
707 }
708 return VINF_SUCCESS;
709}
710
711
712/**
713 * Reads the exit code qualification from the VMCS into the VMX transient
714 * structure.
715 *
716 * @returns VBox status code.
717 * @param pVCpu The cross context virtual CPU structure of the
718 * calling EMT. (Required for the VMCS cache case.)
719 * @param pVmxTransient Pointer to the VMX transient structure.
720 */
721DECLINLINE(int) hmR0VmxReadExitQualificationVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
722{
723 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION))
724 {
725 int rc = VMXReadVmcsGstN(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQualification); NOREF(pVCpu);
726 AssertRCReturn(rc, rc);
727 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION;
728 }
729 return VINF_SUCCESS;
730}
731
732
733/**
734 * Reads the IDT-vectoring information field from the VMCS into the VMX
735 * transient structure.
736 *
737 * @returns VBox status code.
738 * @param pVmxTransient Pointer to the VMX transient structure.
739 *
740 * @remarks No-long-jump zone!!!
741 */
742DECLINLINE(int) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
743{
744 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO))
745 {
746 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_INFO, &pVmxTransient->uIdtVectoringInfo);
747 AssertRCReturn(rc, rc);
748 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO;
749 }
750 return VINF_SUCCESS;
751}
752
753
754/**
755 * Reads the IDT-vectoring error code from the VMCS into the VMX
756 * transient structure.
757 *
758 * @returns VBox status code.
759 * @param pVmxTransient Pointer to the VMX transient structure.
760 */
761DECLINLINE(int) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
762{
763 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE))
764 {
765 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
766 AssertRCReturn(rc, rc);
767 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE;
768 }
769 return VINF_SUCCESS;
770}
771
772
773/**
774 * Enters VMX root mode operation on the current CPU.
775 *
776 * @returns VBox status code.
777 * @param pVM The cross context VM structure. Can be
778 * NULL, after a resume.
779 * @param HCPhysCpuPage Physical address of the VMXON region.
780 * @param pvCpuPage Pointer to the VMXON region.
781 */
782static int hmR0VmxEnterRootMode(PVM pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
783{
784 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
785 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
786 Assert(pvCpuPage);
787 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
788
789 if (pVM)
790 {
791 /* Write the VMCS revision dword to the VMXON region. */
792 *(uint32_t *)pvCpuPage = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.Msrs.u64BasicInfo);
793 }
794
795 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
796 RTCCUINTREG fEFlags = ASMIntDisableFlags();
797
798 /* Enable the VMX bit in CR4 if necessary. */
799 RTCCUINTREG uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
800
801 /* Enter VMX root mode. */
802 int rc = VMXEnable(HCPhysCpuPage);
803 if (RT_FAILURE(rc))
804 {
805 if (!(uOldCr4 & X86_CR4_VMXE))
806 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
807
808 if (pVM)
809 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
810 }
811
812 /* Restore interrupts. */
813 ASMSetFlags(fEFlags);
814 return rc;
815}
816
817
818/**
819 * Exits VMX root mode operation on the current CPU.
820 *
821 * @returns VBox status code.
822 */
823static int hmR0VmxLeaveRootMode(void)
824{
825 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
826
827 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
828 RTCCUINTREG fEFlags = ASMIntDisableFlags();
829
830 /* If we're for some reason not in VMX root mode, then don't leave it. */
831 RTCCUINTREG uHostCR4 = ASMGetCR4();
832
833 int rc;
834 if (uHostCR4 & X86_CR4_VMXE)
835 {
836 /* Exit VMX root mode and clear the VMX bit in CR4. */
837 VMXDisable();
838 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
839 rc = VINF_SUCCESS;
840 }
841 else
842 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
843
844 /* Restore interrupts. */
845 ASMSetFlags(fEFlags);
846 return rc;
847}
848
849
850/**
851 * Allocates and maps one physically contiguous page. The allocated page is
852 * zero'd out. (Used by various VT-x structures).
853 *
854 * @returns IPRT status code.
855 * @param pMemObj Pointer to the ring-0 memory object.
856 * @param ppVirt Where to store the virtual address of the
857 * allocation.
858 * @param pHCPhys Where to store the physical address of the
859 * allocation.
860 */
861DECLINLINE(int) hmR0VmxPageAllocZ(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
862{
863 AssertPtrReturn(pMemObj, VERR_INVALID_PARAMETER);
864 AssertPtrReturn(ppVirt, VERR_INVALID_PARAMETER);
865 AssertPtrReturn(pHCPhys, VERR_INVALID_PARAMETER);
866
867 int rc = RTR0MemObjAllocCont(pMemObj, PAGE_SIZE, false /* fExecutable */);
868 if (RT_FAILURE(rc))
869 return rc;
870 *ppVirt = RTR0MemObjAddress(*pMemObj);
871 *pHCPhys = RTR0MemObjGetPagePhysAddr(*pMemObj, 0 /* iPage */);
872 ASMMemZero32(*ppVirt, PAGE_SIZE);
873 return VINF_SUCCESS;
874}
875
876
877/**
878 * Frees and unmaps an allocated physical page.
879 *
880 * @param pMemObj Pointer to the ring-0 memory object.
881 * @param ppVirt Where to re-initialize the virtual address of
882 * allocation as 0.
883 * @param pHCPhys Where to re-initialize the physical address of the
884 * allocation as 0.
885 */
886DECLINLINE(void) hmR0VmxPageFree(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
887{
888 AssertPtr(pMemObj);
889 AssertPtr(ppVirt);
890 AssertPtr(pHCPhys);
891 if (*pMemObj != NIL_RTR0MEMOBJ)
892 {
893 int rc = RTR0MemObjFree(*pMemObj, true /* fFreeMappings */);
894 AssertRC(rc);
895 *pMemObj = NIL_RTR0MEMOBJ;
896 *ppVirt = 0;
897 *pHCPhys = 0;
898 }
899}
900
901
902/**
903 * Worker function to free VT-x related structures.
904 *
905 * @returns IPRT status code.
906 * @param pVM The cross context VM structure.
907 */
908static void hmR0VmxStructsFree(PVM pVM)
909{
910 for (VMCPUID i = 0; i < pVM->cCpus; i++)
911 {
912 PVMCPU pVCpu = &pVM->aCpus[i];
913 AssertPtr(pVCpu);
914
915 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjHostMsr, &pVCpu->hm.s.vmx.pvHostMsr, &pVCpu->hm.s.vmx.HCPhysHostMsr);
916 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjGuestMsr, &pVCpu->hm.s.vmx.pvGuestMsr, &pVCpu->hm.s.vmx.HCPhysGuestMsr);
917
918 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
919 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjMsrBitmap, &pVCpu->hm.s.vmx.pvMsrBitmap, &pVCpu->hm.s.vmx.HCPhysMsrBitmap);
920
921 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjVirtApic, (PRTR0PTR)&pVCpu->hm.s.vmx.pbVirtApic, &pVCpu->hm.s.vmx.HCPhysVirtApic);
922 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjVmcs, &pVCpu->hm.s.vmx.pvVmcs, &pVCpu->hm.s.vmx.HCPhysVmcs);
923 }
924
925 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess, &pVM->hm.s.vmx.HCPhysApicAccess);
926#ifdef VBOX_WITH_CRASHDUMP_MAGIC
927 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
928#endif
929}
930
931
932/**
933 * Worker function to allocate VT-x related VM structures.
934 *
935 * @returns IPRT status code.
936 * @param pVM The cross context VM structure.
937 */
938static int hmR0VmxStructsAlloc(PVM pVM)
939{
940 /*
941 * Initialize members up-front so we can cleanup properly on allocation failure.
942 */
943#define VMXLOCAL_INIT_VM_MEMOBJ(a_Name, a_VirtPrefix) \
944 pVM->hm.s.vmx.hMemObj##a_Name = NIL_RTR0MEMOBJ; \
945 pVM->hm.s.vmx.a_VirtPrefix##a_Name = 0; \
946 pVM->hm.s.vmx.HCPhys##a_Name = 0;
947
948#define VMXLOCAL_INIT_VMCPU_MEMOBJ(a_Name, a_VirtPrefix) \
949 pVCpu->hm.s.vmx.hMemObj##a_Name = NIL_RTR0MEMOBJ; \
950 pVCpu->hm.s.vmx.a_VirtPrefix##a_Name = 0; \
951 pVCpu->hm.s.vmx.HCPhys##a_Name = 0;
952
953#ifdef VBOX_WITH_CRASHDUMP_MAGIC
954 VMXLOCAL_INIT_VM_MEMOBJ(Scratch, pv);
955#endif
956 VMXLOCAL_INIT_VM_MEMOBJ(ApicAccess, pb);
957
958 AssertCompile(sizeof(VMCPUID) == sizeof(pVM->cCpus));
959 for (VMCPUID i = 0; i < pVM->cCpus; i++)
960 {
961 PVMCPU pVCpu = &pVM->aCpus[i];
962 VMXLOCAL_INIT_VMCPU_MEMOBJ(Vmcs, pv);
963 VMXLOCAL_INIT_VMCPU_MEMOBJ(VirtApic, pb);
964 VMXLOCAL_INIT_VMCPU_MEMOBJ(MsrBitmap, pv);
965 VMXLOCAL_INIT_VMCPU_MEMOBJ(GuestMsr, pv);
966 VMXLOCAL_INIT_VMCPU_MEMOBJ(HostMsr, pv);
967 }
968#undef VMXLOCAL_INIT_VMCPU_MEMOBJ
969#undef VMXLOCAL_INIT_VM_MEMOBJ
970
971 /* The VMCS size cannot be more than 4096 bytes. See Intel spec. Appendix A.1 "Basic VMX Information". */
972 AssertReturnStmt(MSR_IA32_VMX_BASIC_INFO_VMCS_SIZE(pVM->hm.s.vmx.Msrs.u64BasicInfo) <= PAGE_SIZE,
973 (&pVM->aCpus[0])->hm.s.u32HMError = VMX_UFC_INVALID_VMCS_SIZE,
974 VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO);
975
976 /*
977 * Allocate all the VT-x structures.
978 */
979 int rc = VINF_SUCCESS;
980#ifdef VBOX_WITH_CRASHDUMP_MAGIC
981 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
982 if (RT_FAILURE(rc))
983 goto cleanup;
984 strcpy((char *)pVM->hm.s.vmx.pbScratch, "SCRATCH Magic");
985 *(uint64_t *)(pVM->hm.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
986#endif
987
988 /* Allocate the APIC-access page for trapping APIC accesses from the guest. */
989 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC)
990 {
991 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess,
992 &pVM->hm.s.vmx.HCPhysApicAccess);
993 if (RT_FAILURE(rc))
994 goto cleanup;
995 }
996
997 /*
998 * Initialize per-VCPU VT-x structures.
999 */
1000 for (VMCPUID i = 0; i < pVM->cCpus; i++)
1001 {
1002 PVMCPU pVCpu = &pVM->aCpus[i];
1003 AssertPtr(pVCpu);
1004
1005 /* Allocate the VM control structure (VMCS). */
1006 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjVmcs, &pVCpu->hm.s.vmx.pvVmcs, &pVCpu->hm.s.vmx.HCPhysVmcs);
1007 if (RT_FAILURE(rc))
1008 goto cleanup;
1009
1010 /* Allocate the Virtual-APIC page for transparent TPR accesses. */
1011 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
1012 {
1013 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjVirtApic, (PRTR0PTR)&pVCpu->hm.s.vmx.pbVirtApic,
1014 &pVCpu->hm.s.vmx.HCPhysVirtApic);
1015 if (RT_FAILURE(rc))
1016 goto cleanup;
1017 }
1018
1019 /*
1020 * Allocate the MSR-bitmap if supported by the CPU. The MSR-bitmap is for
1021 * transparent accesses of specific MSRs.
1022 *
1023 * If the condition for enabling MSR bitmaps changes here, don't forget to
1024 * update HMAreMsrBitmapsAvailable().
1025 */
1026 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1027 {
1028 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjMsrBitmap, &pVCpu->hm.s.vmx.pvMsrBitmap,
1029 &pVCpu->hm.s.vmx.HCPhysMsrBitmap);
1030 if (RT_FAILURE(rc))
1031 goto cleanup;
1032 ASMMemFill32(pVCpu->hm.s.vmx.pvMsrBitmap, PAGE_SIZE, UINT32_C(0xffffffff));
1033 }
1034
1035 /* Allocate the VM-entry MSR-load and VM-exit MSR-store page for the guest MSRs. */
1036 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjGuestMsr, &pVCpu->hm.s.vmx.pvGuestMsr, &pVCpu->hm.s.vmx.HCPhysGuestMsr);
1037 if (RT_FAILURE(rc))
1038 goto cleanup;
1039
1040 /* Allocate the VM-exit MSR-load page for the host MSRs. */
1041 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjHostMsr, &pVCpu->hm.s.vmx.pvHostMsr, &pVCpu->hm.s.vmx.HCPhysHostMsr);
1042 if (RT_FAILURE(rc))
1043 goto cleanup;
1044 }
1045
1046 return VINF_SUCCESS;
1047
1048cleanup:
1049 hmR0VmxStructsFree(pVM);
1050 return rc;
1051}
1052
1053
1054/**
1055 * Does global VT-x initialization (called during module initialization).
1056 *
1057 * @returns VBox status code.
1058 */
1059VMMR0DECL(int) VMXR0GlobalInit(void)
1060{
1061#ifdef HMVMX_USE_FUNCTION_TABLE
1062 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_apfnVMExitHandlers));
1063# ifdef VBOX_STRICT
1064 for (unsigned i = 0; i < RT_ELEMENTS(g_apfnVMExitHandlers); i++)
1065 Assert(g_apfnVMExitHandlers[i]);
1066# endif
1067#endif
1068 return VINF_SUCCESS;
1069}
1070
1071
1072/**
1073 * Does global VT-x termination (called during module termination).
1074 */
1075VMMR0DECL(void) VMXR0GlobalTerm()
1076{
1077 /* Nothing to do currently. */
1078}
1079
1080
1081/**
1082 * Sets up and activates VT-x on the current CPU.
1083 *
1084 * @returns VBox status code.
1085 * @param pCpu Pointer to the global CPU info struct.
1086 * @param pVM The cross context VM structure. Can be
1087 * NULL after a host resume operation.
1088 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
1089 * fEnabledByHost is @c true).
1090 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
1091 * @a fEnabledByHost is @c true).
1092 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
1093 * enable VT-x on the host.
1094 * @param pvMsrs Opaque pointer to VMXMSRS struct.
1095 */
1096VMMR0DECL(int) VMXR0EnableCpu(PHMGLOBALCPUINFO pCpu, PVM pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
1097 void *pvMsrs)
1098{
1099 Assert(pCpu);
1100 Assert(pvMsrs);
1101 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1102
1103 /* Enable VT-x if it's not already enabled by the host. */
1104 if (!fEnabledByHost)
1105 {
1106 int rc = hmR0VmxEnterRootMode(pVM, HCPhysCpuPage, pvCpuPage);
1107 if (RT_FAILURE(rc))
1108 return rc;
1109 }
1110
1111 /*
1112 * Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been using EPTPs) so
1113 * we don't retain any stale guest-physical mappings which won't get invalidated when flushing by VPID.
1114 */
1115 PVMXMSRS pMsrs = (PVMXMSRS)pvMsrs;
1116 if (pMsrs->u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
1117 {
1118 hmR0VmxFlushEpt(NULL /* pVCpu */, VMXFLUSHEPT_ALL_CONTEXTS);
1119 pCpu->fFlushAsidBeforeUse = false;
1120 }
1121 else
1122 pCpu->fFlushAsidBeforeUse = true;
1123
1124 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
1125 ++pCpu->cTlbFlushes;
1126
1127 return VINF_SUCCESS;
1128}
1129
1130
1131/**
1132 * Deactivates VT-x on the current CPU.
1133 *
1134 * @returns VBox status code.
1135 * @param pCpu Pointer to the global CPU info struct.
1136 * @param pvCpuPage Pointer to the VMXON region.
1137 * @param HCPhysCpuPage Physical address of the VMXON region.
1138 *
1139 * @remarks This function should never be called when SUPR0EnableVTx() or
1140 * similar was used to enable VT-x on the host.
1141 */
1142VMMR0DECL(int) VMXR0DisableCpu(PHMGLOBALCPUINFO pCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
1143{
1144 NOREF(pCpu);
1145 NOREF(pvCpuPage);
1146 NOREF(HCPhysCpuPage);
1147
1148 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1149 return hmR0VmxLeaveRootMode();
1150}
1151
1152
1153/**
1154 * Sets the permission bits for the specified MSR in the MSR bitmap.
1155 *
1156 * @param pVCpu The cross context virtual CPU structure.
1157 * @param uMsr The MSR value.
1158 * @param enmRead Whether reading this MSR causes a VM-exit.
1159 * @param enmWrite Whether writing this MSR causes a VM-exit.
1160 */
1161static void hmR0VmxSetMsrPermission(PVMCPU pVCpu, uint32_t uMsr, VMXMSREXITREAD enmRead, VMXMSREXITWRITE enmWrite)
1162{
1163 int32_t iBit;
1164 uint8_t *pbMsrBitmap = (uint8_t *)pVCpu->hm.s.vmx.pvMsrBitmap;
1165
1166 /*
1167 * Layout:
1168 * 0x000 - 0x3ff - Low MSR read bits
1169 * 0x400 - 0x7ff - High MSR read bits
1170 * 0x800 - 0xbff - Low MSR write bits
1171 * 0xc00 - 0xfff - High MSR write bits
1172 */
1173 if (uMsr <= 0x00001FFF)
1174 iBit = uMsr;
1175 else if (uMsr - UINT32_C(0xC0000000) <= UINT32_C(0x00001FFF))
1176 {
1177 iBit = uMsr - UINT32_C(0xC0000000);
1178 pbMsrBitmap += 0x400;
1179 }
1180 else
1181 AssertMsgFailedReturnVoid(("hmR0VmxSetMsrPermission: Invalid MSR %#RX32\n", uMsr));
1182
1183 Assert(iBit <= 0x1fff);
1184 if (enmRead == VMXMSREXIT_INTERCEPT_READ)
1185 ASMBitSet(pbMsrBitmap, iBit);
1186 else
1187 ASMBitClear(pbMsrBitmap, iBit);
1188
1189 if (enmWrite == VMXMSREXIT_INTERCEPT_WRITE)
1190 ASMBitSet(pbMsrBitmap + 0x800, iBit);
1191 else
1192 ASMBitClear(pbMsrBitmap + 0x800, iBit);
1193}
1194
1195
1196#ifdef VBOX_STRICT
1197/**
1198 * Gets the permission bits for the specified MSR in the MSR bitmap.
1199 *
1200 * @returns VBox status code.
1201 * @retval VINF_SUCCESS if the specified MSR is found.
1202 * @retval VERR_NOT_FOUND if the specified MSR is not found.
1203 * @retval VERR_NOT_SUPPORTED if VT-x doesn't allow the MSR.
1204 *
1205 * @param pVCpu The cross context virtual CPU structure.
1206 * @param uMsr The MSR.
1207 * @param penmRead Where to store the read permissions.
1208 * @param penmWrite Where to store the write permissions.
1209 */
1210static int hmR0VmxGetMsrPermission(PVMCPU pVCpu, uint32_t uMsr, PVMXMSREXITREAD penmRead, PVMXMSREXITWRITE penmWrite)
1211{
1212 AssertPtrReturn(penmRead, VERR_INVALID_PARAMETER);
1213 AssertPtrReturn(penmWrite, VERR_INVALID_PARAMETER);
1214 int32_t iBit;
1215 uint8_t *pbMsrBitmap = (uint8_t *)pVCpu->hm.s.vmx.pvMsrBitmap;
1216
1217 /* See hmR0VmxSetMsrPermission() for the layout. */
1218 if (uMsr <= 0x00001FFF)
1219 iBit = uMsr;
1220 else if ( uMsr >= 0xC0000000
1221 && uMsr <= 0xC0001FFF)
1222 {
1223 iBit = (uMsr - 0xC0000000);
1224 pbMsrBitmap += 0x400;
1225 }
1226 else
1227 AssertMsgFailedReturn(("hmR0VmxGetMsrPermission: Invalid MSR %#RX32\n", uMsr), VERR_NOT_SUPPORTED);
1228
1229 Assert(iBit <= 0x1fff);
1230 if (ASMBitTest(pbMsrBitmap, iBit))
1231 *penmRead = VMXMSREXIT_INTERCEPT_READ;
1232 else
1233 *penmRead = VMXMSREXIT_PASSTHRU_READ;
1234
1235 if (ASMBitTest(pbMsrBitmap + 0x800, iBit))
1236 *penmWrite = VMXMSREXIT_INTERCEPT_WRITE;
1237 else
1238 *penmWrite = VMXMSREXIT_PASSTHRU_WRITE;
1239 return VINF_SUCCESS;
1240}
1241#endif /* VBOX_STRICT */
1242
1243
1244/**
1245 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
1246 * area.
1247 *
1248 * @returns VBox status code.
1249 * @param pVCpu The cross context virtual CPU structure.
1250 * @param cMsrs The number of MSRs.
1251 */
1252DECLINLINE(int) hmR0VmxSetAutoLoadStoreMsrCount(PVMCPU pVCpu, uint32_t cMsrs)
1253{
1254 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
1255 uint32_t const cMaxSupportedMsrs = MSR_IA32_VMX_MISC_MAX_MSR(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc);
1256 if (RT_UNLIKELY(cMsrs > cMaxSupportedMsrs))
1257 {
1258 LogRel(("CPU auto-load/store MSR count in VMCS exceeded cMsrs=%u Supported=%u.\n", cMsrs, cMaxSupportedMsrs));
1259 pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
1260 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1261 }
1262
1263 /* Update number of guest MSRs to load/store across the world-switch. */
1264 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs);
1265 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs);
1266
1267 /* Update number of host MSRs to load after the world-switch. Identical to guest-MSR count as it's always paired. */
1268 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cMsrs);
1269 AssertRCReturn(rc, rc);
1270
1271 /* Update the VCPU's copy of the MSR count. */
1272 pVCpu->hm.s.vmx.cMsrs = cMsrs;
1273
1274 return VINF_SUCCESS;
1275}
1276
1277
1278/**
1279 * Adds a new (or updates the value of an existing) guest/host MSR
1280 * pair to be swapped during the world-switch as part of the
1281 * auto-load/store MSR area in the VMCS.
1282 *
1283 * @returns VBox status code.
1284 * @param pVCpu The cross context virtual CPU structure.
1285 * @param uMsr The MSR.
1286 * @param uGuestMsrValue Value of the guest MSR.
1287 * @param fUpdateHostMsr Whether to update the value of the host MSR if
1288 * necessary.
1289 * @param pfAddedAndUpdated Where to store whether the MSR was added -and-
1290 * its value was updated. Optional, can be NULL.
1291 */
1292static int hmR0VmxAddAutoLoadStoreMsr(PVMCPU pVCpu, uint32_t uMsr, uint64_t uGuestMsrValue, bool fUpdateHostMsr,
1293 bool *pfAddedAndUpdated)
1294{
1295 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1296 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
1297 uint32_t i;
1298 for (i = 0; i < cMsrs; i++)
1299 {
1300 if (pGuestMsr->u32Msr == uMsr)
1301 break;
1302 pGuestMsr++;
1303 }
1304
1305 bool fAdded = false;
1306 if (i == cMsrs)
1307 {
1308 ++cMsrs;
1309 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, cMsrs);
1310 AssertMsgRCReturn(rc, ("hmR0VmxAddAutoLoadStoreMsr: Insufficient space to add MSR %u\n", uMsr), rc);
1311
1312 /* Now that we're swapping MSRs during the world-switch, allow the guest to read/write them without causing VM-exits. */
1313 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1314 hmR0VmxSetMsrPermission(pVCpu, uMsr, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1315
1316 fAdded = true;
1317 }
1318
1319 /* Update the MSR values in the auto-load/store MSR area. */
1320 pGuestMsr->u32Msr = uMsr;
1321 pGuestMsr->u64Value = uGuestMsrValue;
1322
1323 /* Create/update the MSR slot in the host MSR area. */
1324 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1325 pHostMsr += i;
1326 pHostMsr->u32Msr = uMsr;
1327
1328 /*
1329 * Update the host MSR only when requested by the caller AND when we're
1330 * adding it to the auto-load/store area. Otherwise, it would have been
1331 * updated by hmR0VmxSaveHostMsrs(). We do this for performance reasons.
1332 */
1333 bool fUpdatedMsrValue = false;
1334 if ( fAdded
1335 && fUpdateHostMsr)
1336 {
1337 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1338 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1339 pHostMsr->u64Value = ASMRdMsr(pHostMsr->u32Msr);
1340 fUpdatedMsrValue = true;
1341 }
1342
1343 if (pfAddedAndUpdated)
1344 *pfAddedAndUpdated = fUpdatedMsrValue;
1345 return VINF_SUCCESS;
1346}
1347
1348
1349/**
1350 * Removes a guest/host MSR pair to be swapped during the world-switch from the
1351 * auto-load/store MSR area in the VMCS.
1352 *
1353 * @returns VBox status code.
1354 * @param pVCpu The cross context virtual CPU structure.
1355 * @param uMsr The MSR.
1356 */
1357static int hmR0VmxRemoveAutoLoadStoreMsr(PVMCPU pVCpu, uint32_t uMsr)
1358{
1359 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1360 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
1361 for (uint32_t i = 0; i < cMsrs; i++)
1362 {
1363 /* Find the MSR. */
1364 if (pGuestMsr->u32Msr == uMsr)
1365 {
1366 /* If it's the last MSR, simply reduce the count. */
1367 if (i == cMsrs - 1)
1368 {
1369 --cMsrs;
1370 break;
1371 }
1372
1373 /* Remove it by swapping the last MSR in place of it, and reducing the count. */
1374 PVMXAUTOMSR pLastGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1375 pLastGuestMsr += cMsrs - 1;
1376 pGuestMsr->u32Msr = pLastGuestMsr->u32Msr;
1377 pGuestMsr->u64Value = pLastGuestMsr->u64Value;
1378
1379 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1380 PVMXAUTOMSR pLastHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1381 pLastHostMsr += cMsrs - 1;
1382 pHostMsr->u32Msr = pLastHostMsr->u32Msr;
1383 pHostMsr->u64Value = pLastHostMsr->u64Value;
1384 --cMsrs;
1385 break;
1386 }
1387 pGuestMsr++;
1388 }
1389
1390 /* Update the VMCS if the count changed (meaning the MSR was found). */
1391 if (cMsrs != pVCpu->hm.s.vmx.cMsrs)
1392 {
1393 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, cMsrs);
1394 AssertRCReturn(rc, rc);
1395
1396 /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
1397 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1398 hmR0VmxSetMsrPermission(pVCpu, uMsr, VMXMSREXIT_INTERCEPT_READ, VMXMSREXIT_INTERCEPT_WRITE);
1399
1400 Log4(("Removed MSR %#RX32 new cMsrs=%u\n", uMsr, pVCpu->hm.s.vmx.cMsrs));
1401 return VINF_SUCCESS;
1402 }
1403
1404 return VERR_NOT_FOUND;
1405}
1406
1407
1408/**
1409 * Checks if the specified guest MSR is part of the auto-load/store area in
1410 * the VMCS.
1411 *
1412 * @returns true if found, false otherwise.
1413 * @param pVCpu The cross context virtual CPU structure.
1414 * @param uMsr The MSR to find.
1415 */
1416static bool hmR0VmxIsAutoLoadStoreGuestMsr(PVMCPU pVCpu, uint32_t uMsr)
1417{
1418 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1419 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
1420
1421 for (uint32_t i = 0; i < cMsrs; i++, pGuestMsr++)
1422 {
1423 if (pGuestMsr->u32Msr == uMsr)
1424 return true;
1425 }
1426 return false;
1427}
1428
1429
1430/**
1431 * Updates the value of all host MSRs in the auto-load/store area in the VMCS.
1432 *
1433 * @param pVCpu The cross context virtual CPU structure.
1434 *
1435 * @remarks No-long-jump zone!!!
1436 */
1437static void hmR0VmxUpdateAutoLoadStoreHostMsrs(PVMCPU pVCpu)
1438{
1439 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1440 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1441 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1442 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
1443
1444 for (uint32_t i = 0; i < cMsrs; i++, pHostMsr++, pGuestMsr++)
1445 {
1446 AssertReturnVoid(pHostMsr->u32Msr == pGuestMsr->u32Msr);
1447
1448 /*
1449 * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
1450 * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
1451 */
1452 if (pHostMsr->u32Msr == MSR_K6_EFER)
1453 pHostMsr->u64Value = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostEfer;
1454 else
1455 pHostMsr->u64Value = ASMRdMsr(pHostMsr->u32Msr);
1456 }
1457
1458 pVCpu->hm.s.vmx.fUpdatedHostMsrs = true;
1459}
1460
1461
1462/**
1463 * Saves a set of host MSRs to allow read/write passthru access to the guest and
1464 * perform lazy restoration of the host MSRs while leaving VT-x.
1465 *
1466 * @param pVCpu The cross context virtual CPU structure.
1467 *
1468 * @remarks No-long-jump zone!!!
1469 */
1470static void hmR0VmxLazySaveHostMsrs(PVMCPU pVCpu)
1471{
1472 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1473
1474 /*
1475 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap permissions in hmR0VmxSetupProcCtls().
1476 */
1477 if (!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST))
1478 {
1479 Assert(!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)); /* Guest MSRs better not be loaded now. */
1480#if HC_ARCH_BITS == 64
1481 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
1482 {
1483 pVCpu->hm.s.vmx.u64HostLStarMsr = ASMRdMsr(MSR_K8_LSTAR);
1484 pVCpu->hm.s.vmx.u64HostStarMsr = ASMRdMsr(MSR_K6_STAR);
1485 pVCpu->hm.s.vmx.u64HostSFMaskMsr = ASMRdMsr(MSR_K8_SF_MASK);
1486 pVCpu->hm.s.vmx.u64HostKernelGSBaseMsr = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
1487 }
1488#endif
1489 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
1490 }
1491}
1492
1493
1494/**
1495 * Checks whether the MSR belongs to the set of guest MSRs that we restore
1496 * lazily while leaving VT-x.
1497 *
1498 * @returns true if it does, false otherwise.
1499 * @param pVCpu The cross context virtual CPU structure.
1500 * @param uMsr The MSR to check.
1501 */
1502static bool hmR0VmxIsLazyGuestMsr(PVMCPU pVCpu, uint32_t uMsr)
1503{
1504 NOREF(pVCpu);
1505#if HC_ARCH_BITS == 64
1506 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
1507 {
1508 switch (uMsr)
1509 {
1510 case MSR_K8_LSTAR:
1511 case MSR_K6_STAR:
1512 case MSR_K8_SF_MASK:
1513 case MSR_K8_KERNEL_GS_BASE:
1514 return true;
1515 }
1516 }
1517#else
1518 RT_NOREF(pVCpu, uMsr);
1519#endif
1520 return false;
1521}
1522
1523
1524/**
1525 * Saves a set of guest MSRs back into the guest-CPU context.
1526 *
1527 * @param pVCpu The cross context virtual CPU structure.
1528 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
1529 * out-of-sync. Make sure to update the required fields
1530 * before using them.
1531 *
1532 * @remarks No-long-jump zone!!!
1533 */
1534static void hmR0VmxLazySaveGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
1535{
1536 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1537 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1538
1539 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
1540 {
1541 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
1542#if HC_ARCH_BITS == 64
1543 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
1544 {
1545 pMixedCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
1546 pMixedCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
1547 pMixedCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
1548 pMixedCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
1549 }
1550#else
1551 NOREF(pMixedCtx);
1552#endif
1553 }
1554}
1555
1556
1557/**
1558 * Loads a set of guests MSRs to allow read/passthru to the guest.
1559 *
1560 * The name of this function is slightly confusing. This function does NOT
1561 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
1562 * common prefix for functions dealing with "lazy restoration" of the shared
1563 * MSRs.
1564 *
1565 * @param pVCpu The cross context virtual CPU structure.
1566 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
1567 * out-of-sync. Make sure to update the required fields
1568 * before using them.
1569 *
1570 * @remarks No-long-jump zone!!!
1571 */
1572static void hmR0VmxLazyLoadGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
1573{
1574 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1575 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1576
1577#define VMXLOCAL_LAZY_LOAD_GUEST_MSR(uMsr, a_GuestMsr, a_HostMsr) \
1578 do { \
1579 if (pMixedCtx->msr##a_GuestMsr != pVCpu->hm.s.vmx.u64Host##a_HostMsr##Msr) \
1580 ASMWrMsr(uMsr, pMixedCtx->msr##a_GuestMsr); \
1581 else \
1582 Assert(ASMRdMsr(uMsr) == pVCpu->hm.s.vmx.u64Host##a_HostMsr##Msr); \
1583 } while (0)
1584
1585 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
1586 if (!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
1587 {
1588#if HC_ARCH_BITS == 64
1589 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
1590 {
1591 VMXLOCAL_LAZY_LOAD_GUEST_MSR(MSR_K8_LSTAR, LSTAR, LStar);
1592 VMXLOCAL_LAZY_LOAD_GUEST_MSR(MSR_K6_STAR, STAR, Star);
1593 VMXLOCAL_LAZY_LOAD_GUEST_MSR(MSR_K8_SF_MASK, SFMASK, SFMask);
1594 VMXLOCAL_LAZY_LOAD_GUEST_MSR(MSR_K8_KERNEL_GS_BASE, KERNELGSBASE, KernelGSBase);
1595 }
1596#else
1597 RT_NOREF(pMixedCtx);
1598#endif
1599 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
1600 }
1601
1602#undef VMXLOCAL_LAZY_LOAD_GUEST_MSR
1603}
1604
1605
1606/**
1607 * Performs lazy restoration of the set of host MSRs if they were previously
1608 * loaded with guest MSR values.
1609 *
1610 * @param pVCpu The cross context virtual CPU structure.
1611 *
1612 * @remarks No-long-jump zone!!!
1613 * @remarks The guest MSRs should have been saved back into the guest-CPU
1614 * context by hmR0VmxSaveGuestLazyMsrs()!!!
1615 */
1616static void hmR0VmxLazyRestoreHostMsrs(PVMCPU pVCpu)
1617{
1618 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1619 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1620
1621 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
1622 {
1623 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
1624#if HC_ARCH_BITS == 64
1625 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
1626 {
1627 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hm.s.vmx.u64HostLStarMsr);
1628 ASMWrMsr(MSR_K6_STAR, pVCpu->hm.s.vmx.u64HostStarMsr);
1629 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hm.s.vmx.u64HostSFMaskMsr);
1630 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hm.s.vmx.u64HostKernelGSBaseMsr);
1631 }
1632#endif
1633 }
1634 pVCpu->hm.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
1635}
1636
1637
1638/**
1639 * Verifies that our cached values of the VMCS controls are all
1640 * consistent with what's actually present in the VMCS.
1641 *
1642 * @returns VBox status code.
1643 * @param pVCpu The cross context virtual CPU structure.
1644 */
1645static int hmR0VmxCheckVmcsCtls(PVMCPU pVCpu)
1646{
1647 uint32_t u32Val;
1648 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
1649 AssertRCReturn(rc, rc);
1650 AssertMsgReturn(pVCpu->hm.s.vmx.u32EntryCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32EntryCtls, u32Val),
1651 VERR_VMX_ENTRY_CTLS_CACHE_INVALID);
1652
1653 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
1654 AssertRCReturn(rc, rc);
1655 AssertMsgReturn(pVCpu->hm.s.vmx.u32ExitCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32ExitCtls, u32Val),
1656 VERR_VMX_EXIT_CTLS_CACHE_INVALID);
1657
1658 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
1659 AssertRCReturn(rc, rc);
1660 AssertMsgReturn(pVCpu->hm.s.vmx.u32PinCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32PinCtls, u32Val),
1661 VERR_VMX_PIN_EXEC_CTLS_CACHE_INVALID);
1662
1663 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
1664 AssertRCReturn(rc, rc);
1665 AssertMsgReturn(pVCpu->hm.s.vmx.u32ProcCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32ProcCtls, u32Val),
1666 VERR_VMX_PROC_EXEC_CTLS_CACHE_INVALID);
1667
1668 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
1669 {
1670 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
1671 AssertRCReturn(rc, rc);
1672 AssertMsgReturn(pVCpu->hm.s.vmx.u32ProcCtls2 == u32Val,
1673 ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32ProcCtls2, u32Val),
1674 VERR_VMX_PROC_EXEC2_CTLS_CACHE_INVALID);
1675 }
1676
1677 return VINF_SUCCESS;
1678}
1679
1680
1681#ifdef VBOX_STRICT
1682/**
1683 * Verifies that our cached host EFER value has not changed
1684 * since we cached it.
1685 *
1686 * @param pVCpu The cross context virtual CPU structure.
1687 */
1688static void hmR0VmxCheckHostEferMsr(PVMCPU pVCpu)
1689{
1690 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1691
1692 if (pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR)
1693 {
1694 uint64_t u64Val;
1695 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &u64Val);
1696 AssertRC(rc);
1697
1698 uint64_t u64HostEferMsr = ASMRdMsr(MSR_K6_EFER);
1699 AssertMsgReturnVoid(u64HostEferMsr == u64Val, ("u64HostEferMsr=%#RX64 u64Val=%#RX64\n", u64HostEferMsr, u64Val));
1700 }
1701}
1702
1703
1704/**
1705 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
1706 * VMCS are correct.
1707 *
1708 * @param pVCpu The cross context virtual CPU structure.
1709 */
1710static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPU pVCpu)
1711{
1712 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1713
1714 /* Verify MSR counts in the VMCS are what we think it should be. */
1715 uint32_t cMsrs;
1716 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cMsrs); AssertRC(rc);
1717 Assert(cMsrs == pVCpu->hm.s.vmx.cMsrs);
1718
1719 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cMsrs); AssertRC(rc);
1720 Assert(cMsrs == pVCpu->hm.s.vmx.cMsrs);
1721
1722 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cMsrs); AssertRC(rc);
1723 Assert(cMsrs == pVCpu->hm.s.vmx.cMsrs);
1724
1725 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1726 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1727 for (uint32_t i = 0; i < cMsrs; i++, pHostMsr++, pGuestMsr++)
1728 {
1729 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
1730 AssertMsgReturnVoid(pHostMsr->u32Msr == pGuestMsr->u32Msr, ("HostMsr=%#RX32 GuestMsr=%#RX32 cMsrs=%u\n", pHostMsr->u32Msr,
1731 pGuestMsr->u32Msr, cMsrs));
1732
1733 uint64_t u64Msr = ASMRdMsr(pHostMsr->u32Msr);
1734 AssertMsgReturnVoid(pHostMsr->u64Value == u64Msr, ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
1735 pHostMsr->u32Msr, pHostMsr->u64Value, u64Msr, cMsrs));
1736
1737 /* Verify that the permissions are as expected in the MSR bitmap. */
1738 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1739 {
1740 VMXMSREXITREAD enmRead;
1741 VMXMSREXITWRITE enmWrite;
1742 rc = hmR0VmxGetMsrPermission(pVCpu, pGuestMsr->u32Msr, &enmRead, &enmWrite);
1743 AssertMsgReturnVoid(rc == VINF_SUCCESS, ("hmR0VmxGetMsrPermission! failed. rc=%Rrc\n", rc));
1744 if (pGuestMsr->u32Msr == MSR_K6_EFER)
1745 {
1746 AssertMsgReturnVoid(enmRead == VMXMSREXIT_INTERCEPT_READ, ("Passthru read for EFER!?\n"));
1747 AssertMsgReturnVoid(enmWrite == VMXMSREXIT_INTERCEPT_WRITE, ("Passthru write for EFER!?\n"));
1748 }
1749 else
1750 {
1751 AssertMsgReturnVoid(enmRead == VMXMSREXIT_PASSTHRU_READ, ("u32Msr=%#RX32 cMsrs=%u No passthru read!\n",
1752 pGuestMsr->u32Msr, cMsrs));
1753 AssertMsgReturnVoid(enmWrite == VMXMSREXIT_PASSTHRU_WRITE, ("u32Msr=%#RX32 cMsrs=%u No passthru write!\n",
1754 pGuestMsr->u32Msr, cMsrs));
1755 }
1756 }
1757 }
1758}
1759#endif /* VBOX_STRICT */
1760
1761
1762/**
1763 * Flushes the TLB using EPT.
1764 *
1765 * @returns VBox status code.
1766 * @param pVCpu The cross context virtual CPU structure of the calling
1767 * EMT. Can be NULL depending on @a enmFlush.
1768 * @param enmFlush Type of flush.
1769 *
1770 * @remarks Caller is responsible for making sure this function is called only
1771 * when NestedPaging is supported and providing @a enmFlush that is
1772 * supported by the CPU.
1773 * @remarks Can be called with interrupts disabled.
1774 */
1775static void hmR0VmxFlushEpt(PVMCPU pVCpu, VMXFLUSHEPT enmFlush)
1776{
1777 uint64_t au64Descriptor[2];
1778 if (enmFlush == VMXFLUSHEPT_ALL_CONTEXTS)
1779 au64Descriptor[0] = 0;
1780 else
1781 {
1782 Assert(pVCpu);
1783 au64Descriptor[0] = pVCpu->hm.s.vmx.HCPhysEPTP;
1784 }
1785 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
1786
1787 int rc = VMXR0InvEPT(enmFlush, &au64Descriptor[0]);
1788 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %RGv failed with %Rrc\n", enmFlush, pVCpu ? pVCpu->hm.s.vmx.HCPhysEPTP : 0,
1789 rc));
1790 if ( RT_SUCCESS(rc)
1791 && pVCpu)
1792 {
1793 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
1794 }
1795}
1796
1797
1798/**
1799 * Flushes the TLB using VPID.
1800 *
1801 * @returns VBox status code.
1802 * @param pVM The cross context VM structure.
1803 * @param pVCpu The cross context virtual CPU structure of the calling
1804 * EMT. Can be NULL depending on @a enmFlush.
1805 * @param enmFlush Type of flush.
1806 * @param GCPtr Virtual address of the page to flush (can be 0 depending
1807 * on @a enmFlush).
1808 *
1809 * @remarks Can be called with interrupts disabled.
1810 */
1811static void hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMXFLUSHVPID enmFlush, RTGCPTR GCPtr)
1812{
1813 NOREF(pVM);
1814 AssertPtr(pVM);
1815 Assert(pVM->hm.s.vmx.fVpid);
1816
1817 uint64_t au64Descriptor[2];
1818 if (enmFlush == VMXFLUSHVPID_ALL_CONTEXTS)
1819 {
1820 au64Descriptor[0] = 0;
1821 au64Descriptor[1] = 0;
1822 }
1823 else
1824 {
1825 AssertPtr(pVCpu);
1826 AssertMsg(pVCpu->hm.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
1827 AssertMsg(pVCpu->hm.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
1828 au64Descriptor[0] = pVCpu->hm.s.uCurrentAsid;
1829 au64Descriptor[1] = GCPtr;
1830 }
1831
1832 int rc = VMXR0InvVPID(enmFlush, &au64Descriptor[0]); NOREF(rc);
1833 AssertMsg(rc == VINF_SUCCESS,
1834 ("VMXR0InvVPID %#x %u %RGv failed with %d\n", enmFlush, pVCpu ? pVCpu->hm.s.uCurrentAsid : 0, GCPtr, rc));
1835 if ( RT_SUCCESS(rc)
1836 && pVCpu)
1837 {
1838 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
1839 }
1840}
1841
1842
1843/**
1844 * Invalidates a guest page by guest virtual address. Only relevant for
1845 * EPT/VPID, otherwise there is nothing really to invalidate.
1846 *
1847 * @returns VBox status code.
1848 * @param pVM The cross context VM structure.
1849 * @param pVCpu The cross context virtual CPU structure.
1850 * @param GCVirt Guest virtual address of the page to invalidate.
1851 */
1852VMMR0DECL(int) VMXR0InvalidatePage(PVM pVM, PVMCPU pVCpu, RTGCPTR GCVirt)
1853{
1854 AssertPtr(pVM);
1855 AssertPtr(pVCpu);
1856 LogFlowFunc(("pVM=%p pVCpu=%p GCVirt=%RGv\n", pVM, pVCpu, GCVirt));
1857
1858 bool fFlushPending = VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TLB_FLUSH);
1859 if (!fFlushPending)
1860 {
1861 /*
1862 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for the EPT case
1863 * See @bugref{6043} and @bugref{6177}.
1864 *
1865 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*() as this
1866 * function maybe called in a loop with individual addresses.
1867 */
1868 if (pVM->hm.s.vmx.fVpid)
1869 {
1870 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
1871 {
1872 hmR0VmxFlushVpid(pVM, pVCpu, VMXFLUSHVPID_INDIV_ADDR, GCVirt);
1873 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
1874 }
1875 else
1876 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1877 }
1878 else if (pVM->hm.s.fNestedPaging)
1879 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1880 }
1881
1882 return VINF_SUCCESS;
1883}
1884
1885
1886/**
1887 * Invalidates a guest page by physical address. Only relevant for EPT/VPID,
1888 * otherwise there is nothing really to invalidate.
1889 *
1890 * @returns VBox status code.
1891 * @param pVM The cross context VM structure.
1892 * @param pVCpu The cross context virtual CPU structure.
1893 * @param GCPhys Guest physical address of the page to invalidate.
1894 */
1895VMMR0DECL(int) VMXR0InvalidatePhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
1896{
1897 NOREF(pVM); NOREF(GCPhys);
1898 LogFlowFunc(("%RGp\n", GCPhys));
1899
1900 /*
1901 * We cannot flush a page by guest-physical address. invvpid takes only a linear address while invept only flushes
1902 * by EPT not individual addresses. We update the force flag here and flush before the next VM-entry in hmR0VmxFlushTLB*().
1903 * This function might be called in a loop. This should cause a flush-by-EPT if EPT is in use. See @bugref{6568}.
1904 */
1905 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1906 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgPhys);
1907 return VINF_SUCCESS;
1908}
1909
1910
1911/**
1912 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
1913 * case where neither EPT nor VPID is supported by the CPU.
1914 *
1915 * @param pVM The cross context VM structure.
1916 * @param pVCpu The cross context virtual CPU structure.
1917 * @param pCpu Pointer to the global HM struct.
1918 *
1919 * @remarks Called with interrupts disabled.
1920 */
1921static void hmR0VmxFlushTaggedTlbNone(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
1922{
1923 AssertPtr(pVCpu);
1924 AssertPtr(pCpu);
1925 NOREF(pVM);
1926
1927 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
1928
1929 Assert(pCpu->idCpu != NIL_RTCPUID);
1930 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
1931 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
1932 pVCpu->hm.s.fForceTLBFlush = false;
1933 return;
1934}
1935
1936
1937/**
1938 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
1939 *
1940 * @param pVM The cross context VM structure.
1941 * @param pVCpu The cross context virtual CPU structure.
1942 * @param pCpu Pointer to the global HM CPU struct.
1943 * @remarks All references to "ASID" in this function pertains to "VPID" in
1944 * Intel's nomenclature. The reason is, to avoid confusion in compare
1945 * statements since the host-CPU copies are named "ASID".
1946 *
1947 * @remarks Called with interrupts disabled.
1948 */
1949static void hmR0VmxFlushTaggedTlbBoth(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
1950{
1951#ifdef VBOX_WITH_STATISTICS
1952 bool fTlbFlushed = false;
1953# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
1954# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
1955 if (!fTlbFlushed) \
1956 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
1957 } while (0)
1958#else
1959# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
1960# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
1961#endif
1962
1963 AssertPtr(pVM);
1964 AssertPtr(pCpu);
1965 AssertPtr(pVCpu);
1966 Assert(pCpu->idCpu != NIL_RTCPUID);
1967
1968 AssertMsg(pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid,
1969 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
1970 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hm.s.fNestedPaging, pVM->hm.s.vmx.fVpid));
1971
1972 /*
1973 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
1974 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB
1975 * or the host CPU is online after a suspend/resume, so we cannot reuse the current ASID anymore.
1976 */
1977 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
1978 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
1979 {
1980 ++pCpu->uCurrentAsid;
1981 if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
1982 {
1983 pCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
1984 pCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
1985 pCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
1986 }
1987
1988 pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
1989 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
1990 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
1991
1992 /*
1993 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
1994 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
1995 */
1996 hmR0VmxFlushEpt(pVCpu, pVM->hm.s.vmx.enmFlushEpt);
1997 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
1998 HMVMX_SET_TAGGED_TLB_FLUSHED();
1999 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH); /* Already flushed-by-EPT, skip doing it again below. */
2000 }
2001
2002 /* Check for explicit TLB flushes. */
2003 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2004 {
2005 /*
2006 * Changes to the EPT paging structure by VMM requires flushing by EPT as the CPU creates
2007 * guest-physical (only EPT-tagged) mappings while traversing the EPT tables when EPT is in use.
2008 * Flushing by VPID will only flush linear (only VPID-tagged) and combined (EPT+VPID tagged) mappings
2009 * but not guest-physical mappings.
2010 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information". See @bugref{6568}.
2011 */
2012 hmR0VmxFlushEpt(pVCpu, pVM->hm.s.vmx.enmFlushEpt);
2013 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2014 HMVMX_SET_TAGGED_TLB_FLUSHED();
2015 }
2016
2017 pVCpu->hm.s.fForceTLBFlush = false;
2018 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
2019
2020 Assert(pVCpu->hm.s.idLastCpu == pCpu->idCpu);
2021 Assert(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes);
2022 AssertMsg(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes,
2023 ("Flush count mismatch for cpu %d (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
2024 AssertMsg(pCpu->uCurrentAsid >= 1 && pCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
2025 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pCpu->idCpu,
2026 pCpu->uCurrentAsid, pCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
2027 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
2028 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
2029
2030 /* Update VMCS with the VPID. */
2031 int rc = VMXWriteVmcs32(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
2032 AssertRC(rc);
2033
2034#undef HMVMX_SET_TAGGED_TLB_FLUSHED
2035}
2036
2037
2038/**
2039 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
2040 *
2041 * @returns VBox status code.
2042 * @param pVM The cross context VM structure.
2043 * @param pVCpu The cross context virtual CPU structure.
2044 * @param pCpu Pointer to the global HM CPU struct.
2045 *
2046 * @remarks Called with interrupts disabled.
2047 */
2048static void hmR0VmxFlushTaggedTlbEpt(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
2049{
2050 AssertPtr(pVM);
2051 AssertPtr(pVCpu);
2052 AssertPtr(pCpu);
2053 Assert(pCpu->idCpu != NIL_RTCPUID);
2054 AssertMsg(pVM->hm.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with NestedPaging disabled."));
2055 AssertMsg(!pVM->hm.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID enabled."));
2056
2057 /*
2058 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
2059 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
2060 */
2061 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
2062 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
2063 {
2064 pVCpu->hm.s.fForceTLBFlush = true;
2065 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2066 }
2067
2068 /* Check for explicit TLB flushes. */
2069 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2070 {
2071 pVCpu->hm.s.fForceTLBFlush = true;
2072 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2073 }
2074
2075 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
2076 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
2077
2078 if (pVCpu->hm.s.fForceTLBFlush)
2079 {
2080 hmR0VmxFlushEpt(pVCpu, pVM->hm.s.vmx.enmFlushEpt);
2081 pVCpu->hm.s.fForceTLBFlush = false;
2082 }
2083}
2084
2085
2086/**
2087 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
2088 *
2089 * @returns VBox status code.
2090 * @param pVM The cross context VM structure.
2091 * @param pVCpu The cross context virtual CPU structure.
2092 * @param pCpu Pointer to the global HM CPU struct.
2093 *
2094 * @remarks Called with interrupts disabled.
2095 */
2096static void hmR0VmxFlushTaggedTlbVpid(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
2097{
2098 AssertPtr(pVM);
2099 AssertPtr(pVCpu);
2100 AssertPtr(pCpu);
2101 Assert(pCpu->idCpu != NIL_RTCPUID);
2102 AssertMsg(pVM->hm.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked with VPID disabled."));
2103 AssertMsg(!pVM->hm.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging enabled"));
2104
2105 /*
2106 * Force a TLB flush for the first world switch if the current CPU differs from the one we ran on last.
2107 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB
2108 * or the host CPU is online after a suspend/resume, so we cannot reuse the current ASID anymore.
2109 */
2110 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
2111 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
2112 {
2113 pVCpu->hm.s.fForceTLBFlush = true;
2114 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2115 }
2116
2117 /* Check for explicit TLB flushes. */
2118 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2119 {
2120 /*
2121 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see hmR0VmxSetupTaggedTlb())
2122 * we would need to explicitly flush in this case (add an fExplicitFlush = true here and change the
2123 * pCpu->fFlushAsidBeforeUse check below to include fExplicitFlush's too) - an obscure corner case.
2124 */
2125 pVCpu->hm.s.fForceTLBFlush = true;
2126 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2127 }
2128
2129 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
2130 if (pVCpu->hm.s.fForceTLBFlush)
2131 {
2132 ++pCpu->uCurrentAsid;
2133 if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
2134 {
2135 pCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
2136 pCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
2137 pCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
2138 }
2139
2140 pVCpu->hm.s.fForceTLBFlush = false;
2141 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
2142 pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
2143 if (pCpu->fFlushAsidBeforeUse)
2144 {
2145 if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_SINGLE_CONTEXT)
2146 hmR0VmxFlushVpid(pVM, pVCpu, VMXFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
2147 else if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_ALL_CONTEXTS)
2148 {
2149 hmR0VmxFlushVpid(pVM, pVCpu, VMXFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
2150 pCpu->fFlushAsidBeforeUse = false;
2151 }
2152 else
2153 {
2154 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
2155 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
2156 }
2157 }
2158 }
2159
2160 AssertMsg(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes,
2161 ("Flush count mismatch for cpu %d (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
2162 AssertMsg(pCpu->uCurrentAsid >= 1 && pCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
2163 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pCpu->idCpu,
2164 pCpu->uCurrentAsid, pCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
2165 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
2166 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
2167
2168 int rc = VMXWriteVmcs32(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
2169 AssertRC(rc);
2170}
2171
2172
2173/**
2174 * Flushes the guest TLB entry based on CPU capabilities.
2175 *
2176 * @param pVCpu The cross context virtual CPU structure.
2177 * @param pCpu Pointer to the global HM CPU struct.
2178 */
2179DECLINLINE(void) hmR0VmxFlushTaggedTlb(PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
2180{
2181#ifdef HMVMX_ALWAYS_FLUSH_TLB
2182 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2183#endif
2184 PVM pVM = pVCpu->CTX_SUFF(pVM);
2185 switch (pVM->hm.s.vmx.uFlushTaggedTlb)
2186 {
2187 case HMVMX_FLUSH_TAGGED_TLB_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pVM, pVCpu, pCpu); break;
2188 case HMVMX_FLUSH_TAGGED_TLB_EPT: hmR0VmxFlushTaggedTlbEpt(pVM, pVCpu, pCpu); break;
2189 case HMVMX_FLUSH_TAGGED_TLB_VPID: hmR0VmxFlushTaggedTlbVpid(pVM, pVCpu, pCpu); break;
2190 case HMVMX_FLUSH_TAGGED_TLB_NONE: hmR0VmxFlushTaggedTlbNone(pVM, pVCpu, pCpu); break;
2191 default:
2192 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
2193 break;
2194 }
2195
2196 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
2197}
2198
2199
2200/**
2201 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
2202 * TLB entries from the host TLB before VM-entry.
2203 *
2204 * @returns VBox status code.
2205 * @param pVM The cross context VM structure.
2206 */
2207static int hmR0VmxSetupTaggedTlb(PVM pVM)
2208{
2209 /*
2210 * Determine optimal flush type for Nested Paging.
2211 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup unrestricted
2212 * guest execution (see hmR3InitFinalizeR0()).
2213 */
2214 if (pVM->hm.s.fNestedPaging)
2215 {
2216 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
2217 {
2218 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
2219 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_SINGLE_CONTEXT;
2220 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
2221 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_ALL_CONTEXTS;
2222 else
2223 {
2224 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
2225 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2226 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
2227 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2228 }
2229
2230 /* Make sure the write-back cacheable memory type for EPT is supported. */
2231 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB)))
2232 {
2233 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2234 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
2235 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2236 }
2237
2238 /* EPT requires a page-walk length of 4. */
2239 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
2240 {
2241 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2242 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
2243 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2244 }
2245 }
2246 else
2247 {
2248 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
2249 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2250 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
2251 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2252 }
2253 }
2254
2255 /*
2256 * Determine optimal flush type for VPID.
2257 */
2258 if (pVM->hm.s.vmx.fVpid)
2259 {
2260 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
2261 {
2262 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
2263 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_SINGLE_CONTEXT;
2264 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
2265 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_ALL_CONTEXTS;
2266 else
2267 {
2268 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
2269 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
2270 LogRel(("hmR0VmxSetupTaggedTlb: Only INDIV_ADDR supported. Ignoring VPID.\n"));
2271 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
2272 LogRel(("hmR0VmxSetupTaggedTlb: Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
2273 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_NOT_SUPPORTED;
2274 pVM->hm.s.vmx.fVpid = false;
2275 }
2276 }
2277 else
2278 {
2279 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
2280 Log4(("hmR0VmxSetupTaggedTlb: VPID supported without INVEPT support. Ignoring VPID.\n"));
2281 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_NOT_SUPPORTED;
2282 pVM->hm.s.vmx.fVpid = false;
2283 }
2284 }
2285
2286 /*
2287 * Setup the handler for flushing tagged-TLBs.
2288 */
2289 if (pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid)
2290 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_EPT_VPID;
2291 else if (pVM->hm.s.fNestedPaging)
2292 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_EPT;
2293 else if (pVM->hm.s.vmx.fVpid)
2294 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_VPID;
2295 else
2296 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_NONE;
2297 return VINF_SUCCESS;
2298}
2299
2300
2301/**
2302 * Sets up pin-based VM-execution controls in the VMCS.
2303 *
2304 * @returns VBox status code.
2305 * @param pVM The cross context VM structure.
2306 * @param pVCpu The cross context virtual CPU structure.
2307 */
2308static int hmR0VmxSetupPinCtls(PVM pVM, PVMCPU pVCpu)
2309{
2310 AssertPtr(pVM);
2311 AssertPtr(pVCpu);
2312
2313 uint32_t val = pVM->hm.s.vmx.Msrs.VmxPinCtls.n.disallowed0; /* Bits set here must always be set. */
2314 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
2315
2316 val |= VMX_VMCS_CTRL_PIN_EXEC_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
2317 | VMX_VMCS_CTRL_PIN_EXEC_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
2318
2319 if (pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
2320 val |= VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
2321
2322 /* Enable the VMX preemption timer. */
2323 if (pVM->hm.s.vmx.fUsePreemptTimer)
2324 {
2325 Assert(pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_PREEMPT_TIMER);
2326 val |= VMX_VMCS_CTRL_PIN_EXEC_PREEMPT_TIMER;
2327 }
2328
2329#if 0
2330 /* Enable posted-interrupt processing. */
2331 if (pVM->hm.s.fPostedIntrs)
2332 {
2333 Assert(pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_POSTED_INTR);
2334 Assert(pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT);
2335 val |= VMX_VMCS_CTRL_PIN_EXEC_POSTED_INTR;
2336 }
2337#endif
2338
2339 if ((val & zap) != val)
2340 {
2341 LogRel(("hmR0VmxSetupPinCtls: Invalid pin-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
2342 pVM->hm.s.vmx.Msrs.VmxPinCtls.n.disallowed0, val, zap));
2343 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
2344 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2345 }
2346
2347 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, val);
2348 AssertRCReturn(rc, rc);
2349
2350 pVCpu->hm.s.vmx.u32PinCtls = val;
2351 return rc;
2352}
2353
2354
2355/**
2356 * Sets up processor-based VM-execution controls in the VMCS.
2357 *
2358 * @returns VBox status code.
2359 * @param pVM The cross context VM structure.
2360 * @param pVCpu The cross context virtual CPU structure.
2361 */
2362static int hmR0VmxSetupProcCtls(PVM pVM, PVMCPU pVCpu)
2363{
2364 AssertPtr(pVM);
2365 AssertPtr(pVCpu);
2366
2367 int rc = VERR_INTERNAL_ERROR_5;
2368 uint32_t val = pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0; /* Bits set here must be set in the VMCS. */
2369 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2370
2371 val |= VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT /* HLT causes a VM-exit. */
2372 | VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
2373 | VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
2374 | VMX_VMCS_CTRL_PROC_EXEC_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
2375 | VMX_VMCS_CTRL_PROC_EXEC_RDPMC_EXIT /* RDPMC causes a VM-exit. */
2376 | VMX_VMCS_CTRL_PROC_EXEC_MONITOR_EXIT /* MONITOR causes a VM-exit. */
2377 | VMX_VMCS_CTRL_PROC_EXEC_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
2378
2379 /* We toggle VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
2380 if ( !(pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT)
2381 || (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0 & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT))
2382 {
2383 LogRel(("hmR0VmxSetupProcCtls: Unsupported VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT combo!"));
2384 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
2385 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2386 }
2387
2388 /* Without Nested Paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
2389 if (!pVM->hm.s.fNestedPaging)
2390 {
2391 Assert(!pVM->hm.s.vmx.fUnrestrictedGuest); /* Paranoia. */
2392 val |= VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT
2393 | VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
2394 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
2395 }
2396
2397 /* Use TPR shadowing if supported by the CPU. */
2398 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
2399 {
2400 Assert(pVCpu->hm.s.vmx.HCPhysVirtApic);
2401 Assert(!(pVCpu->hm.s.vmx.HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
2402 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, 0);
2403 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VAPIC_PAGEADDR_FULL, pVCpu->hm.s.vmx.HCPhysVirtApic);
2404 AssertRCReturn(rc, rc);
2405
2406 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
2407 /* CR8 writes cause a VM-exit based on TPR threshold. */
2408 Assert(!(val & VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT));
2409 Assert(!(val & VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT));
2410 }
2411 else
2412 {
2413 /*
2414 * Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is invalid on 32-bit Intel CPUs.
2415 * Set this control only for 64-bit guests.
2416 */
2417 if (pVM->hm.s.fAllow64BitGuests)
2418 {
2419 val |= VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
2420 | VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
2421 }
2422 }
2423
2424 /* Use MSR-bitmaps if supported by the CPU. */
2425 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
2426 {
2427 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS;
2428
2429 Assert(pVCpu->hm.s.vmx.HCPhysMsrBitmap);
2430 Assert(!(pVCpu->hm.s.vmx.HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
2431 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, pVCpu->hm.s.vmx.HCPhysMsrBitmap);
2432 AssertRCReturn(rc, rc);
2433
2434 /*
2435 * The guest can access the following MSRs (read, write) without causing VM-exits; they are loaded/stored
2436 * automatically using dedicated fields in the VMCS.
2437 */
2438 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_CS, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2439 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_ESP, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2440 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_EIP, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2441 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2442 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_FS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2443
2444#if HC_ARCH_BITS == 64
2445 /*
2446 * Set passthru permissions for the following MSRs (mandatory for VT-x) required for 64-bit guests.
2447 */
2448 if (pVM->hm.s.fAllow64BitGuests)
2449 {
2450 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_LSTAR, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2451 hmR0VmxSetMsrPermission(pVCpu, MSR_K6_STAR, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2452 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_SF_MASK, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2453 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_KERNEL_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2454 }
2455#endif
2456 /* Though MSR_IA32_PERF_GLOBAL_CTRL is saved/restored lazily, we want intercept reads/write to it for now. */
2457 }
2458
2459 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
2460 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
2461 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL;
2462
2463 if ((val & zap) != val)
2464 {
2465 LogRel(("hmR0VmxSetupProcCtls: Invalid processor-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
2466 pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0, val, zap));
2467 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
2468 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2469 }
2470
2471 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, val);
2472 AssertRCReturn(rc, rc);
2473
2474 pVCpu->hm.s.vmx.u32ProcCtls = val;
2475
2476 /*
2477 * Secondary processor-based VM-execution controls.
2478 */
2479 if (RT_LIKELY(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL))
2480 {
2481 val = pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.disallowed0; /* Bits set here must be set in the VMCS. */
2482 zap = pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2483
2484 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT)
2485 val |= VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT; /* WBINVD causes a VM-exit. */
2486
2487 if (pVM->hm.s.fNestedPaging)
2488 val |= VMX_VMCS_CTRL_PROC_EXEC2_EPT; /* Enable EPT. */
2489 else
2490 {
2491 /*
2492 * Without Nested Paging, INVPCID should cause a VM-exit. Enabling this bit causes the CPU to refer to
2493 * VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT when INVPCID is executed by the guest.
2494 * See Intel spec. 25.4 "Changes to instruction behaviour in VMX non-root operation".
2495 */
2496 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_INVPCID)
2497 val |= VMX_VMCS_CTRL_PROC_EXEC2_INVPCID;
2498 }
2499
2500 if (pVM->hm.s.vmx.fVpid)
2501 val |= VMX_VMCS_CTRL_PROC_EXEC2_VPID; /* Enable VPID. */
2502
2503 if (pVM->hm.s.vmx.fUnrestrictedGuest)
2504 val |= VMX_VMCS_CTRL_PROC_EXEC2_UNRESTRICTED_GUEST; /* Enable Unrestricted Execution. */
2505
2506#if 0
2507 if (pVM->hm.s.fVirtApicRegs)
2508 {
2509 Assert(pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_APIC_REG_VIRT);
2510 val |= VMX_VMCS_CTRL_PROC_EXEC2_APIC_REG_VIRT; /* Enable APIC-register virtualization. */
2511
2512 Assert(pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_INTR_DELIVERY);
2513 val |= VMX_VMCS_CTRL_PROC_EXEC2_VIRT_INTR_DELIVERY; /* Enable virtual-interrupt delivery. */
2514 }
2515#endif
2516
2517 /* Enable Virtual-APIC page accesses if supported by the CPU. This is essentially where the TPR shadow resides. */
2518 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
2519 * done dynamically. */
2520 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC)
2521 {
2522 Assert(pVM->hm.s.vmx.HCPhysApicAccess);
2523 Assert(!(pVM->hm.s.vmx.HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
2524 val |= VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC; /* Virtualize APIC accesses. */
2525 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, pVM->hm.s.vmx.HCPhysApicAccess);
2526 AssertRCReturn(rc, rc);
2527 }
2528
2529 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP)
2530 val |= VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP; /* Enable RDTSCP support. */
2531
2532 if ( pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_PAUSE_LOOP_EXIT
2533 && pVM->hm.s.vmx.cPleGapTicks
2534 && pVM->hm.s.vmx.cPleWindowTicks)
2535 {
2536 val |= VMX_VMCS_CTRL_PROC_EXEC2_PAUSE_LOOP_EXIT; /* Enable pause-loop exiting. */
2537
2538 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks);
2539 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks);
2540 AssertRCReturn(rc, rc);
2541 }
2542
2543 if ((val & zap) != val)
2544 {
2545 LogRel(("hmR0VmxSetupProcCtls: Invalid secondary processor-based VM-execution controls combo! "
2546 "cpu=%#RX64 val=%#RX64 zap=%#RX64\n", pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.disallowed0, val, zap));
2547 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
2548 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2549 }
2550
2551 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, val);
2552 AssertRCReturn(rc, rc);
2553
2554 pVCpu->hm.s.vmx.u32ProcCtls2 = val;
2555 }
2556 else if (RT_UNLIKELY(pVM->hm.s.vmx.fUnrestrictedGuest))
2557 {
2558 LogRel(("hmR0VmxSetupProcCtls: Unrestricted Guest set as true when secondary processor-based VM-execution controls not "
2559 "available\n"));
2560 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
2561 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2562 }
2563
2564 return VINF_SUCCESS;
2565}
2566
2567
2568/**
2569 * Sets up miscellaneous (everything other than Pin & Processor-based
2570 * VM-execution) control fields in the VMCS.
2571 *
2572 * @returns VBox status code.
2573 * @param pVM The cross context VM structure.
2574 * @param pVCpu The cross context virtual CPU structure.
2575 */
2576static int hmR0VmxSetupMiscCtls(PVM pVM, PVMCPU pVCpu)
2577{
2578 NOREF(pVM);
2579 AssertPtr(pVM);
2580 AssertPtr(pVCpu);
2581
2582 int rc = VERR_GENERAL_FAILURE;
2583
2584 /* All fields are zero-initialized during allocation; but don't remove the commented block below. */
2585#if 0
2586 /* All CR3 accesses cause VM-exits. Later we optimize CR3 accesses (see hmR0VmxLoadGuestCR3AndCR4())*/
2587 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_CR3_TARGET_COUNT, 0);
2588 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, 0);
2589
2590 /*
2591 * Set MASK & MATCH to 0. VMX checks if GuestPFErrCode & MASK == MATCH. If equal (in our case it always is)
2592 * 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.
2593 * We thus use the exception bitmap to control it rather than use both.
2594 */
2595 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, 0);
2596 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, 0);
2597
2598 /** @todo Explore possibility of using IO-bitmaps. */
2599 /* All IO & IOIO instructions cause VM-exits. */
2600 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_IO_BITMAP_A_FULL, 0);
2601 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_IO_BITMAP_B_FULL, 0);
2602
2603 /* Initialize the MSR-bitmap area. */
2604 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, 0);
2605 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, 0);
2606 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, 0);
2607 AssertRCReturn(rc, rc);
2608#endif
2609
2610 /* Setup MSR auto-load/store area. */
2611 Assert(pVCpu->hm.s.vmx.HCPhysGuestMsr);
2612 Assert(!(pVCpu->hm.s.vmx.HCPhysGuestMsr & 0xf)); /* Lower 4 bits MBZ. */
2613 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, pVCpu->hm.s.vmx.HCPhysGuestMsr);
2614 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, pVCpu->hm.s.vmx.HCPhysGuestMsr);
2615 AssertRCReturn(rc, rc);
2616
2617 Assert(pVCpu->hm.s.vmx.HCPhysHostMsr);
2618 Assert(!(pVCpu->hm.s.vmx.HCPhysHostMsr & 0xf)); /* Lower 4 bits MBZ. */
2619 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, pVCpu->hm.s.vmx.HCPhysHostMsr);
2620 AssertRCReturn(rc, rc);
2621
2622 /* Set VMCS link pointer. Reserved for future use, must be -1. Intel spec. 24.4 "Guest-State Area". */
2623 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, UINT64_C(0xffffffffffffffff));
2624 AssertRCReturn(rc, rc);
2625
2626 /* All fields are zero-initialized during allocation; but don't remove the commented block below. */
2627#if 0
2628 /* Setup debug controls */
2629 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, 0); /** @todo We don't support IA32_DEBUGCTL MSR. Should we? */
2630 rc |= VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, 0);
2631 AssertRCReturn(rc, rc);
2632#endif
2633
2634 return rc;
2635}
2636
2637
2638/**
2639 * Sets up the initial exception bitmap in the VMCS based on static conditions.
2640 *
2641 * @returns VBox status code.
2642 * @param pVM The cross context VM structure.
2643 * @param pVCpu The cross context virtual CPU structure.
2644 */
2645static int hmR0VmxInitXcptBitmap(PVM pVM, PVMCPU pVCpu)
2646{
2647 AssertPtr(pVM);
2648 AssertPtr(pVCpu);
2649
2650 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
2651
2652 uint32_t u32XcptBitmap = pVCpu->hm.s.fGIMTrapXcptUD ? RT_BIT(X86_XCPT_UD) : 0;
2653
2654 /* Must always intercept #AC to prevent the guest from hanging the CPU. */
2655 u32XcptBitmap |= RT_BIT_32(X86_XCPT_AC);
2656
2657 /* Because we need to maintain the DR6 state even when intercepting DRx reads
2658 and writes, and because recursive #DBs can cause the CPU hang, we must always
2659 intercept #DB. */
2660 u32XcptBitmap |= RT_BIT_32(X86_XCPT_DB);
2661
2662 /* Without Nested Paging, #PF must cause a VM-exit so we can sync our shadow page tables. */
2663 if (!pVM->hm.s.fNestedPaging)
2664 u32XcptBitmap |= RT_BIT(X86_XCPT_PF);
2665
2666 pVCpu->hm.s.vmx.u32XcptBitmap = u32XcptBitmap;
2667 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
2668 AssertRCReturn(rc, rc);
2669 return rc;
2670}
2671
2672
2673/**
2674 * Sets up the initial guest-state mask. The guest-state mask is consulted
2675 * before reading guest-state fields from the VMCS as VMREADs can be expensive
2676 * for the nested virtualization case (as it would cause a VM-exit).
2677 *
2678 * @param pVCpu The cross context virtual CPU structure.
2679 */
2680static int hmR0VmxInitUpdatedGuestStateMask(PVMCPU pVCpu)
2681{
2682 /* Initially the guest-state is up-to-date as there is nothing in the VMCS. */
2683 HMVMXCPU_GST_RESET_TO(pVCpu, HMVMX_UPDATED_GUEST_ALL);
2684 return VINF_SUCCESS;
2685}
2686
2687
2688/**
2689 * Does per-VM VT-x initialization.
2690 *
2691 * @returns VBox status code.
2692 * @param pVM The cross context VM structure.
2693 */
2694VMMR0DECL(int) VMXR0InitVM(PVM pVM)
2695{
2696 LogFlowFunc(("pVM=%p\n", pVM));
2697
2698 int rc = hmR0VmxStructsAlloc(pVM);
2699 if (RT_FAILURE(rc))
2700 {
2701 LogRel(("VMXR0InitVM: hmR0VmxStructsAlloc failed! rc=%Rrc\n", rc));
2702 return rc;
2703 }
2704
2705 return VINF_SUCCESS;
2706}
2707
2708
2709/**
2710 * Does per-VM VT-x termination.
2711 *
2712 * @returns VBox status code.
2713 * @param pVM The cross context VM structure.
2714 */
2715VMMR0DECL(int) VMXR0TermVM(PVM pVM)
2716{
2717 LogFlowFunc(("pVM=%p\n", pVM));
2718
2719#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2720 if (pVM->hm.s.vmx.hMemObjScratch != NIL_RTR0MEMOBJ)
2721 ASMMemZero32(pVM->hm.s.vmx.pvScratch, PAGE_SIZE);
2722#endif
2723 hmR0VmxStructsFree(pVM);
2724 return VINF_SUCCESS;
2725}
2726
2727
2728/**
2729 * Sets up the VM for execution under VT-x.
2730 * This function is only called once per-VM during initialization.
2731 *
2732 * @returns VBox status code.
2733 * @param pVM The cross context VM structure.
2734 */
2735VMMR0DECL(int) VMXR0SetupVM(PVM pVM)
2736{
2737 AssertPtrReturn(pVM, VERR_INVALID_PARAMETER);
2738 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2739
2740 LogFlowFunc(("pVM=%p\n", pVM));
2741
2742 /*
2743 * Without UnrestrictedGuest, pRealModeTSS and pNonPagingModeEPTPageTable *must* always be allocated.
2744 * We no longer support the highly unlikely case of UnrestrictedGuest without pRealModeTSS. See hmR3InitFinalizeR0Intel().
2745 */
2746 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
2747 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
2748 || !pVM->hm.s.vmx.pRealModeTSS))
2749 {
2750 LogRel(("VMXR0SetupVM: Invalid real-on-v86 state.\n"));
2751 return VERR_INTERNAL_ERROR;
2752 }
2753
2754 /* Initialize these always, see hmR3InitFinalizeR0().*/
2755 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NONE;
2756 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_NONE;
2757
2758 /* Setup the tagged-TLB flush handlers. */
2759 int rc = hmR0VmxSetupTaggedTlb(pVM);
2760 if (RT_FAILURE(rc))
2761 {
2762 LogRel(("VMXR0SetupVM: hmR0VmxSetupTaggedTlb failed! rc=%Rrc\n", rc));
2763 return rc;
2764 }
2765
2766 /* Check if we can use the VMCS controls for swapping the EFER MSR. */
2767 Assert(!pVM->hm.s.vmx.fSupportsVmcsEfer);
2768#if HC_ARCH_BITS == 64
2769 if ( (pVM->hm.s.vmx.Msrs.VmxEntry.n.allowed1 & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR)
2770 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR)
2771 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR))
2772 {
2773 pVM->hm.s.vmx.fSupportsVmcsEfer = true;
2774 }
2775#endif
2776
2777 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
2778 RTCCUINTREG uHostCR4 = ASMGetCR4();
2779 if (RT_UNLIKELY(!(uHostCR4 & X86_CR4_VMXE)))
2780 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
2781
2782 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2783 {
2784 PVMCPU pVCpu = &pVM->aCpus[i];
2785 AssertPtr(pVCpu);
2786 AssertPtr(pVCpu->hm.s.vmx.pvVmcs);
2787
2788 /* Log the VCPU pointers, useful for debugging SMP VMs. */
2789 Log4(("VMXR0SetupVM: pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
2790
2791 /* Initialize the VM-exit history array with end-of-array markers (UINT16_MAX). */
2792 Assert(!pVCpu->hm.s.idxExitHistoryFree);
2793 HMCPU_EXIT_HISTORY_RESET(pVCpu);
2794
2795 /* Set revision dword at the beginning of the VMCS structure. */
2796 *(uint32_t *)pVCpu->hm.s.vmx.pvVmcs = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.Msrs.u64BasicInfo);
2797
2798 /* Initialize our VMCS region in memory, set the VMCS launch state to "clear". */
2799 rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2800 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVmcs failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2801 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2802
2803 /* Load this VMCS as the current VMCS. */
2804 rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2805 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXActivateVmcs failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2806 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2807
2808 rc = hmR0VmxSetupPinCtls(pVM, pVCpu);
2809 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupPinCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2810 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2811
2812 rc = hmR0VmxSetupProcCtls(pVM, pVCpu);
2813 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupProcCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2814 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2815
2816 rc = hmR0VmxSetupMiscCtls(pVM, pVCpu);
2817 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupMiscCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2818 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2819
2820 rc = hmR0VmxInitXcptBitmap(pVM, pVCpu);
2821 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitXcptBitmap failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2822 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2823
2824 rc = hmR0VmxInitUpdatedGuestStateMask(pVCpu);
2825 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitUpdatedGuestStateMask failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2826 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2827
2828#if HC_ARCH_BITS == 32
2829 rc = hmR0VmxInitVmcsReadCache(pVM, pVCpu);
2830 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitVmcsReadCache failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2831 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2832#endif
2833
2834 /* Re-sync the CPU's internal data into our VMCS memory region & reset the launch state to "clear". */
2835 rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2836 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVmcs(2) failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2837 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2838
2839 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
2840
2841 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc);
2842 }
2843
2844 return VINF_SUCCESS;
2845}
2846
2847
2848/**
2849 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
2850 * the VMCS.
2851 *
2852 * @returns VBox status code.
2853 * @param pVM The cross context VM structure.
2854 * @param pVCpu The cross context virtual CPU structure.
2855 */
2856DECLINLINE(int) hmR0VmxSaveHostControlRegs(PVM pVM, PVMCPU pVCpu)
2857{
2858 NOREF(pVM); NOREF(pVCpu);
2859
2860 RTCCUINTREG uReg = ASMGetCR0();
2861 int rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR0, uReg);
2862 AssertRCReturn(rc, rc);
2863
2864 uReg = ASMGetCR3();
2865 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR3, uReg);
2866 AssertRCReturn(rc, rc);
2867
2868 uReg = ASMGetCR4();
2869 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR4, uReg);
2870 AssertRCReturn(rc, rc);
2871 return rc;
2872}
2873
2874
2875#if HC_ARCH_BITS == 64
2876/**
2877 * Macro for adjusting host segment selectors to satisfy VT-x's VM-entry
2878 * requirements. See hmR0VmxSaveHostSegmentRegs().
2879 */
2880# define VMXLOCAL_ADJUST_HOST_SEG(seg, selValue) \
2881 if ((selValue) & (X86_SEL_RPL | X86_SEL_LDT)) \
2882 { \
2883 bool fValidSelector = true; \
2884 if ((selValue) & X86_SEL_LDT) \
2885 { \
2886 uint32_t uAttr = ASMGetSegAttr((selValue)); \
2887 fValidSelector = RT_BOOL(uAttr != UINT32_MAX && (uAttr & X86_DESC_P)); \
2888 } \
2889 if (fValidSelector) \
2890 { \
2891 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##seg; \
2892 pVCpu->hm.s.vmx.RestoreHost.uHostSel##seg = (selValue); \
2893 } \
2894 (selValue) = 0; \
2895 }
2896#endif
2897
2898
2899/**
2900 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
2901 * the host-state area in the VMCS.
2902 *
2903 * @returns VBox status code.
2904 * @param pVM The cross context VM structure.
2905 * @param pVCpu The cross context virtual CPU structure.
2906 */
2907DECLINLINE(int) hmR0VmxSaveHostSegmentRegs(PVM pVM, PVMCPU pVCpu)
2908{
2909 int rc = VERR_INTERNAL_ERROR_5;
2910
2911#if HC_ARCH_BITS == 64
2912 /*
2913 * If we've executed guest code using VT-x, the host-state bits will be messed up. We
2914 * should -not- save the messed up state without restoring the original host-state. See @bugref{7240}.
2915 *
2916 * This apparently can happen (most likely the FPU changes), deal with it rather than asserting.
2917 * Was observed booting Solaris10u10 32-bit guest.
2918 */
2919 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
2920 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
2921 {
2922 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags,
2923 pVCpu->idCpu));
2924 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
2925 }
2926 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
2927#else
2928 RT_NOREF(pVCpu);
2929#endif
2930
2931 /*
2932 * Host DS, ES, FS and GS segment registers.
2933 */
2934#if HC_ARCH_BITS == 64
2935 RTSEL uSelDS = ASMGetDS();
2936 RTSEL uSelES = ASMGetES();
2937 RTSEL uSelFS = ASMGetFS();
2938 RTSEL uSelGS = ASMGetGS();
2939#else
2940 RTSEL uSelDS = 0;
2941 RTSEL uSelES = 0;
2942 RTSEL uSelFS = 0;
2943 RTSEL uSelGS = 0;
2944#endif
2945
2946 /*
2947 * Host CS and SS segment registers.
2948 */
2949 RTSEL uSelCS = ASMGetCS();
2950 RTSEL uSelSS = ASMGetSS();
2951
2952 /*
2953 * Host TR segment register.
2954 */
2955 RTSEL uSelTR = ASMGetTR();
2956
2957#if HC_ARCH_BITS == 64
2958 /*
2959 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to gain VM-entry and restore them
2960 * before we get preempted. See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
2961 */
2962 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
2963 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
2964 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
2965 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
2966# undef VMXLOCAL_ADJUST_HOST_SEG
2967#endif
2968
2969 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
2970 Assert(!(uSelCS & X86_SEL_RPL)); Assert(!(uSelCS & X86_SEL_LDT));
2971 Assert(!(uSelSS & X86_SEL_RPL)); Assert(!(uSelSS & X86_SEL_LDT));
2972 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
2973 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
2974 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
2975 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
2976 Assert(!(uSelTR & X86_SEL_RPL)); Assert(!(uSelTR & X86_SEL_LDT));
2977 Assert(uSelCS);
2978 Assert(uSelTR);
2979
2980 /* Assertion is right but we would not have updated u32ExitCtls yet. */
2981#if 0
2982 if (!(pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE))
2983 Assert(uSelSS != 0);
2984#endif
2985
2986 /* Write these host selector fields into the host-state area in the VMCS. */
2987 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_CS_SEL, uSelCS);
2988 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_SS_SEL, uSelSS);
2989#if HC_ARCH_BITS == 64
2990 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_DS_SEL, uSelDS);
2991 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_ES_SEL, uSelES);
2992 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_FS_SEL, uSelFS);
2993 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_GS_SEL, uSelGS);
2994#else
2995 NOREF(uSelDS);
2996 NOREF(uSelES);
2997 NOREF(uSelFS);
2998 NOREF(uSelGS);
2999#endif
3000 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_TR_SEL, uSelTR);
3001 AssertRCReturn(rc, rc);
3002
3003 /*
3004 * Host GDTR and IDTR.
3005 */
3006 RTGDTR Gdtr;
3007 RTIDTR Idtr;
3008 RT_ZERO(Gdtr);
3009 RT_ZERO(Idtr);
3010 ASMGetGDTR(&Gdtr);
3011 ASMGetIDTR(&Idtr);
3012 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_GDTR_BASE, Gdtr.pGdt);
3013 rc |= VMXWriteVmcsHstN(VMX_VMCS_HOST_IDTR_BASE, Idtr.pIdt);
3014 AssertRCReturn(rc, rc);
3015
3016#if HC_ARCH_BITS == 64
3017 /*
3018 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps them to the
3019 * maximum limit (0xffff) on every VM-exit.
3020 */
3021 if (Gdtr.cbGdt != 0xffff)
3022 {
3023 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
3024 AssertCompile(sizeof(Gdtr) == sizeof(X86XDTR64));
3025 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
3026 }
3027
3028 /*
3029 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT"
3030 * and Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit as 0xfff, VT-x
3031 * bloating the limit to 0xffff shouldn't cause any different CPU behavior. However, several hosts either insists
3032 * on 0xfff being the limit (Windows Patch Guard) or uses the limit for other purposes (darwin puts the CPU ID in there
3033 * but botches sidt alignment in at least one consumer). So, we're only allowing IDTR.LIMIT to be left at 0xffff on
3034 * hosts where we are pretty sure it won't cause trouble.
3035 */
3036# if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
3037 if (Idtr.cbIdt < 0x0fff)
3038# else
3039 if (Idtr.cbIdt != 0xffff)
3040# endif
3041 {
3042 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
3043 AssertCompile(sizeof(Idtr) == sizeof(X86XDTR64));
3044 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostIdtr, &Idtr, sizeof(X86XDTR64));
3045 }
3046#endif
3047
3048 /*
3049 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI and RPL bits
3050 * is effectively what the CPU does for "scaling by 8". TI is always 0 and RPL should be too in most cases.
3051 */
3052 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= Gdtr.cbGdt,
3053 ("hmR0VmxSaveHostSegmentRegs: TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, Gdtr.cbGdt),
3054 VERR_VMX_INVALID_HOST_STATE);
3055
3056 PCX86DESCHC pDesc = (PCX86DESCHC)(Gdtr.pGdt + (uSelTR & X86_SEL_MASK));
3057#if HC_ARCH_BITS == 64
3058 uintptr_t uTRBase = X86DESC64_BASE(pDesc);
3059
3060 /*
3061 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on all VM-exits.
3062 * The type is the same for 64-bit busy TSS[1]. The limit needs manual restoration if the host has something else.
3063 * Task switching is not supported in 64-bit mode[2], but the limit still matters as IOPM is supported in 64-bit mode.
3064 * Restoring the limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
3065 *
3066 * [1] See Intel spec. 3.5 "System Descriptor Types".
3067 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
3068 */
3069 Assert(pDesc->System.u4Type == 11);
3070 if ( pDesc->System.u16LimitLow != 0x67
3071 || pDesc->System.u4LimitHigh)
3072 {
3073 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
3074 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
3075 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
3076 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
3077 pVCpu->hm.s.vmx.RestoreHost.uHostSelTR = uSelTR;
3078
3079 /* Store the GDTR here as we need it while restoring TR. */
3080 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
3081 }
3082#else
3083 NOREF(pVM);
3084 uintptr_t uTRBase = X86DESC_BASE(pDesc);
3085#endif
3086 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_TR_BASE, uTRBase);
3087 AssertRCReturn(rc, rc);
3088
3089 /*
3090 * Host FS base and GS base.
3091 */
3092#if HC_ARCH_BITS == 64
3093 uint64_t u64FSBase = ASMRdMsr(MSR_K8_FS_BASE);
3094 uint64_t u64GSBase = ASMRdMsr(MSR_K8_GS_BASE);
3095 rc = VMXWriteVmcs64(VMX_VMCS_HOST_FS_BASE, u64FSBase);
3096 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_GS_BASE, u64GSBase);
3097 AssertRCReturn(rc, rc);
3098
3099 /* Store the base if we have to restore FS or GS manually as we need to restore the base as well. */
3100 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_FS)
3101 pVCpu->hm.s.vmx.RestoreHost.uHostFSBase = u64FSBase;
3102 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_GS)
3103 pVCpu->hm.s.vmx.RestoreHost.uHostGSBase = u64GSBase;
3104#endif
3105 return rc;
3106}
3107
3108
3109/**
3110 * Saves certain host MSRs in the VM-Exit MSR-load area and some in the
3111 * host-state area of the VMCS. Theses MSRs will be automatically restored on
3112 * the host after every successful VM-exit.
3113 *
3114 * @returns VBox status code.
3115 * @param pVM The cross context VM structure.
3116 * @param pVCpu The cross context virtual CPU structure.
3117 *
3118 * @remarks No-long-jump zone!!!
3119 */
3120DECLINLINE(int) hmR0VmxSaveHostMsrs(PVM pVM, PVMCPU pVCpu)
3121{
3122 NOREF(pVM);
3123
3124 AssertPtr(pVCpu);
3125 AssertPtr(pVCpu->hm.s.vmx.pvHostMsr);
3126
3127 /*
3128 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
3129 * rather than swapping them on every VM-entry.
3130 */
3131 hmR0VmxLazySaveHostMsrs(pVCpu);
3132
3133 /*
3134 * Host Sysenter MSRs.
3135 */
3136 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS));
3137#if HC_ARCH_BITS == 32
3138 rc |= VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP));
3139 rc |= VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP));
3140#else
3141 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP));
3142 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP));
3143#endif
3144 AssertRCReturn(rc, rc);
3145
3146 /*
3147 * Host EFER MSR.
3148 * If the CPU supports the newer VMCS controls for managing EFER, use it.
3149 * Otherwise it's done as part of auto-load/store MSR area in the VMCS, see hmR0VmxLoadGuestMsrs().
3150 */
3151 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
3152 {
3153 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, pVM->hm.s.vmx.u64HostEfer);
3154 AssertRCReturn(rc, rc);
3155 }
3156
3157 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
3158 * hmR0VmxLoadGuestExitCtls() !! */
3159
3160 return rc;
3161}
3162
3163
3164/**
3165 * Figures out if we need to swap the EFER MSR which is particularly expensive.
3166 *
3167 * We check all relevant bits. For now, that's everything besides LMA/LME, as
3168 * these two bits are handled by VM-entry, see hmR0VmxLoadGuestExitCtls() and
3169 * hmR0VMxLoadGuestEntryCtls().
3170 *
3171 * @returns true if we need to load guest EFER, false otherwise.
3172 * @param pVCpu The cross context virtual CPU structure.
3173 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3174 * out-of-sync. Make sure to update the required fields
3175 * before using them.
3176 *
3177 * @remarks Requires EFER, CR4.
3178 * @remarks No-long-jump zone!!!
3179 */
3180static bool hmR0VmxShouldSwapEferMsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3181{
3182#ifdef HMVMX_ALWAYS_SWAP_EFER
3183 return true;
3184#endif
3185
3186#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
3187 /* For 32-bit hosts running 64-bit guests, we always swap EFER in the world-switcher. Nothing to do here. */
3188 if (CPUMIsGuestInLongMode(pVCpu))
3189 return false;
3190#endif
3191
3192 PVM pVM = pVCpu->CTX_SUFF(pVM);
3193 uint64_t u64HostEfer = pVM->hm.s.vmx.u64HostEfer;
3194 uint64_t u64GuestEfer = pMixedCtx->msrEFER;
3195
3196 /*
3197 * For 64-bit guests, if EFER.SCE bit differs, we need to swap to ensure that the
3198 * guest's SYSCALL behaviour isn't screwed. See @bugref{7386}.
3199 */
3200 if ( CPUMIsGuestInLongMode(pVCpu)
3201 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
3202 {
3203 return true;
3204 }
3205
3206 /*
3207 * If the guest uses PAE and EFER.NXE bit differs, we need to swap EFER as it
3208 * affects guest paging. 64-bit paging implies CR4.PAE as well.
3209 * See Intel spec. 4.5 "IA-32e Paging" and Intel spec. 4.1.1 "Three Paging Modes".
3210 */
3211 if ( (pMixedCtx->cr4 & X86_CR4_PAE)
3212 && (pMixedCtx->cr0 & X86_CR0_PG)
3213 && (u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
3214 {
3215 /* Assert that host is PAE capable. */
3216 Assert(pVM->hm.s.cpuid.u32AMDFeatureEDX & X86_CPUID_EXT_FEATURE_EDX_NX);
3217 return true;
3218 }
3219
3220 /** @todo Check the latest Intel spec. for any other bits,
3221 * like SMEP/SMAP? */
3222 return false;
3223}
3224
3225
3226/**
3227 * Sets up VM-entry controls in the VMCS. These controls can affect things done
3228 * on VM-exit; e.g. "load debug controls", see Intel spec. 24.8.1 "VM-entry
3229 * controls".
3230 *
3231 * @returns VBox status code.
3232 * @param pVCpu The cross context virtual CPU structure.
3233 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3234 * out-of-sync. Make sure to update the required fields
3235 * before using them.
3236 *
3237 * @remarks Requires EFER.
3238 * @remarks No-long-jump zone!!!
3239 */
3240DECLINLINE(int) hmR0VmxLoadGuestEntryCtls(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3241{
3242 int rc = VINF_SUCCESS;
3243 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_ENTRY_CTLS))
3244 {
3245 PVM pVM = pVCpu->CTX_SUFF(pVM);
3246 uint32_t val = pVM->hm.s.vmx.Msrs.VmxEntry.n.disallowed0; /* Bits set here must be set in the VMCS. */
3247 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxEntry.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3248
3249 /* Load debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x capable CPUs only supports the 1-setting of this bit. */
3250 val |= VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG;
3251
3252 /* Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry. */
3253 if (CPUMIsGuestInLongModeEx(pMixedCtx))
3254 {
3255 val |= VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST;
3256 Log4(("Load[%RU32]: VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST\n", pVCpu->idCpu));
3257 }
3258 else
3259 Assert(!(val & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST));
3260
3261 /* If the CPU supports the newer VMCS controls for managing guest/host EFER, use it. */
3262 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
3263 && hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
3264 {
3265 val |= VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR;
3266 Log4(("Load[%RU32]: VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR\n", pVCpu->idCpu));
3267 }
3268
3269 /*
3270 * The following should -not- be set (since we're not in SMM mode):
3271 * - VMX_VMCS_CTRL_ENTRY_ENTRY_SMM
3272 * - VMX_VMCS_CTRL_ENTRY_DEACTIVATE_DUALMON
3273 */
3274
3275 /** @todo VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PERF_MSR,
3276 * VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PAT_MSR. */
3277
3278 if ((val & zap) != val)
3279 {
3280 LogRel(("hmR0VmxLoadGuestEntryCtls: Invalid VM-entry controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
3281 pVM->hm.s.vmx.Msrs.VmxEntry.n.disallowed0, val, zap));
3282 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
3283 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3284 }
3285
3286 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, val);
3287 AssertRCReturn(rc, rc);
3288
3289 pVCpu->hm.s.vmx.u32EntryCtls = val;
3290 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_ENTRY_CTLS);
3291 }
3292 return rc;
3293}
3294
3295
3296/**
3297 * Sets up the VM-exit controls in the VMCS.
3298 *
3299 * @returns VBox status code.
3300 * @param pVCpu The cross context virtual CPU structure.
3301 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3302 * out-of-sync. Make sure to update the required fields
3303 * before using them.
3304 *
3305 * @remarks Requires EFER.
3306 */
3307DECLINLINE(int) hmR0VmxLoadGuestExitCtls(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3308{
3309 NOREF(pMixedCtx);
3310
3311 int rc = VINF_SUCCESS;
3312 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_EXIT_CTLS))
3313 {
3314 PVM pVM = pVCpu->CTX_SUFF(pVM);
3315 uint32_t val = pVM->hm.s.vmx.Msrs.VmxExit.n.disallowed0; /* Bits set here must be set in the VMCS. */
3316 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3317
3318 /* Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only supported the 1-setting of this bit. */
3319 val |= VMX_VMCS_CTRL_EXIT_SAVE_DEBUG;
3320
3321 /*
3322 * Set the host long mode active (EFER.LMA) bit (which Intel calls "Host address-space size") if necessary.
3323 * On VM-exit, VT-x sets both the host EFER.LMA and EFER.LME bit to this value. See assertion in hmR0VmxSaveHostMsrs().
3324 */
3325#if HC_ARCH_BITS == 64
3326 val |= VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE;
3327 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE\n", pVCpu->idCpu));
3328#else
3329 Assert( pVCpu->hm.s.vmx.pfnStartVM == VMXR0SwitcherStartVM64
3330 || pVCpu->hm.s.vmx.pfnStartVM == VMXR0StartVM32);
3331 /* Set the host address-space size based on the switcher, not guest state. See @bugref{8432}. */
3332 if (pVCpu->hm.s.vmx.pfnStartVM == VMXR0SwitcherStartVM64)
3333 {
3334 /* The switcher returns to long mode, EFER is managed by the switcher. */
3335 val |= VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE;
3336 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE\n", pVCpu->idCpu));
3337 }
3338 else
3339 Assert(!(val & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE));
3340#endif
3341
3342 /* If the newer VMCS fields for managing EFER exists, use it. */
3343 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
3344 && hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
3345 {
3346 val |= VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR
3347 | VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR;
3348 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR, VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR\n", pVCpu->idCpu));
3349 }
3350
3351 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
3352 Assert(!(val & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT));
3353
3354 /** @todo VMX_VMCS_CTRL_EXIT_LOAD_PERF_MSR,
3355 * VMX_VMCS_CTRL_EXIT_SAVE_GUEST_PAT_MSR,
3356 * VMX_VMCS_CTRL_EXIT_LOAD_HOST_PAT_MSR. */
3357
3358 if ( pVM->hm.s.vmx.fUsePreemptTimer
3359 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_SAVE_VMX_PREEMPT_TIMER))
3360 val |= VMX_VMCS_CTRL_EXIT_SAVE_VMX_PREEMPT_TIMER;
3361
3362 if ((val & zap) != val)
3363 {
3364 LogRel(("hmR0VmxSetupProcCtls: Invalid VM-exit controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
3365 pVM->hm.s.vmx.Msrs.VmxExit.n.disallowed0, val, zap));
3366 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
3367 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3368 }
3369
3370 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, val);
3371 AssertRCReturn(rc, rc);
3372
3373 pVCpu->hm.s.vmx.u32ExitCtls = val;
3374 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_EXIT_CTLS);
3375 }
3376 return rc;
3377}
3378
3379
3380/**
3381 * Sets the TPR threshold in the VMCS.
3382 *
3383 * @returns VBox status code.
3384 * @param pVCpu The cross context virtual CPU structure.
3385 * @param u32TprThreshold The TPR threshold (task-priority class only).
3386 */
3387DECLINLINE(int) hmR0VmxApicSetTprThreshold(PVMCPU pVCpu, uint32_t u32TprThreshold)
3388{
3389 Assert(!(u32TprThreshold & 0xfffffff0)); /* Bits 31:4 MBZ. */
3390 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW); RT_NOREF_PV(pVCpu);
3391 return VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
3392}
3393
3394
3395/**
3396 * Loads the guest APIC and related state.
3397 *
3398 * @returns VBox status code.
3399 * @param pVCpu The cross context virtual CPU structure.
3400 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3401 * out-of-sync. Make sure to update the required fields
3402 * before using them.
3403 */
3404DECLINLINE(int) hmR0VmxLoadGuestApicState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3405{
3406 NOREF(pMixedCtx);
3407
3408 int rc = VINF_SUCCESS;
3409 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE))
3410 {
3411 /* Setup TPR shadowing. Also setup TPR patching for 32-bit guests. */
3412 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
3413 {
3414 Assert(pVCpu->hm.s.vmx.HCPhysVirtApic);
3415
3416 bool fPendingIntr = false;
3417 uint8_t u8Tpr = 0;
3418 uint8_t u8PendingIntr = 0;
3419 rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
3420 AssertRCReturn(rc, rc);
3421
3422 /*
3423 * If there are external interrupts pending but masked by the TPR value, instruct VT-x to cause a VM-exit when
3424 * the guest lowers its TPR below the highest-priority pending interrupt and we can deliver the interrupt.
3425 * If there are no external interrupts pending, set threshold to 0 to not cause a VM-exit. We will eventually deliver
3426 * the interrupt when we VM-exit for other reasons.
3427 */
3428 pVCpu->hm.s.vmx.pbVirtApic[0x80] = u8Tpr; /* Offset 0x80 is TPR in the APIC MMIO range. */
3429 uint32_t u32TprThreshold = 0;
3430 if (fPendingIntr)
3431 {
3432 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR (which is the Task-Priority Class). */
3433 const uint8_t u8PendingPriority = (u8PendingIntr >> 4) & 0xf;
3434 const uint8_t u8TprPriority = (u8Tpr >> 4) & 0xf;
3435 if (u8PendingPriority <= u8TprPriority)
3436 u32TprThreshold = u8PendingPriority;
3437 else
3438 u32TprThreshold = u8TprPriority; /* Required for Vista 64-bit guest, see @bugref{6398}. */
3439 }
3440
3441 rc = hmR0VmxApicSetTprThreshold(pVCpu, u32TprThreshold);
3442 AssertRCReturn(rc, rc);
3443 }
3444
3445 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
3446 }
3447 return rc;
3448}
3449
3450
3451/**
3452 * Gets the guest's interruptibility-state ("interrupt shadow" as AMD calls it).
3453 *
3454 * @returns Guest's interruptibility-state.
3455 * @param pVCpu The cross context virtual CPU structure.
3456 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3457 * out-of-sync. Make sure to update the required fields
3458 * before using them.
3459 *
3460 * @remarks No-long-jump zone!!!
3461 */
3462DECLINLINE(uint32_t) hmR0VmxGetGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3463{
3464 /*
3465 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
3466 */
3467 uint32_t uIntrState = 0;
3468 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
3469 {
3470 /* If inhibition is active, RIP & RFLAGS should've been accessed (i.e. read previously from the VMCS or from ring-3). */
3471 AssertMsg(HMVMXCPU_GST_IS_SET(pVCpu, HMVMX_UPDATED_GUEST_RIP | HMVMX_UPDATED_GUEST_RFLAGS),
3472 ("%#x\n", HMVMXCPU_GST_VALUE(pVCpu)));
3473 if (pMixedCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
3474 {
3475 if (pMixedCtx->eflags.Bits.u1IF)
3476 uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
3477 else
3478 uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS;
3479 }
3480 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
3481 {
3482 /*
3483 * We can clear the inhibit force flag as even if we go back to the recompiler without executing guest code in
3484 * VT-x, the flag's condition to be cleared is met and thus the cleared state is correct.
3485 */
3486 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
3487 }
3488 }
3489
3490 /*
3491 * NMIs to the guest are blocked after an NMI is injected until the guest executes an IRET. We only
3492 * bother with virtual-NMI blocking when we have support for virtual NMIs in the CPU, otherwise
3493 * setting this would block host-NMIs and IRET will not clear the blocking.
3494 *
3495 * See Intel spec. 26.6.1 "Interruptibility state". See @bugref{7445}.
3496 */
3497 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS)
3498 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
3499 {
3500 uIntrState |= VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI;
3501 }
3502
3503 return uIntrState;
3504}
3505
3506
3507/**
3508 * Loads the guest's interruptibility-state into the guest-state area in the
3509 * VMCS.
3510 *
3511 * @returns VBox status code.
3512 * @param pVCpu The cross context virtual CPU structure.
3513 * @param uIntrState The interruptibility-state to set.
3514 */
3515static int hmR0VmxLoadGuestIntrState(PVMCPU pVCpu, uint32_t uIntrState)
3516{
3517 NOREF(pVCpu);
3518 AssertMsg(!(uIntrState & 0xfffffff0), ("%#x\n", uIntrState)); /* Bits 31:4 MBZ. */
3519 Assert((uIntrState & 0x3) != 0x3); /* Block-by-STI and MOV SS cannot be simultaneously set. */
3520 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, uIntrState);
3521 AssertRC(rc);
3522 return rc;
3523}
3524
3525
3526/**
3527 * Loads the exception intercepts required for guest execution in the VMCS.
3528 *
3529 * @returns VBox status code.
3530 * @param pVCpu The cross context virtual CPU structure.
3531 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3532 * out-of-sync. Make sure to update the required fields
3533 * before using them.
3534 */
3535static int hmR0VmxLoadGuestXcptIntercepts(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3536{
3537 NOREF(pMixedCtx);
3538 int rc = VINF_SUCCESS;
3539 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
3540 {
3541 /* The remaining exception intercepts are handled elsewhere, e.g. in hmR0VmxLoadSharedCR0(). */
3542 if (pVCpu->hm.s.fGIMTrapXcptUD)
3543 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_UD);
3544#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
3545 else
3546 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_UD);
3547#endif
3548
3549 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_AC));
3550 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
3551
3552 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
3553 AssertRCReturn(rc, rc);
3554
3555 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
3556 Log4(("Load[%RU32]: VMX_VMCS32_CTRL_EXCEPTION_BITMAP=%#RX64 fContextUseFlags=%#RX32\n", pVCpu->idCpu,
3557 pVCpu->hm.s.vmx.u32XcptBitmap, HMCPU_CF_VALUE(pVCpu)));
3558 }
3559 return rc;
3560}
3561
3562
3563/**
3564 * Loads the guest's RIP into the guest-state area in the VMCS.
3565 *
3566 * @returns VBox status code.
3567 * @param pVCpu The cross context virtual CPU structure.
3568 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3569 * out-of-sync. Make sure to update the required fields
3570 * before using them.
3571 *
3572 * @remarks No-long-jump zone!!!
3573 */
3574static int hmR0VmxLoadGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3575{
3576 int rc = VINF_SUCCESS;
3577 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RIP))
3578 {
3579 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_RIP, pMixedCtx->rip);
3580 AssertRCReturn(rc, rc);
3581
3582 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RIP);
3583 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RIP=%#RX64 fContextUseFlags=%#RX32\n", pVCpu->idCpu, pMixedCtx->rip,
3584 HMCPU_CF_VALUE(pVCpu)));
3585 }
3586 return rc;
3587}
3588
3589
3590/**
3591 * Loads the guest's RSP into the guest-state area in the VMCS.
3592 *
3593 * @returns VBox status code.
3594 * @param pVCpu The cross context virtual CPU structure.
3595 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3596 * out-of-sync. Make sure to update the required fields
3597 * before using them.
3598 *
3599 * @remarks No-long-jump zone!!!
3600 */
3601static int hmR0VmxLoadGuestRsp(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3602{
3603 int rc = VINF_SUCCESS;
3604 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RSP))
3605 {
3606 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_RSP, pMixedCtx->rsp);
3607 AssertRCReturn(rc, rc);
3608
3609 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RSP);
3610 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RSP=%#RX64\n", pVCpu->idCpu, pMixedCtx->rsp));
3611 }
3612 return rc;
3613}
3614
3615
3616/**
3617 * Loads the guest's RFLAGS into the guest-state area in the VMCS.
3618 *
3619 * @returns VBox status code.
3620 * @param pVCpu The cross context virtual CPU structure.
3621 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3622 * out-of-sync. Make sure to update the required fields
3623 * before using them.
3624 *
3625 * @remarks No-long-jump zone!!!
3626 */
3627static int hmR0VmxLoadGuestRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3628{
3629 int rc = VINF_SUCCESS;
3630 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RFLAGS))
3631 {
3632 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
3633 Let us assert it as such and use 32-bit VMWRITE. */
3634 Assert(!(pMixedCtx->rflags.u64 >> 32));
3635 X86EFLAGS Eflags = pMixedCtx->eflags;
3636 /** @todo r=bird: There shall be no need to OR in X86_EFL_1 here, nor
3637 * shall there be any reason for clearing bits 63:22, 15, 5 and 3.
3638 * These will never be cleared/set, unless some other part of the VMM
3639 * code is buggy - in which case we're better of finding and fixing
3640 * those bugs than hiding them. */
3641 Assert(Eflags.u32 & X86_EFL_RA1_MASK);
3642 Assert(!(Eflags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
3643 Eflags.u32 &= VMX_EFLAGS_RESERVED_0; /* Bits 22-31, 15, 5 & 3 MBZ. */
3644 Eflags.u32 |= VMX_EFLAGS_RESERVED_1; /* Bit 1 MB1. */
3645
3646 /*
3647 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so we can restore them on VM-exit.
3648 * Modify the real-mode guest's eflags so that VT-x can run the real-mode guest code under Virtual 8086 mode.
3649 */
3650 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3651 {
3652 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
3653 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
3654 pVCpu->hm.s.vmx.RealMode.Eflags.u32 = Eflags.u32; /* Save the original eflags of the real-mode guest. */
3655 Eflags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
3656 Eflags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
3657 }
3658
3659 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_RFLAGS, Eflags.u32);
3660 AssertRCReturn(rc, rc);
3661
3662 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RFLAGS);
3663 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RFLAGS=%#RX32\n", pVCpu->idCpu, Eflags.u32));
3664 }
3665 return rc;
3666}
3667
3668
3669/**
3670 * Loads the guest RIP, RSP and RFLAGS into the guest-state area in the VMCS.
3671 *
3672 * @returns VBox status code.
3673 * @param pVCpu The cross context virtual CPU structure.
3674 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3675 * out-of-sync. Make sure to update the required fields
3676 * before using them.
3677 *
3678 * @remarks No-long-jump zone!!!
3679 */
3680DECLINLINE(int) hmR0VmxLoadGuestRipRspRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3681{
3682 int rc = hmR0VmxLoadGuestRip(pVCpu, pMixedCtx);
3683 rc |= hmR0VmxLoadGuestRsp(pVCpu, pMixedCtx);
3684 rc |= hmR0VmxLoadGuestRflags(pVCpu, pMixedCtx);
3685 AssertRCReturn(rc, rc);
3686 return rc;
3687}
3688
3689
3690/**
3691 * Loads the guest CR0 control register into the guest-state area in the VMCS.
3692 * CR0 is partially shared with the host and we have to consider the FPU bits.
3693 *
3694 * @returns VBox status code.
3695 * @param pVCpu The cross context virtual CPU structure.
3696 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3697 * out-of-sync. Make sure to update the required fields
3698 * before using them.
3699 *
3700 * @remarks No-long-jump zone!!!
3701 */
3702static int hmR0VmxLoadSharedCR0(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3703{
3704 /*
3705 * Guest CR0.
3706 * Guest FPU.
3707 */
3708 int rc = VINF_SUCCESS;
3709 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
3710 {
3711 Assert(!(pMixedCtx->cr0 >> 32));
3712 uint32_t u32GuestCR0 = pMixedCtx->cr0;
3713 PVM pVM = pVCpu->CTX_SUFF(pVM);
3714
3715 /* The guest's view (read access) of its CR0 is unblemished. */
3716 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_READ_SHADOW, u32GuestCR0);
3717 AssertRCReturn(rc, rc);
3718 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR0_READ_SHADOW=%#RX32\n", pVCpu->idCpu, u32GuestCR0));
3719
3720 /* Setup VT-x's view of the guest CR0. */
3721 /* Minimize VM-exits due to CR3 changes when we have NestedPaging. */
3722 if (pVM->hm.s.fNestedPaging)
3723 {
3724 if (CPUMIsGuestPagingEnabledEx(pMixedCtx))
3725 {
3726 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
3727 pVCpu->hm.s.vmx.u32ProcCtls &= ~( VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
3728 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT);
3729 }
3730 else
3731 {
3732 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
3733 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
3734 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
3735 }
3736
3737 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
3738 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3739 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
3740
3741 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
3742 AssertRCReturn(rc, rc);
3743 }
3744 else
3745 u32GuestCR0 |= X86_CR0_WP; /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
3746
3747 /*
3748 * Guest FPU bits.
3749 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be set on the first
3750 * CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
3751 */
3752 u32GuestCR0 |= X86_CR0_NE;
3753 bool fInterceptNM = false;
3754 if (CPUMIsGuestFPUStateActive(pVCpu))
3755 {
3756 fInterceptNM = false; /* Guest FPU active, no need to VM-exit on #NM. */
3757 /* The guest should still get #NM exceptions when it expects it to, so we should not clear TS & MP bits here.
3758 We're only concerned about -us- not intercepting #NMs when the guest-FPU is active. Not the guest itself! */
3759 }
3760 else
3761 {
3762 fInterceptNM = true; /* Guest FPU inactive, VM-exit on #NM for lazy FPU loading. */
3763 u32GuestCR0 |= X86_CR0_TS /* Guest can task switch quickly and do lazy FPU syncing. */
3764 | X86_CR0_MP; /* FWAIT/WAIT should not ignore CR0.TS and should generate #NM. */
3765 }
3766
3767 /* Catch floating point exceptions if we need to report them to the guest in a different way. */
3768 bool fInterceptMF = false;
3769 if (!(pMixedCtx->cr0 & X86_CR0_NE))
3770 fInterceptMF = true;
3771
3772 /* Finally, intercept all exceptions as we cannot directly inject them in real-mode, see hmR0VmxInjectEventVmcs(). */
3773 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3774 {
3775 Assert(PDMVmmDevHeapIsEnabled(pVM));
3776 Assert(pVM->hm.s.vmx.pRealModeTSS);
3777 pVCpu->hm.s.vmx.u32XcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
3778 fInterceptNM = true;
3779 fInterceptMF = true;
3780 }
3781 else
3782 {
3783 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
3784 pVCpu->hm.s.vmx.u32XcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
3785 }
3786 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
3787
3788 if (fInterceptNM)
3789 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_NM);
3790 else
3791 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_NM);
3792
3793 if (fInterceptMF)
3794 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_MF);
3795 else
3796 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_MF);
3797
3798 /* Additional intercepts for debugging, define these yourself explicitly. */
3799#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
3800 pVCpu->hm.s.vmx.u32XcptBitmap |= 0
3801 | RT_BIT(X86_XCPT_BP)
3802 | RT_BIT(X86_XCPT_DE)
3803 | RT_BIT(X86_XCPT_NM)
3804 | RT_BIT(X86_XCPT_TS)
3805 | RT_BIT(X86_XCPT_UD)
3806 | RT_BIT(X86_XCPT_NP)
3807 | RT_BIT(X86_XCPT_SS)
3808 | RT_BIT(X86_XCPT_GP)
3809 | RT_BIT(X86_XCPT_PF)
3810 | RT_BIT(X86_XCPT_MF)
3811 ;
3812#elif defined(HMVMX_ALWAYS_TRAP_PF)
3813 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_PF);
3814#endif
3815
3816 Assert(pVM->hm.s.fNestedPaging || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_PF)));
3817
3818 /* Set/clear the CR0 specific bits along with their exceptions (PE, PG, CD, NW). */
3819 uint32_t uSetCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
3820 uint32_t uZapCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
3821 if (pVM->hm.s.vmx.fUnrestrictedGuest) /* Exceptions for unrestricted-guests for fixed CR0 bits (PE, PG). */
3822 uSetCR0 &= ~(X86_CR0_PE | X86_CR0_PG);
3823 else
3824 Assert((uSetCR0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
3825
3826 u32GuestCR0 |= uSetCR0;
3827 u32GuestCR0 &= uZapCR0;
3828 u32GuestCR0 &= ~(X86_CR0_CD | X86_CR0_NW); /* Always enable caching. */
3829
3830 /* Write VT-x's view of the guest CR0 into the VMCS. */
3831 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_CR0, u32GuestCR0);
3832 AssertRCReturn(rc, rc);
3833 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR0=%#RX32 (uSetCR0=%#RX32 uZapCR0=%#RX32)\n", pVCpu->idCpu, u32GuestCR0, uSetCR0,
3834 uZapCR0));
3835
3836 /*
3837 * CR0 is shared between host and guest along with a CR0 read shadow. Therefore, certain bits must not be changed
3838 * by the guest because VT-x ignores saving/restoring them (namely CD, ET, NW) and for certain other bits
3839 * we want to be notified immediately of guest CR0 changes (e.g. PG to update our shadow page tables).
3840 */
3841 uint32_t u32CR0Mask = 0;
3842 u32CR0Mask = X86_CR0_PE
3843 | X86_CR0_NE
3844 | X86_CR0_WP
3845 | X86_CR0_PG
3846 | X86_CR0_ET /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.ET */
3847 | X86_CR0_CD /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.CD */
3848 | X86_CR0_NW; /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.NW */
3849
3850 /** @todo Avoid intercepting CR0.PE with unrestricted guests. Fix PGM
3851 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
3852 * and @bugref{6944}. */
3853#if 0
3854 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3855 u32CR0Mask &= ~X86_CR0_PE;
3856#endif
3857 if (pVM->hm.s.fNestedPaging)
3858 u32CR0Mask &= ~X86_CR0_WP;
3859
3860 /* If the guest FPU state is active, don't need to VM-exit on writes to FPU related bits in CR0. */
3861 if (fInterceptNM)
3862 {
3863 u32CR0Mask |= X86_CR0_TS
3864 | X86_CR0_MP;
3865 }
3866
3867 /* Write the CR0 mask into the VMCS and update the VCPU's copy of the current CR0 mask. */
3868 pVCpu->hm.s.vmx.u32CR0Mask = u32CR0Mask;
3869 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_MASK, u32CR0Mask);
3870 AssertRCReturn(rc, rc);
3871 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR0_MASK=%#RX32\n", pVCpu->idCpu, u32CR0Mask));
3872
3873 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR0);
3874 }
3875 return rc;
3876}
3877
3878
3879/**
3880 * Loads the guest control registers (CR3, CR4) into the guest-state area
3881 * in the VMCS.
3882 *
3883 * @returns VBox strict status code.
3884 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
3885 * without unrestricted guest access and the VMMDev is not presently
3886 * mapped (e.g. EFI32).
3887 *
3888 * @param pVCpu The cross context virtual CPU structure.
3889 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3890 * out-of-sync. Make sure to update the required fields
3891 * before using them.
3892 *
3893 * @remarks No-long-jump zone!!!
3894 */
3895static VBOXSTRICTRC hmR0VmxLoadGuestCR3AndCR4(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3896{
3897 int rc = VINF_SUCCESS;
3898 PVM pVM = pVCpu->CTX_SUFF(pVM);
3899
3900 /*
3901 * Guest CR2.
3902 * It's always loaded in the assembler code. Nothing to do here.
3903 */
3904
3905 /*
3906 * Guest CR3.
3907 */
3908 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR3))
3909 {
3910 RTGCPHYS GCPhysGuestCR3 = NIL_RTGCPHYS;
3911 if (pVM->hm.s.fNestedPaging)
3912 {
3913 pVCpu->hm.s.vmx.HCPhysEPTP = PGMGetHyperCR3(pVCpu);
3914
3915 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
3916 Assert(pVCpu->hm.s.vmx.HCPhysEPTP);
3917 Assert(!(pVCpu->hm.s.vmx.HCPhysEPTP & UINT64_C(0xfff0000000000000)));
3918 Assert(!(pVCpu->hm.s.vmx.HCPhysEPTP & 0xfff));
3919
3920 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
3921 pVCpu->hm.s.vmx.HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
3922 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
3923
3924 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
3925 AssertMsg( ((pVCpu->hm.s.vmx.HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
3926 && ((pVCpu->hm.s.vmx.HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
3927 ("EPTP %#RX64\n", pVCpu->hm.s.vmx.HCPhysEPTP));
3928 AssertMsg( !((pVCpu->hm.s.vmx.HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
3929 || (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
3930 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVCpu->hm.s.vmx.HCPhysEPTP));
3931
3932 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVCpu->hm.s.vmx.HCPhysEPTP);
3933 AssertRCReturn(rc, rc);
3934 Log4(("Load[%RU32]: VMX_VMCS64_CTRL_EPTP_FULL=%#RX64\n", pVCpu->idCpu, pVCpu->hm.s.vmx.HCPhysEPTP));
3935
3936 if ( pVM->hm.s.vmx.fUnrestrictedGuest
3937 || CPUMIsGuestPagingEnabledEx(pMixedCtx))
3938 {
3939 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
3940 if (CPUMIsGuestInPAEModeEx(pMixedCtx))
3941 {
3942 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
3943 AssertRCReturn(rc, rc);
3944 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u);
3945 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u);
3946 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u);
3947 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u);
3948 AssertRCReturn(rc, rc);
3949 }
3950
3951 /* The guest's view of its CR3 is unblemished with Nested Paging when the guest is using paging or we
3952 have Unrestricted Execution to handle the guest when it's not using paging. */
3953 GCPhysGuestCR3 = pMixedCtx->cr3;
3954 }
3955 else
3956 {
3957 /*
3958 * The guest is not using paging, but the CPU (VT-x) has to. While the guest thinks it accesses physical memory
3959 * directly, we use our identity-mapped page table to map guest-linear to guest-physical addresses.
3960 * EPT takes care of translating it to host-physical addresses.
3961 */
3962 RTGCPHYS GCPhys;
3963 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
3964
3965 /* We obtain it here every time as the guest could have relocated this PCI region. */
3966 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
3967 if (RT_SUCCESS(rc))
3968 { /* likely */ }
3969 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
3970 {
3971 Log4(("Load[%RU32]: VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n", pVCpu->idCpu));
3972 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
3973 }
3974 else
3975 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
3976
3977 GCPhysGuestCR3 = GCPhys;
3978 }
3979
3980 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR3=%#RGp (GstN)\n", pVCpu->idCpu, GCPhysGuestCR3));
3981 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_CR3, GCPhysGuestCR3);
3982 }
3983 else
3984 {
3985 /* Non-nested paging case, just use the hypervisor's CR3. */
3986 RTHCPHYS HCPhysGuestCR3 = PGMGetHyperCR3(pVCpu);
3987
3988 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR3=%#RHv (HstN)\n", pVCpu->idCpu, HCPhysGuestCR3));
3989 rc = VMXWriteVmcsHstN(VMX_VMCS_GUEST_CR3, HCPhysGuestCR3);
3990 }
3991 AssertRCReturn(rc, rc);
3992
3993 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR3);
3994 }
3995
3996 /*
3997 * Guest CR4.
3998 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
3999 */
4000 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR4))
4001 {
4002 Assert(!(pMixedCtx->cr4 >> 32));
4003 uint32_t u32GuestCR4 = pMixedCtx->cr4;
4004
4005 /* The guest's view of its CR4 is unblemished. */
4006 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_READ_SHADOW, u32GuestCR4);
4007 AssertRCReturn(rc, rc);
4008 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR4_READ_SHADOW=%#RX32\n", pVCpu->idCpu, u32GuestCR4));
4009
4010 /* Setup VT-x's view of the guest CR4. */
4011 /*
4012 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software interrupts to the 8086 program
4013 * interrupt handler. Clear the VME bit (the interrupt redirection bitmap is already all 0, see hmR3InitFinalizeR0())
4014 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
4015 */
4016 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4017 {
4018 Assert(pVM->hm.s.vmx.pRealModeTSS);
4019 Assert(PDMVmmDevHeapIsEnabled(pVM));
4020 u32GuestCR4 &= ~X86_CR4_VME;
4021 }
4022
4023 if (pVM->hm.s.fNestedPaging)
4024 {
4025 if ( !CPUMIsGuestPagingEnabledEx(pMixedCtx)
4026 && !pVM->hm.s.vmx.fUnrestrictedGuest)
4027 {
4028 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
4029 u32GuestCR4 |= X86_CR4_PSE;
4030 /* Our identity mapping is a 32-bit page directory. */
4031 u32GuestCR4 &= ~X86_CR4_PAE;
4032 }
4033 /* else use guest CR4.*/
4034 }
4035 else
4036 {
4037 /*
4038 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
4039 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
4040 */
4041 switch (pVCpu->hm.s.enmShadowMode)
4042 {
4043 case PGMMODE_REAL: /* Real-mode. */
4044 case PGMMODE_PROTECTED: /* Protected mode without paging. */
4045 case PGMMODE_32_BIT: /* 32-bit paging. */
4046 {
4047 u32GuestCR4 &= ~X86_CR4_PAE;
4048 break;
4049 }
4050
4051 case PGMMODE_PAE: /* PAE paging. */
4052 case PGMMODE_PAE_NX: /* PAE paging with NX. */
4053 {
4054 u32GuestCR4 |= X86_CR4_PAE;
4055 break;
4056 }
4057
4058 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
4059 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
4060#ifdef VBOX_ENABLE_64_BITS_GUESTS
4061 break;
4062#endif
4063 default:
4064 AssertFailed();
4065 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
4066 }
4067 }
4068
4069 /* We need to set and clear the CR4 specific bits here (mainly the X86_CR4_VMXE bit). */
4070 uint64_t uSetCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
4071 uint64_t uZapCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
4072 u32GuestCR4 |= uSetCR4;
4073 u32GuestCR4 &= uZapCR4;
4074
4075 /* Write VT-x's view of the guest CR4 into the VMCS. */
4076 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR4=%#RX32 (Set=%#RX32 Zap=%#RX32)\n", pVCpu->idCpu, u32GuestCR4, uSetCR4, uZapCR4));
4077 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_CR4, u32GuestCR4);
4078 AssertRCReturn(rc, rc);
4079
4080 /* Setup CR4 mask. CR4 flags owned by the host, if the guest attempts to change them, that would cause a VM-exit. */
4081 uint32_t u32CR4Mask = X86_CR4_VME
4082 | X86_CR4_PAE
4083 | X86_CR4_PGE
4084 | X86_CR4_PSE
4085 | X86_CR4_VMXE;
4086 if (pVM->cpum.ro.HostFeatures.fXSaveRstor)
4087 u32CR4Mask |= X86_CR4_OSXSAVE;
4088 pVCpu->hm.s.vmx.u32CR4Mask = u32CR4Mask;
4089 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_MASK, u32CR4Mask);
4090 AssertRCReturn(rc, rc);
4091
4092 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
4093 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pMixedCtx->cr4 & X86_CR4_OSXSAVE) && pMixedCtx->aXcr[0] != ASMGetXcr0();
4094
4095 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR4);
4096 }
4097 return rc;
4098}
4099
4100
4101/**
4102 * Loads the guest debug registers into the guest-state area in the VMCS.
4103 *
4104 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
4105 *
4106 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
4107 *
4108 * @returns VBox status code.
4109 * @param pVCpu The cross context virtual CPU structure.
4110 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4111 * out-of-sync. Make sure to update the required fields
4112 * before using them.
4113 *
4114 * @remarks No-long-jump zone!!!
4115 */
4116static int hmR0VmxLoadSharedDebugState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4117{
4118 if (!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_DEBUG))
4119 return VINF_SUCCESS;
4120
4121#ifdef VBOX_STRICT
4122 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
4123 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
4124 {
4125 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
4126 Assert((pMixedCtx->dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0); /* Bits 63:32, 15, 14, 12, 11 are reserved. */
4127 Assert((pMixedCtx->dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK); /* Bit 10 is reserved (RA1). */
4128 }
4129#endif
4130
4131 int rc;
4132 PVM pVM = pVCpu->CTX_SUFF(pVM);
4133 bool fSteppingDB = false;
4134 bool fInterceptMovDRx = false;
4135 if (pVCpu->hm.s.fSingleInstruction)
4136 {
4137 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
4138 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG)
4139 {
4140 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG;
4141 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
4142 AssertRCReturn(rc, rc);
4143 Assert(fSteppingDB == false);
4144 }
4145 else
4146 {
4147 pMixedCtx->eflags.u32 |= X86_EFL_TF;
4148 pVCpu->hm.s.fClearTrapFlag = true;
4149 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
4150 fSteppingDB = true;
4151 }
4152 }
4153
4154 if ( fSteppingDB
4155 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
4156 {
4157 /*
4158 * Use the combined guest and host DRx values found in the hypervisor
4159 * register set because the debugger has breakpoints active or someone
4160 * is single stepping on the host side without a monitor trap flag.
4161 *
4162 * Note! DBGF expects a clean DR6 state before executing guest code.
4163 */
4164#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4165 if ( CPUMIsGuestInLongModeEx(pMixedCtx)
4166 && !CPUMIsHyperDebugStateActivePending(pVCpu))
4167 {
4168 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
4169 Assert(CPUMIsHyperDebugStateActivePending(pVCpu));
4170 Assert(!CPUMIsGuestDebugStateActivePending(pVCpu));
4171 }
4172 else
4173#endif
4174 if (!CPUMIsHyperDebugStateActive(pVCpu))
4175 {
4176 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
4177 Assert(CPUMIsHyperDebugStateActive(pVCpu));
4178 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
4179 }
4180
4181 /* Update DR7. (The other DRx values are handled by CPUM one way or the other.) */
4182 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, (uint32_t)CPUMGetHyperDR7(pVCpu));
4183 AssertRCReturn(rc, rc);
4184
4185 pVCpu->hm.s.fUsingHyperDR7 = true;
4186 fInterceptMovDRx = true;
4187 }
4188 else
4189 {
4190 /*
4191 * If the guest has enabled debug registers, we need to load them prior to
4192 * executing guest code so they'll trigger at the right time.
4193 */
4194 if (pMixedCtx->dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD)) /** @todo Why GD? */
4195 {
4196#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4197 if ( CPUMIsGuestInLongModeEx(pMixedCtx)
4198 && !CPUMIsGuestDebugStateActivePending(pVCpu))
4199 {
4200 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
4201 Assert(CPUMIsGuestDebugStateActivePending(pVCpu));
4202 Assert(!CPUMIsHyperDebugStateActivePending(pVCpu));
4203 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
4204 }
4205 else
4206#endif
4207 if (!CPUMIsGuestDebugStateActive(pVCpu))
4208 {
4209 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
4210 Assert(CPUMIsGuestDebugStateActive(pVCpu));
4211 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
4212 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
4213 }
4214 Assert(!fInterceptMovDRx);
4215 }
4216 /*
4217 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
4218 * must intercept #DB in order to maintain a correct DR6 guest value, and
4219 * because we need to intercept it to prevent nested #DBs from hanging the
4220 * CPU, we end up always having to intercept it. See hmR0VmxInitXcptBitmap.
4221 */
4222#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4223 else if ( !CPUMIsGuestDebugStateActivePending(pVCpu)
4224 && !CPUMIsGuestDebugStateActive(pVCpu))
4225#else
4226 else if (!CPUMIsGuestDebugStateActive(pVCpu))
4227#endif
4228 {
4229 fInterceptMovDRx = true;
4230 }
4231
4232 /* Update guest DR7. */
4233 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, pMixedCtx->dr[7]);
4234 AssertRCReturn(rc, rc);
4235
4236 pVCpu->hm.s.fUsingHyperDR7 = false;
4237 }
4238
4239 /*
4240 * Update the processor-based VM-execution controls regarding intercepting MOV DRx instructions.
4241 */
4242 if (fInterceptMovDRx)
4243 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
4244 else
4245 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
4246 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
4247 AssertRCReturn(rc, rc);
4248
4249 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_DEBUG);
4250 return VINF_SUCCESS;
4251}
4252
4253
4254#ifdef VBOX_STRICT
4255/**
4256 * Strict function to validate segment registers.
4257 *
4258 * @remarks ASSUMES CR0 is up to date.
4259 */
4260static void hmR0VmxValidateSegmentRegs(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
4261{
4262 /* Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers". */
4263 /* NOTE: The reason we check for attribute value 0 and not just the unusable bit here is because hmR0VmxWriteSegmentReg()
4264 * only updates the VMCS' copy of the value with the unusable bit and doesn't change the guest-context value. */
4265 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
4266 && ( !CPUMIsGuestInRealModeEx(pCtx)
4267 && !CPUMIsGuestInV86ModeEx(pCtx)))
4268 {
4269 /* Protected mode checks */
4270 /* CS */
4271 Assert(pCtx->cs.Attr.n.u1Present);
4272 Assert(!(pCtx->cs.Attr.u & 0xf00));
4273 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
4274 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
4275 || !(pCtx->cs.Attr.n.u1Granularity));
4276 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
4277 || (pCtx->cs.Attr.n.u1Granularity));
4278 /* CS cannot be loaded with NULL in protected mode. */
4279 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
4280 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
4281 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
4282 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
4283 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
4284 else
4285 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
4286 /* SS */
4287 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
4288 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
4289 if ( !(pCtx->cr0 & X86_CR0_PE)
4290 || pCtx->cs.Attr.n.u4Type == 3)
4291 {
4292 Assert(!pCtx->ss.Attr.n.u2Dpl);
4293 }
4294 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
4295 {
4296 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
4297 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
4298 Assert(pCtx->ss.Attr.n.u1Present);
4299 Assert(!(pCtx->ss.Attr.u & 0xf00));
4300 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
4301 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
4302 || !(pCtx->ss.Attr.n.u1Granularity));
4303 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
4304 || (pCtx->ss.Attr.n.u1Granularity));
4305 }
4306 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxWriteSegmentReg(). */
4307 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
4308 {
4309 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4310 Assert(pCtx->ds.Attr.n.u1Present);
4311 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
4312 Assert(!(pCtx->ds.Attr.u & 0xf00));
4313 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
4314 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
4315 || !(pCtx->ds.Attr.n.u1Granularity));
4316 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
4317 || (pCtx->ds.Attr.n.u1Granularity));
4318 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4319 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
4320 }
4321 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
4322 {
4323 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4324 Assert(pCtx->es.Attr.n.u1Present);
4325 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
4326 Assert(!(pCtx->es.Attr.u & 0xf00));
4327 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
4328 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
4329 || !(pCtx->es.Attr.n.u1Granularity));
4330 Assert( !(pCtx->es.u32Limit & 0xfff00000)
4331 || (pCtx->es.Attr.n.u1Granularity));
4332 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4333 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
4334 }
4335 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
4336 {
4337 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4338 Assert(pCtx->fs.Attr.n.u1Present);
4339 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
4340 Assert(!(pCtx->fs.Attr.u & 0xf00));
4341 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
4342 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
4343 || !(pCtx->fs.Attr.n.u1Granularity));
4344 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
4345 || (pCtx->fs.Attr.n.u1Granularity));
4346 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4347 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
4348 }
4349 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
4350 {
4351 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4352 Assert(pCtx->gs.Attr.n.u1Present);
4353 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
4354 Assert(!(pCtx->gs.Attr.u & 0xf00));
4355 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
4356 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
4357 || !(pCtx->gs.Attr.n.u1Granularity));
4358 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
4359 || (pCtx->gs.Attr.n.u1Granularity));
4360 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4361 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
4362 }
4363 /* 64-bit capable CPUs. */
4364# if HC_ARCH_BITS == 64
4365 Assert(!(pCtx->cs.u64Base >> 32));
4366 Assert(!pCtx->ss.Attr.u || !(pCtx->ss.u64Base >> 32));
4367 Assert(!pCtx->ds.Attr.u || !(pCtx->ds.u64Base >> 32));
4368 Assert(!pCtx->es.Attr.u || !(pCtx->es.u64Base >> 32));
4369# endif
4370 }
4371 else if ( CPUMIsGuestInV86ModeEx(pCtx)
4372 || ( CPUMIsGuestInRealModeEx(pCtx)
4373 && !pVM->hm.s.vmx.fUnrestrictedGuest))
4374 {
4375 /* Real and v86 mode checks. */
4376 /* hmR0VmxWriteSegmentReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
4377 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
4378 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4379 {
4380 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3; u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
4381 }
4382 else
4383 {
4384 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
4385 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
4386 }
4387
4388 /* CS */
4389 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
4390 Assert(pCtx->cs.u32Limit == 0xffff);
4391 Assert(u32CSAttr == 0xf3);
4392 /* SS */
4393 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
4394 Assert(pCtx->ss.u32Limit == 0xffff);
4395 Assert(u32SSAttr == 0xf3);
4396 /* DS */
4397 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
4398 Assert(pCtx->ds.u32Limit == 0xffff);
4399 Assert(u32DSAttr == 0xf3);
4400 /* ES */
4401 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
4402 Assert(pCtx->es.u32Limit == 0xffff);
4403 Assert(u32ESAttr == 0xf3);
4404 /* FS */
4405 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
4406 Assert(pCtx->fs.u32Limit == 0xffff);
4407 Assert(u32FSAttr == 0xf3);
4408 /* GS */
4409 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
4410 Assert(pCtx->gs.u32Limit == 0xffff);
4411 Assert(u32GSAttr == 0xf3);
4412 /* 64-bit capable CPUs. */
4413# if HC_ARCH_BITS == 64
4414 Assert(!(pCtx->cs.u64Base >> 32));
4415 Assert(!u32SSAttr || !(pCtx->ss.u64Base >> 32));
4416 Assert(!u32DSAttr || !(pCtx->ds.u64Base >> 32));
4417 Assert(!u32ESAttr || !(pCtx->es.u64Base >> 32));
4418# endif
4419 }
4420}
4421#endif /* VBOX_STRICT */
4422
4423
4424/**
4425 * Writes a guest segment register into the guest-state area in the VMCS.
4426 *
4427 * @returns VBox status code.
4428 * @param pVCpu The cross context virtual CPU structure.
4429 * @param idxSel Index of the selector in the VMCS.
4430 * @param idxLimit Index of the segment limit in the VMCS.
4431 * @param idxBase Index of the segment base in the VMCS.
4432 * @param idxAccess Index of the access rights of the segment in the VMCS.
4433 * @param pSelReg Pointer to the segment selector.
4434 *
4435 * @remarks No-long-jump zone!!!
4436 */
4437static int hmR0VmxWriteSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase,
4438 uint32_t idxAccess, PCPUMSELREG pSelReg)
4439{
4440 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); /* 16-bit guest selector field. */
4441 rc |= VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); /* 32-bit guest segment limit field. */
4442 rc |= VMXWriteVmcsGstN(idxBase, pSelReg->u64Base); /* Natural width guest segment base field.*/
4443 AssertRCReturn(rc, rc);
4444
4445 uint32_t u32Access = pSelReg->Attr.u;
4446 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4447 {
4448 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
4449 u32Access = 0xf3;
4450 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
4451 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
4452 }
4453 else
4454 {
4455 /*
4456 * The way to differentiate between whether this is really a null selector or was just a selector loaded with 0 in
4457 * real-mode is using the segment attributes. A selector loaded in real-mode with the value 0 is valid and usable in
4458 * protected-mode and we should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures NULL selectors
4459 * loaded in protected-mode have their attribute as 0.
4460 */
4461 if (!u32Access)
4462 u32Access = X86DESCATTR_UNUSABLE;
4463 }
4464
4465 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
4466 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
4467 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
4468
4469 rc = VMXWriteVmcs32(idxAccess, u32Access); /* 32-bit guest segment access-rights field. */
4470 AssertRCReturn(rc, rc);
4471 return rc;
4472}
4473
4474
4475/**
4476 * Loads the guest segment registers, GDTR, IDTR, LDTR, (TR, FS and GS bases)
4477 * into the guest-state area in the VMCS.
4478 *
4479 * @returns VBox status code.
4480 * @param pVCpu The cross context virtual CPU structure.
4481 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4482 * out-of-sync. Make sure to update the required fields
4483 * before using them.
4484 *
4485 * @remarks ASSUMES pMixedCtx->cr0 is up to date (strict builds validation).
4486 * @remarks No-long-jump zone!!!
4487 */
4488static int hmR0VmxLoadGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4489{
4490 int rc = VERR_INTERNAL_ERROR_5;
4491 PVM pVM = pVCpu->CTX_SUFF(pVM);
4492
4493 /*
4494 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
4495 */
4496 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS))
4497 {
4498 /* Save the segment attributes for real-on-v86 mode hack, so we can restore them on VM-exit. */
4499 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4500 {
4501 pVCpu->hm.s.vmx.RealMode.AttrCS.u = pMixedCtx->cs.Attr.u;
4502 pVCpu->hm.s.vmx.RealMode.AttrSS.u = pMixedCtx->ss.Attr.u;
4503 pVCpu->hm.s.vmx.RealMode.AttrDS.u = pMixedCtx->ds.Attr.u;
4504 pVCpu->hm.s.vmx.RealMode.AttrES.u = pMixedCtx->es.Attr.u;
4505 pVCpu->hm.s.vmx.RealMode.AttrFS.u = pMixedCtx->fs.Attr.u;
4506 pVCpu->hm.s.vmx.RealMode.AttrGS.u = pMixedCtx->gs.Attr.u;
4507 }
4508
4509#ifdef VBOX_WITH_REM
4510 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
4511 {
4512 Assert(pVM->hm.s.vmx.pRealModeTSS);
4513 AssertCompile(PGMMODE_REAL < PGMMODE_PROTECTED);
4514 if ( pVCpu->hm.s.vmx.fWasInRealMode
4515 && PGMGetGuestMode(pVCpu) >= PGMMODE_PROTECTED)
4516 {
4517 /* Signal that the recompiler must flush its code-cache as the guest -may- rewrite code it will later execute
4518 in real-mode (e.g. OpenBSD 4.0) */
4519 REMFlushTBs(pVM);
4520 Log4(("Load[%RU32]: Switch to protected mode detected!\n", pVCpu->idCpu));
4521 pVCpu->hm.s.vmx.fWasInRealMode = false;
4522 }
4523 }
4524#endif
4525 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_CS_SEL, VMX_VMCS32_GUEST_CS_LIMIT, VMX_VMCS_GUEST_CS_BASE,
4526 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS, &pMixedCtx->cs);
4527 AssertRCReturn(rc, rc);
4528 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_SS_SEL, VMX_VMCS32_GUEST_SS_LIMIT, VMX_VMCS_GUEST_SS_BASE,
4529 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS, &pMixedCtx->ss);
4530 AssertRCReturn(rc, rc);
4531 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_DS_SEL, VMX_VMCS32_GUEST_DS_LIMIT, VMX_VMCS_GUEST_DS_BASE,
4532 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS, &pMixedCtx->ds);
4533 AssertRCReturn(rc, rc);
4534 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_ES_SEL, VMX_VMCS32_GUEST_ES_LIMIT, VMX_VMCS_GUEST_ES_BASE,
4535 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS, &pMixedCtx->es);
4536 AssertRCReturn(rc, rc);
4537 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FS_SEL, VMX_VMCS32_GUEST_FS_LIMIT, VMX_VMCS_GUEST_FS_BASE,
4538 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS, &pMixedCtx->fs);
4539 AssertRCReturn(rc, rc);
4540 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_GS_SEL, VMX_VMCS32_GUEST_GS_LIMIT, VMX_VMCS_GUEST_GS_BASE,
4541 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS, &pMixedCtx->gs);
4542 AssertRCReturn(rc, rc);
4543
4544#ifdef VBOX_STRICT
4545 /* Validate. */
4546 hmR0VmxValidateSegmentRegs(pVM, pVCpu, pMixedCtx);
4547#endif
4548
4549 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS);
4550 Log4(("Load[%RU32]: CS=%#RX16 Base=%#RX64 Limit=%#RX32 Attr=%#RX32\n", pVCpu->idCpu, pMixedCtx->cs.Sel,
4551 pMixedCtx->cs.u64Base, pMixedCtx->cs.u32Limit, pMixedCtx->cs.Attr.u));
4552 }
4553
4554 /*
4555 * Guest TR.
4556 */
4557 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_TR))
4558 {
4559 /*
4560 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is achieved
4561 * using the interrupt redirection bitmap (all bits cleared to let the guest handle INT-n's) in the TSS.
4562 * See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
4563 */
4564 uint16_t u16Sel = 0;
4565 uint32_t u32Limit = 0;
4566 uint64_t u64Base = 0;
4567 uint32_t u32AccessRights = 0;
4568
4569 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4570 {
4571 u16Sel = pMixedCtx->tr.Sel;
4572 u32Limit = pMixedCtx->tr.u32Limit;
4573 u64Base = pMixedCtx->tr.u64Base;
4574 u32AccessRights = pMixedCtx->tr.Attr.u;
4575 }
4576 else
4577 {
4578 Assert(pVM->hm.s.vmx.pRealModeTSS);
4579 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMR3CanExecuteGuest() -XXX- what about inner loop changes? */
4580
4581 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
4582 RTGCPHYS GCPhys;
4583 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
4584 AssertRCReturn(rc, rc);
4585
4586 X86DESCATTR DescAttr;
4587 DescAttr.u = 0;
4588 DescAttr.n.u1Present = 1;
4589 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
4590
4591 u16Sel = 0;
4592 u32Limit = HM_VTX_TSS_SIZE;
4593 u64Base = GCPhys; /* in real-mode phys = virt. */
4594 u32AccessRights = DescAttr.u;
4595 }
4596
4597 /* Validate. */
4598 Assert(!(u16Sel & RT_BIT(2)));
4599 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
4600 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
4601 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
4602 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
4603 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
4604 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
4605 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
4606 Assert( (u32Limit & 0xfff) == 0xfff
4607 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
4608 Assert( !(pMixedCtx->tr.u32Limit & 0xfff00000)
4609 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
4610
4611 rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_TR_SEL, u16Sel);
4612 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit);
4613 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_TR_BASE, u64Base);
4614 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights);
4615 AssertRCReturn(rc, rc);
4616
4617 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_TR);
4618 Log4(("Load[%RU32]: VMX_VMCS_GUEST_TR_BASE=%#RX64\n", pVCpu->idCpu, u64Base));
4619 }
4620
4621 /*
4622 * Guest GDTR.
4623 */
4624 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_GDTR))
4625 {
4626 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pMixedCtx->gdtr.cbGdt);
4627 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_GDTR_BASE, pMixedCtx->gdtr.pGdt);
4628 AssertRCReturn(rc, rc);
4629
4630 /* Validate. */
4631 Assert(!(pMixedCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
4632
4633 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_GDTR);
4634 Log4(("Load[%RU32]: VMX_VMCS_GUEST_GDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->gdtr.pGdt));
4635 }
4636
4637 /*
4638 * Guest LDTR.
4639 */
4640 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LDTR))
4641 {
4642 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
4643 uint32_t u32Access = 0;
4644 if (!pMixedCtx->ldtr.Attr.u)
4645 u32Access = X86DESCATTR_UNUSABLE;
4646 else
4647 u32Access = pMixedCtx->ldtr.Attr.u;
4648
4649 rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_LDTR_SEL, pMixedCtx->ldtr.Sel);
4650 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pMixedCtx->ldtr.u32Limit);
4651 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_LDTR_BASE, pMixedCtx->ldtr.u64Base);
4652 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access);
4653 AssertRCReturn(rc, rc);
4654
4655 /* Validate. */
4656 if (!(u32Access & X86DESCATTR_UNUSABLE))
4657 {
4658 Assert(!(pMixedCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
4659 Assert(pMixedCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
4660 Assert(!pMixedCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
4661 Assert(pMixedCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
4662 Assert(!pMixedCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
4663 Assert(!(pMixedCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
4664 Assert( (pMixedCtx->ldtr.u32Limit & 0xfff) == 0xfff
4665 || !pMixedCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
4666 Assert( !(pMixedCtx->ldtr.u32Limit & 0xfff00000)
4667 || pMixedCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
4668 }
4669
4670 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_LDTR);
4671 Log4(("Load[%RU32]: VMX_VMCS_GUEST_LDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->ldtr.u64Base));
4672 }
4673
4674 /*
4675 * Guest IDTR.
4676 */
4677 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_IDTR))
4678 {
4679 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pMixedCtx->idtr.cbIdt);
4680 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_IDTR_BASE, pMixedCtx->idtr.pIdt);
4681 AssertRCReturn(rc, rc);
4682
4683 /* Validate. */
4684 Assert(!(pMixedCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
4685
4686 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_IDTR);
4687 Log4(("Load[%RU32]: VMX_VMCS_GUEST_IDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->idtr.pIdt));
4688 }
4689
4690 return VINF_SUCCESS;
4691}
4692
4693
4694/**
4695 * Loads certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
4696 * areas.
4697 *
4698 * These MSRs will automatically be loaded to the host CPU on every successful
4699 * VM-entry and stored from the host CPU on every successful VM-exit. This also
4700 * creates/updates MSR slots for the host MSRs. The actual host MSR values are
4701 * -not- updated here for performance reasons. See hmR0VmxSaveHostMsrs().
4702 *
4703 * Also loads the sysenter MSRs into the guest-state area in the VMCS.
4704 *
4705 * @returns VBox status code.
4706 * @param pVCpu The cross context virtual CPU structure.
4707 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4708 * out-of-sync. Make sure to update the required fields
4709 * before using them.
4710 *
4711 * @remarks No-long-jump zone!!!
4712 */
4713static int hmR0VmxLoadGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4714{
4715 AssertPtr(pVCpu);
4716 AssertPtr(pVCpu->hm.s.vmx.pvGuestMsr);
4717
4718 /*
4719 * MSRs that we use the auto-load/store MSR area in the VMCS.
4720 */
4721 PVM pVM = pVCpu->CTX_SUFF(pVM);
4722 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS))
4723 {
4724 /* For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(). */
4725#if HC_ARCH_BITS == 32
4726 if (pVM->hm.s.fAllow64BitGuests)
4727 {
4728 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_LSTAR, pMixedCtx->msrLSTAR, false, NULL);
4729 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K6_STAR, pMixedCtx->msrSTAR, false, NULL);
4730 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_SF_MASK, pMixedCtx->msrSFMASK, false, NULL);
4731 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_KERNEL_GS_BASE, pMixedCtx->msrKERNELGSBASE, false, NULL);
4732 AssertRCReturn(rc, rc);
4733# ifdef LOG_ENABLED
4734 PVMXAUTOMSR pMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
4735 for (uint32_t i = 0; i < pVCpu->hm.s.vmx.cMsrs; i++, pMsr++)
4736 {
4737 Log4(("Load[%RU32]: MSR[%RU32]: u32Msr=%#RX32 u64Value=%#RX64\n", pVCpu->idCpu, i, pMsr->u32Msr,
4738 pMsr->u64Value));
4739 }
4740# endif
4741 }
4742#endif
4743 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
4744 }
4745
4746 /*
4747 * Guest Sysenter MSRs.
4748 * These flags are only set when MSR-bitmaps are not supported by the CPU and we cause
4749 * VM-exits on WRMSRs for these MSRs.
4750 */
4751 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR))
4752 {
4753 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pMixedCtx->SysEnter.cs); AssertRCReturn(rc, rc);
4754 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR);
4755 }
4756
4757 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR))
4758 {
4759 int rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, pMixedCtx->SysEnter.eip); AssertRCReturn(rc, rc);
4760 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
4761 }
4762
4763 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR))
4764 {
4765 int rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, pMixedCtx->SysEnter.esp); AssertRCReturn(rc, rc);
4766 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
4767 }
4768
4769 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_EFER_MSR))
4770 {
4771 if (hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
4772 {
4773 /*
4774 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
4775 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
4776 */
4777 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
4778 {
4779 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pMixedCtx->msrEFER);
4780 AssertRCReturn(rc,rc);
4781 Log4(("Load[%RU32]: VMX_VMCS64_GUEST_EFER_FULL=%#RX64\n", pVCpu->idCpu, pMixedCtx->msrEFER));
4782 }
4783 else
4784 {
4785 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K6_EFER, pMixedCtx->msrEFER, false /* fUpdateHostMsr */,
4786 NULL /* pfAddedAndUpdated */);
4787 AssertRCReturn(rc, rc);
4788
4789 /* We need to intercept reads too, see @bugref{7386#c16}. */
4790 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
4791 hmR0VmxSetMsrPermission(pVCpu, MSR_K6_EFER, VMXMSREXIT_INTERCEPT_READ, VMXMSREXIT_INTERCEPT_WRITE);
4792 Log4(("Load[%RU32]: MSR[--]: u32Msr=%#RX32 u64Value=%#RX64 cMsrs=%u\n", pVCpu->idCpu, MSR_K6_EFER,
4793 pMixedCtx->msrEFER, pVCpu->hm.s.vmx.cMsrs));
4794 }
4795 }
4796 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
4797 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, MSR_K6_EFER);
4798 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_EFER_MSR);
4799 }
4800
4801 return VINF_SUCCESS;
4802}
4803
4804
4805/**
4806 * Loads the guest activity state into the guest-state area in the VMCS.
4807 *
4808 * @returns VBox status code.
4809 * @param pVCpu The cross context virtual CPU structure.
4810 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4811 * out-of-sync. Make sure to update the required fields
4812 * before using them.
4813 *
4814 * @remarks No-long-jump zone!!!
4815 */
4816static int hmR0VmxLoadGuestActivityState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4817{
4818 NOREF(pMixedCtx);
4819 /** @todo See if we can make use of other states, e.g.
4820 * VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN or HLT. */
4821 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_ACTIVITY_STATE))
4822 {
4823 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, VMX_VMCS_GUEST_ACTIVITY_ACTIVE);
4824 AssertRCReturn(rc, rc);
4825
4826 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_ACTIVITY_STATE);
4827 }
4828 return VINF_SUCCESS;
4829}
4830
4831
4832#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
4833/**
4834 * Check if guest state allows safe use of 32-bit switcher again.
4835 *
4836 * Segment bases and protected mode structures must be 32-bit addressable
4837 * because the 32-bit switcher will ignore high dword when writing these VMCS
4838 * fields. See @bugref{8432} for details.
4839 *
4840 * @returns true if safe, false if must continue to use the 64-bit switcher.
4841 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4842 * out-of-sync. Make sure to update the required fields
4843 * before using them.
4844 *
4845 * @remarks No-long-jump zone!!!
4846 */
4847static bool hmR0VmxIs32BitSwitcherSafe(PCPUMCTX pMixedCtx)
4848{
4849 if (pMixedCtx->gdtr.pGdt & UINT64_C(0xffffffff00000000))
4850 return false;
4851 if (pMixedCtx->idtr.pIdt & UINT64_C(0xffffffff00000000))
4852 return false;
4853 if (pMixedCtx->ldtr.u64Base & UINT64_C(0xffffffff00000000))
4854 return false;
4855 if (pMixedCtx->tr.u64Base & UINT64_C(0xffffffff00000000))
4856 return false;
4857 if (pMixedCtx->es.u64Base & UINT64_C(0xffffffff00000000))
4858 return false;
4859 if (pMixedCtx->cs.u64Base & UINT64_C(0xffffffff00000000))
4860 return false;
4861 if (pMixedCtx->ss.u64Base & UINT64_C(0xffffffff00000000))
4862 return false;
4863 if (pMixedCtx->ds.u64Base & UINT64_C(0xffffffff00000000))
4864 return false;
4865 if (pMixedCtx->fs.u64Base & UINT64_C(0xffffffff00000000))
4866 return false;
4867 if (pMixedCtx->gs.u64Base & UINT64_C(0xffffffff00000000))
4868 return false;
4869 /* All good, bases are 32-bit. */
4870 return true;
4871}
4872#endif
4873
4874
4875/**
4876 * Sets up the appropriate function to run guest code.
4877 *
4878 * @returns VBox status code.
4879 * @param pVCpu The cross context virtual CPU structure.
4880 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4881 * out-of-sync. Make sure to update the required fields
4882 * before using them.
4883 *
4884 * @remarks No-long-jump zone!!!
4885 */
4886static int hmR0VmxSetupVMRunHandler(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4887{
4888 if (CPUMIsGuestInLongModeEx(pMixedCtx))
4889 {
4890#ifndef VBOX_ENABLE_64_BITS_GUESTS
4891 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
4892#endif
4893 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
4894#if HC_ARCH_BITS == 32
4895 /* 32-bit host. We need to switch to 64-bit before running the 64-bit guest. */
4896 if (pVCpu->hm.s.vmx.pfnStartVM != VMXR0SwitcherStartVM64)
4897 {
4898 if (pVCpu->hm.s.vmx.pfnStartVM != NULL) /* Very first entry would have saved host-state already, ignore it. */
4899 {
4900 /* Currently, all mode changes sends us back to ring-3, so these should be set. See @bugref{6944}. */
4901 AssertMsg(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_VMX_EXIT_CTLS
4902 | HM_CHANGED_VMX_ENTRY_CTLS
4903 | HM_CHANGED_GUEST_EFER_MSR), ("flags=%#x\n", HMCPU_CF_VALUE(pVCpu)));
4904 }
4905 pVCpu->hm.s.vmx.pfnStartVM = VMXR0SwitcherStartVM64;
4906
4907 /* Mark that we've switched to 64-bit handler, we can't safely switch back to 32-bit for
4908 the rest of the VM run (until VM reset). See @bugref{8432#c7}. */
4909 pVCpu->hm.s.vmx.fSwitchedTo64on32 = true;
4910 Log4(("Load[%RU32]: hmR0VmxSetupVMRunHandler: selected 64-bit switcher\n", pVCpu->idCpu));
4911 }
4912#else
4913 /* 64-bit host. */
4914 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM64;
4915#endif
4916 }
4917 else
4918 {
4919 /* Guest is not in long mode, use the 32-bit handler. */
4920#if HC_ARCH_BITS == 32
4921 if ( pVCpu->hm.s.vmx.pfnStartVM != VMXR0StartVM32
4922 && !pVCpu->hm.s.vmx.fSwitchedTo64on32 /* If set, guest mode change does not imply switcher change. */
4923 && pVCpu->hm.s.vmx.pfnStartVM != NULL) /* Very first entry would have saved host-state already, ignore it. */
4924 {
4925 /* Currently, all mode changes sends us back to ring-3, so these should be set. See @bugref{6944}. */
4926 AssertMsg(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_VMX_EXIT_CTLS
4927 | HM_CHANGED_VMX_ENTRY_CTLS
4928 | HM_CHANGED_GUEST_EFER_MSR), ("flags=%#x\n", HMCPU_CF_VALUE(pVCpu)));
4929 }
4930# ifdef VBOX_ENABLE_64_BITS_GUESTS
4931 /*
4932 * Keep using the 64-bit switcher even though we're in 32-bit because of bad Intel design, see @bugref{8432#c7}.
4933 * If real-on-v86 mode is active, clear the 64-bit switcher flag because now we know the guest is in a sane
4934 * state where it's safe to use the 32-bit switcher. Otherwise check the guest state if it's safe to use
4935 * the much faster 32-bit switcher again.
4936 */
4937 if (!pVCpu->hm.s.vmx.fSwitchedTo64on32)
4938 {
4939 if (pVCpu->hm.s.vmx.pfnStartVM != VMXR0StartVM32)
4940 Log4(("Load[%RU32]: hmR0VmxSetupVMRunHandler: selected 32-bit switcher\n", pVCpu->idCpu));
4941 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4942 }
4943 else
4944 {
4945 Assert(pVCpu->hm.s.vmx.pfnStartVM == VMXR0SwitcherStartVM64);
4946 if ( pVCpu->hm.s.vmx.RealMode.fRealOnV86Active
4947 || hmR0VmxIs32BitSwitcherSafe(pMixedCtx))
4948 {
4949 pVCpu->hm.s.vmx.fSwitchedTo64on32 = false;
4950 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4951 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_EFER_MSR
4952 | HM_CHANGED_VMX_ENTRY_CTLS
4953 | HM_CHANGED_VMX_EXIT_CTLS
4954 | HM_CHANGED_HOST_CONTEXT);
4955 Log4(("Load[%RU32]: hmR0VmxSetupVMRunHandler: selected 32-bit switcher (safe)\n", pVCpu->idCpu));
4956 }
4957 }
4958# else
4959 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4960# endif
4961#else
4962 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4963#endif
4964 }
4965 Assert(pVCpu->hm.s.vmx.pfnStartVM);
4966 return VINF_SUCCESS;
4967}
4968
4969
4970/**
4971 * Wrapper for running the guest code in VT-x.
4972 *
4973 * @returns VBox status code, no informational status codes.
4974 * @param pVM The cross context VM structure.
4975 * @param pVCpu The cross context virtual CPU structure.
4976 * @param pCtx Pointer to the guest-CPU context.
4977 *
4978 * @remarks No-long-jump zone!!!
4979 */
4980DECLINLINE(int) hmR0VmxRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
4981{
4982 /*
4983 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses floating-point operations
4984 * using SSE instructions. Some XMM registers (XMM6-XMM15) are callee-saved and thus the need for this XMM wrapper.
4985 * Refer MSDN docs. "Configuring Programs for 64-bit / x64 Software Conventions / Register Usage" for details.
4986 */
4987 bool const fResumeVM = RT_BOOL(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_LAUNCHED);
4988 /** @todo Add stats for resume vs launch. */
4989#ifdef VBOX_WITH_KERNEL_USING_XMM
4990 int rc = HMR0VMXStartVMWrapXMM(fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu, pVCpu->hm.s.vmx.pfnStartVM);
4991#else
4992 int rc = pVCpu->hm.s.vmx.pfnStartVM(fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu);
4993#endif
4994 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
4995 return rc;
4996}
4997
4998
4999/**
5000 * Reports world-switch error and dumps some useful debug info.
5001 *
5002 * @param pVM The cross context VM structure.
5003 * @param pVCpu The cross context virtual CPU structure.
5004 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
5005 * @param pCtx Pointer to the guest-CPU context.
5006 * @param pVmxTransient Pointer to the VMX transient structure (only
5007 * exitReason updated).
5008 */
5009static void hmR0VmxReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, int rcVMRun, PCPUMCTX pCtx, PVMXTRANSIENT pVmxTransient)
5010{
5011 Assert(pVM);
5012 Assert(pVCpu);
5013 Assert(pCtx);
5014 Assert(pVmxTransient);
5015 HMVMX_ASSERT_PREEMPT_SAFE();
5016
5017 Log4(("VM-entry failure: %Rrc\n", rcVMRun));
5018 switch (rcVMRun)
5019 {
5020 case VERR_VMX_INVALID_VMXON_PTR:
5021 AssertFailed();
5022 break;
5023 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
5024 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
5025 {
5026 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
5027 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
5028 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
5029 AssertRC(rc);
5030
5031 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
5032 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
5033 Cannot do it here as we may have been long preempted. */
5034
5035#ifdef VBOX_STRICT
5036 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
5037 pVmxTransient->uExitReason));
5038 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQualification));
5039 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
5040 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
5041 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
5042 else
5043 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
5044 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
5045 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
5046
5047 /* VMX control bits. */
5048 uint32_t u32Val;
5049 uint64_t u64Val;
5050 RTHCUINTREG uHCReg;
5051 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val); AssertRC(rc);
5052 Log4(("VMX_VMCS32_CTRL_PIN_EXEC %#RX32\n", u32Val));
5053 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val); AssertRC(rc);
5054 Log4(("VMX_VMCS32_CTRL_PROC_EXEC %#RX32\n", u32Val));
5055 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
5056 {
5057 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val); AssertRC(rc);
5058 Log4(("VMX_VMCS32_CTRL_PROC_EXEC2 %#RX32\n", u32Val));
5059 }
5060 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val); AssertRC(rc);
5061 Log4(("VMX_VMCS32_CTRL_ENTRY %#RX32\n", u32Val));
5062 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val); AssertRC(rc);
5063 Log4(("VMX_VMCS32_CTRL_EXIT %#RX32\n", u32Val));
5064 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_CR3_TARGET_COUNT, &u32Val); AssertRC(rc);
5065 Log4(("VMX_VMCS32_CTRL_CR3_TARGET_COUNT %#RX32\n", u32Val));
5066 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32Val); AssertRC(rc);
5067 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", u32Val));
5068 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &u32Val); AssertRC(rc);
5069 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", u32Val));
5070 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &u32Val); AssertRC(rc);
5071 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %u\n", u32Val));
5072 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, &u32Val); AssertRC(rc);
5073 Log4(("VMX_VMCS32_CTRL_TPR_THRESHOLD %u\n", u32Val));
5074 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &u32Val); AssertRC(rc);
5075 Log4(("VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT %u (guest MSRs)\n", u32Val));
5076 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &u32Val); AssertRC(rc);
5077 Log4(("VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT %u (host MSRs)\n", u32Val));
5078 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &u32Val); AssertRC(rc);
5079 Log4(("VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT %u (guest MSRs)\n", u32Val));
5080 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val); AssertRC(rc);
5081 Log4(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP %#RX32\n", u32Val));
5082 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, &u32Val); AssertRC(rc);
5083 Log4(("VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK %#RX32\n", u32Val));
5084 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, &u32Val); AssertRC(rc);
5085 Log4(("VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH %#RX32\n", u32Val));
5086 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
5087 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
5088 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
5089 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
5090 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
5091 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
5092 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
5093 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
5094 if (pVM->hm.s.fNestedPaging)
5095 {
5096 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
5097 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
5098 }
5099
5100 /* Guest bits. */
5101 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RIP, &u64Val); AssertRC(rc);
5102 Log4(("Old Guest Rip %#RX64 New %#RX64\n", pCtx->rip, u64Val));
5103 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RSP, &u64Val); AssertRC(rc);
5104 Log4(("Old Guest Rsp %#RX64 New %#RX64\n", pCtx->rsp, u64Val));
5105 rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &u32Val); AssertRC(rc);
5106 Log4(("Old Guest Rflags %#RX32 New %#RX32\n", pCtx->eflags.u32, u32Val));
5107 if (pVM->hm.s.vmx.fVpid)
5108 {
5109 rc = VMXReadVmcs32(VMX_VMCS16_VPID, &u32Val); AssertRC(rc);
5110 Log4(("VMX_VMCS16_VPID %u\n", u32Val));
5111 }
5112
5113 /* Host bits. */
5114 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR0, &uHCReg); AssertRC(rc);
5115 Log4(("Host CR0 %#RHr\n", uHCReg));
5116 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR3, &uHCReg); AssertRC(rc);
5117 Log4(("Host CR3 %#RHr\n", uHCReg));
5118 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR4, &uHCReg); AssertRC(rc);
5119 Log4(("Host CR4 %#RHr\n", uHCReg));
5120
5121 RTGDTR HostGdtr;
5122 PCX86DESCHC pDesc;
5123 ASMGetGDTR(&HostGdtr);
5124 rc = VMXReadVmcs32(VMX_VMCS16_HOST_CS_SEL, &u32Val); AssertRC(rc);
5125 Log4(("Host CS %#08x\n", u32Val));
5126 if (u32Val < HostGdtr.cbGdt)
5127 {
5128 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5129 HMR0DumpDescriptor(pDesc, u32Val, "CS: ");
5130 }
5131
5132 rc = VMXReadVmcs32(VMX_VMCS16_HOST_DS_SEL, &u32Val); AssertRC(rc);
5133 Log4(("Host DS %#08x\n", u32Val));
5134 if (u32Val < HostGdtr.cbGdt)
5135 {
5136 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5137 HMR0DumpDescriptor(pDesc, u32Val, "DS: ");
5138 }
5139
5140 rc = VMXReadVmcs32(VMX_VMCS16_HOST_ES_SEL, &u32Val); AssertRC(rc);
5141 Log4(("Host ES %#08x\n", u32Val));
5142 if (u32Val < HostGdtr.cbGdt)
5143 {
5144 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5145 HMR0DumpDescriptor(pDesc, u32Val, "ES: ");
5146 }
5147
5148 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FS_SEL, &u32Val); AssertRC(rc);
5149 Log4(("Host FS %#08x\n", u32Val));
5150 if (u32Val < HostGdtr.cbGdt)
5151 {
5152 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5153 HMR0DumpDescriptor(pDesc, u32Val, "FS: ");
5154 }
5155
5156 rc = VMXReadVmcs32(VMX_VMCS16_HOST_GS_SEL, &u32Val); AssertRC(rc);
5157 Log4(("Host GS %#08x\n", u32Val));
5158 if (u32Val < HostGdtr.cbGdt)
5159 {
5160 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5161 HMR0DumpDescriptor(pDesc, u32Val, "GS: ");
5162 }
5163
5164 rc = VMXReadVmcs32(VMX_VMCS16_HOST_SS_SEL, &u32Val); AssertRC(rc);
5165 Log4(("Host SS %#08x\n", u32Val));
5166 if (u32Val < HostGdtr.cbGdt)
5167 {
5168 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5169 HMR0DumpDescriptor(pDesc, u32Val, "SS: ");
5170 }
5171
5172 rc = VMXReadVmcs32(VMX_VMCS16_HOST_TR_SEL, &u32Val); AssertRC(rc);
5173 Log4(("Host TR %#08x\n", u32Val));
5174 if (u32Val < HostGdtr.cbGdt)
5175 {
5176 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5177 HMR0DumpDescriptor(pDesc, u32Val, "TR: ");
5178 }
5179
5180 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_TR_BASE, &uHCReg); AssertRC(rc);
5181 Log4(("Host TR Base %#RHv\n", uHCReg));
5182 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_GDTR_BASE, &uHCReg); AssertRC(rc);
5183 Log4(("Host GDTR Base %#RHv\n", uHCReg));
5184 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_IDTR_BASE, &uHCReg); AssertRC(rc);
5185 Log4(("Host IDTR Base %#RHv\n", uHCReg));
5186 rc = VMXReadVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, &u32Val); AssertRC(rc);
5187 Log4(("Host SYSENTER CS %#08x\n", u32Val));
5188 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_SYSENTER_EIP, &uHCReg); AssertRC(rc);
5189 Log4(("Host SYSENTER EIP %#RHv\n", uHCReg));
5190 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_SYSENTER_ESP, &uHCReg); AssertRC(rc);
5191 Log4(("Host SYSENTER ESP %#RHv\n", uHCReg));
5192 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_RSP, &uHCReg); AssertRC(rc);
5193 Log4(("Host RSP %#RHv\n", uHCReg));
5194 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_RIP, &uHCReg); AssertRC(rc);
5195 Log4(("Host RIP %#RHv\n", uHCReg));
5196# if HC_ARCH_BITS == 64
5197 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
5198 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
5199 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
5200 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
5201 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
5202 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
5203# endif
5204#endif /* VBOX_STRICT */
5205 break;
5206 }
5207
5208 default:
5209 /* Impossible */
5210 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
5211 break;
5212 }
5213 NOREF(pVM); NOREF(pCtx);
5214}
5215
5216
5217#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
5218#ifndef VMX_USE_CACHED_VMCS_ACCESSES
5219# error "VMX_USE_CACHED_VMCS_ACCESSES not defined when it should be!"
5220#endif
5221#ifdef VBOX_STRICT
5222static bool hmR0VmxIsValidWriteField(uint32_t idxField)
5223{
5224 switch (idxField)
5225 {
5226 case VMX_VMCS_GUEST_RIP:
5227 case VMX_VMCS_GUEST_RSP:
5228 case VMX_VMCS_GUEST_SYSENTER_EIP:
5229 case VMX_VMCS_GUEST_SYSENTER_ESP:
5230 case VMX_VMCS_GUEST_GDTR_BASE:
5231 case VMX_VMCS_GUEST_IDTR_BASE:
5232 case VMX_VMCS_GUEST_CS_BASE:
5233 case VMX_VMCS_GUEST_DS_BASE:
5234 case VMX_VMCS_GUEST_ES_BASE:
5235 case VMX_VMCS_GUEST_FS_BASE:
5236 case VMX_VMCS_GUEST_GS_BASE:
5237 case VMX_VMCS_GUEST_SS_BASE:
5238 case VMX_VMCS_GUEST_LDTR_BASE:
5239 case VMX_VMCS_GUEST_TR_BASE:
5240 case VMX_VMCS_GUEST_CR3:
5241 return true;
5242 }
5243 return false;
5244}
5245
5246static bool hmR0VmxIsValidReadField(uint32_t idxField)
5247{
5248 switch (idxField)
5249 {
5250 /* Read-only fields. */
5251 case VMX_VMCS_RO_EXIT_QUALIFICATION:
5252 return true;
5253 }
5254 /* Remaining readable fields should also be writable. */
5255 return hmR0VmxIsValidWriteField(idxField);
5256}
5257#endif /* VBOX_STRICT */
5258
5259
5260/**
5261 * Executes the specified handler in 64-bit mode.
5262 *
5263 * @returns VBox status code (no informational status codes).
5264 * @param pVM The cross context VM structure.
5265 * @param pVCpu The cross context virtual CPU structure.
5266 * @param pCtx Pointer to the guest CPU context.
5267 * @param enmOp The operation to perform.
5268 * @param cParams Number of parameters.
5269 * @param paParam Array of 32-bit parameters.
5270 */
5271VMMR0DECL(int) VMXR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, HM64ON32OP enmOp,
5272 uint32_t cParams, uint32_t *paParam)
5273{
5274 NOREF(pCtx);
5275
5276 AssertReturn(pVM->hm.s.pfnHost32ToGuest64R0, VERR_HM_NO_32_TO_64_SWITCHER);
5277 Assert(enmOp > HM64ON32OP_INVALID && enmOp < HM64ON32OP_END);
5278 Assert(pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Write.aField));
5279 Assert(pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Read.aField));
5280
5281#ifdef VBOX_STRICT
5282 for (uint32_t i = 0; i < pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries; i++)
5283 Assert(hmR0VmxIsValidWriteField(pVCpu->hm.s.vmx.VMCSCache.Write.aField[i]));
5284
5285 for (uint32_t i = 0; i <pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries; i++)
5286 Assert(hmR0VmxIsValidReadField(pVCpu->hm.s.vmx.VMCSCache.Read.aField[i]));
5287#endif
5288
5289 /* Disable interrupts. */
5290 RTCCUINTREG fOldEFlags = ASMIntDisableFlags();
5291
5292#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
5293 RTCPUID idHostCpu = RTMpCpuId();
5294 CPUMR0SetLApic(pVCpu, idHostCpu);
5295#endif
5296
5297 PHMGLOBALCPUINFO pCpu = HMR0GetCurrentCpu();
5298 RTHCPHYS HCPhysCpuPage = pCpu->HCPhysMemObj;
5299
5300 /* Clear VMCS. Marking it inactive, clearing implementation-specific data and writing VMCS data back to memory. */
5301 VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
5302 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
5303
5304 /* Leave VMX Root Mode. */
5305 VMXDisable();
5306
5307 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
5308
5309 CPUMSetHyperESP(pVCpu, VMMGetStackRC(pVCpu));
5310 CPUMSetHyperEIP(pVCpu, enmOp);
5311 for (int i = (int)cParams - 1; i >= 0; i--)
5312 CPUMPushHyper(pVCpu, paParam[i]);
5313
5314 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatWorldSwitch3264, z);
5315
5316 /* Call the switcher. */
5317 int rc = pVM->hm.s.pfnHost32ToGuest64R0(pVM, RT_OFFSETOF(VM, aCpus[pVCpu->idCpu].cpum) - RT_OFFSETOF(VM, cpum));
5318 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatWorldSwitch3264, z);
5319
5320 /** @todo replace with hmR0VmxEnterRootMode() and hmR0VmxLeaveRootMode(). */
5321 /* Make sure the VMX instructions don't cause #UD faults. */
5322 SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
5323
5324 /* Re-enter VMX Root Mode */
5325 int rc2 = VMXEnable(HCPhysCpuPage);
5326 if (RT_FAILURE(rc2))
5327 {
5328 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
5329 ASMSetFlags(fOldEFlags);
5330 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
5331 return rc2;
5332 }
5333
5334 rc2 = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
5335 AssertRC(rc2);
5336 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
5337 Assert(!(ASMGetFlags() & X86_EFL_IF));
5338 ASMSetFlags(fOldEFlags);
5339 return rc;
5340}
5341
5342
5343/**
5344 * Prepares for and executes VMLAUNCH (64-bit guests) for 32-bit hosts
5345 * supporting 64-bit guests.
5346 *
5347 * @returns VBox status code.
5348 * @param fResume Whether to VMLAUNCH or VMRESUME.
5349 * @param pCtx Pointer to the guest-CPU context.
5350 * @param pCache Pointer to the VMCS cache.
5351 * @param pVM The cross context VM structure.
5352 * @param pVCpu The cross context virtual CPU structure.
5353 */
5354DECLASM(int) VMXR0SwitcherStartVM64(RTHCUINT fResume, PCPUMCTX pCtx, PVMCSCACHE pCache, PVM pVM, PVMCPU pVCpu)
5355{
5356 NOREF(fResume);
5357
5358 PHMGLOBALCPUINFO pCpu = HMR0GetCurrentCpu();
5359 RTHCPHYS HCPhysCpuPage = pCpu->HCPhysMemObj;
5360
5361#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5362 pCache->uPos = 1;
5363 pCache->interPD = PGMGetInterPaeCR3(pVM);
5364 pCache->pSwitcher = (uint64_t)pVM->hm.s.pfnHost32ToGuest64R0;
5365#endif
5366
5367#if defined(DEBUG) && defined(VMX_USE_CACHED_VMCS_ACCESSES)
5368 pCache->TestIn.HCPhysCpuPage = 0;
5369 pCache->TestIn.HCPhysVmcs = 0;
5370 pCache->TestIn.pCache = 0;
5371 pCache->TestOut.HCPhysVmcs = 0;
5372 pCache->TestOut.pCache = 0;
5373 pCache->TestOut.pCtx = 0;
5374 pCache->TestOut.eflags = 0;
5375#else
5376 NOREF(pCache);
5377#endif
5378
5379 uint32_t aParam[10];
5380 aParam[0] = (uint32_t)(HCPhysCpuPage); /* Param 1: VMXON physical address - Lo. */
5381 aParam[1] = (uint32_t)(HCPhysCpuPage >> 32); /* Param 1: VMXON physical address - Hi. */
5382 aParam[2] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs); /* Param 2: VMCS physical address - Lo. */
5383 aParam[3] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs >> 32); /* Param 2: VMCS physical address - Hi. */
5384 aParam[4] = VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache);
5385 aParam[5] = 0;
5386 aParam[6] = VM_RC_ADDR(pVM, pVM);
5387 aParam[7] = 0;
5388 aParam[8] = VM_RC_ADDR(pVM, pVCpu);
5389 aParam[9] = 0;
5390
5391#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5392 pCtx->dr[4] = pVM->hm.s.vmx.pScratchPhys + 16 + 8;
5393 *(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) = 1;
5394#endif
5395 int rc = VMXR0Execute64BitsHandler(pVM, pVCpu, pCtx, HM64ON32OP_VMXRCStartVM64, RT_ELEMENTS(aParam), &aParam[0]);
5396
5397#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5398 Assert(*(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) == 5);
5399 Assert(pCtx->dr[4] == 10);
5400 *(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) = 0xff;
5401#endif
5402
5403#if defined(DEBUG) && defined(VMX_USE_CACHED_VMCS_ACCESSES)
5404 AssertMsg(pCache->TestIn.HCPhysCpuPage == HCPhysCpuPage, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysCpuPage, HCPhysCpuPage));
5405 AssertMsg(pCache->TestIn.HCPhysVmcs == pVCpu->hm.s.vmx.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
5406 pVCpu->hm.s.vmx.HCPhysVmcs));
5407 AssertMsg(pCache->TestIn.HCPhysVmcs == pCache->TestOut.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
5408 pCache->TestOut.HCPhysVmcs));
5409 AssertMsg(pCache->TestIn.pCache == pCache->TestOut.pCache, ("%RGv vs %RGv\n", pCache->TestIn.pCache,
5410 pCache->TestOut.pCache));
5411 AssertMsg(pCache->TestIn.pCache == VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache),
5412 ("%RGv vs %RGv\n", pCache->TestIn.pCache, VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache)));
5413 AssertMsg(pCache->TestIn.pCtx == pCache->TestOut.pCtx, ("%RGv vs %RGv\n", pCache->TestIn.pCtx,
5414 pCache->TestOut.pCtx));
5415 Assert(!(pCache->TestOut.eflags & X86_EFL_IF));
5416#endif
5417 return rc;
5418}
5419
5420
5421/**
5422 * Initialize the VMCS-Read cache.
5423 *
5424 * The VMCS cache is used for 32-bit hosts running 64-bit guests (except 32-bit
5425 * Darwin which runs with 64-bit paging in 32-bit mode) for 64-bit fields that
5426 * cannot be accessed in 32-bit mode. Some 64-bit fields -can- be accessed
5427 * (those that have a 32-bit FULL & HIGH part).
5428 *
5429 * @returns VBox status code.
5430 * @param pVM The cross context VM structure.
5431 * @param pVCpu The cross context virtual CPU structure.
5432 */
5433static int hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu)
5434{
5435#define VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, idxField) \
5436{ \
5437 Assert(pCache->Read.aField[idxField##_CACHE_IDX] == 0); \
5438 pCache->Read.aField[idxField##_CACHE_IDX] = idxField; \
5439 pCache->Read.aFieldVal[idxField##_CACHE_IDX] = 0; \
5440 ++cReadFields; \
5441}
5442
5443 AssertPtr(pVM);
5444 AssertPtr(pVCpu);
5445 PVMCSCACHE pCache = &pVCpu->hm.s.vmx.VMCSCache;
5446 uint32_t cReadFields = 0;
5447
5448 /*
5449 * Don't remove the #if 0'd fields in this code. They're listed here for consistency
5450 * and serve to indicate exceptions to the rules.
5451 */
5452
5453 /* Guest-natural selector base fields. */
5454#if 0
5455 /* These are 32-bit in practice. See Intel spec. 2.5 "Control Registers". */
5456 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR0);
5457 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR4);
5458#endif
5459 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_ES_BASE);
5460 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CS_BASE);
5461 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SS_BASE);
5462 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_DS_BASE);
5463 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_FS_BASE);
5464 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_GS_BASE);
5465 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_LDTR_BASE);
5466 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_TR_BASE);
5467 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_GDTR_BASE);
5468 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_IDTR_BASE);
5469 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_RSP);
5470 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_RIP);
5471#if 0
5472 /* Unused natural width guest-state fields. */
5473 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS);
5474 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR3); /* Handled in Nested Paging case */
5475#endif
5476 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SYSENTER_ESP);
5477 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SYSENTER_EIP);
5478
5479 /* 64-bit guest-state fields; unused as we use two 32-bit VMREADs for these 64-bit fields (using "FULL" and "HIGH" fields). */
5480#if 0
5481 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL);
5482 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_DEBUGCTL_FULL);
5483 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PAT_FULL);
5484 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_EFER_FULL);
5485 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL);
5486 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE0_FULL);
5487 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE1_FULL);
5488 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE2_FULL);
5489 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE3_FULL);
5490#endif
5491
5492 /* Natural width guest-state fields. */
5493 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_RO_EXIT_QUALIFICATION);
5494#if 0
5495 /* Currently unused field. */
5496 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_RO_EXIT_GUEST_LINEAR_ADDR);
5497#endif
5498
5499 if (pVM->hm.s.fNestedPaging)
5500 {
5501 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR3);
5502 AssertMsg(cReadFields == VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields,
5503 VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX));
5504 pCache->Read.cValidEntries = VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX;
5505 }
5506 else
5507 {
5508 AssertMsg(cReadFields == VMX_VMCS_MAX_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields, VMX_VMCS_MAX_CACHE_IDX));
5509 pCache->Read.cValidEntries = VMX_VMCS_MAX_CACHE_IDX;
5510 }
5511
5512#undef VMXLOCAL_INIT_READ_CACHE_FIELD
5513 return VINF_SUCCESS;
5514}
5515
5516
5517/**
5518 * Writes a field into the VMCS. This can either directly invoke a VMWRITE or
5519 * queue up the VMWRITE by using the VMCS write cache (on 32-bit hosts, except
5520 * darwin, running 64-bit guests).
5521 *
5522 * @returns VBox status code.
5523 * @param pVCpu The cross context virtual CPU structure.
5524 * @param idxField The VMCS field encoding.
5525 * @param u64Val 16, 32 or 64-bit value.
5526 */
5527VMMR0DECL(int) VMXWriteVmcs64Ex(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
5528{
5529 int rc;
5530 switch (idxField)
5531 {
5532 /*
5533 * These fields consists of a "FULL" and a "HIGH" part which can be written to individually.
5534 */
5535 /* 64-bit Control fields. */
5536 case VMX_VMCS64_CTRL_IO_BITMAP_A_FULL:
5537 case VMX_VMCS64_CTRL_IO_BITMAP_B_FULL:
5538 case VMX_VMCS64_CTRL_MSR_BITMAP_FULL:
5539 case VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL:
5540 case VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL:
5541 case VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL:
5542 case VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL:
5543 case VMX_VMCS64_CTRL_TSC_OFFSET_FULL:
5544 case VMX_VMCS64_CTRL_VAPIC_PAGEADDR_FULL:
5545 case VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL:
5546 case VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL:
5547 case VMX_VMCS64_CTRL_EPTP_FULL:
5548 case VMX_VMCS64_CTRL_EPTP_LIST_FULL:
5549 /* 64-bit Guest-state fields. */
5550 case VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL:
5551 case VMX_VMCS64_GUEST_DEBUGCTL_FULL:
5552 case VMX_VMCS64_GUEST_PAT_FULL:
5553 case VMX_VMCS64_GUEST_EFER_FULL:
5554 case VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL:
5555 case VMX_VMCS64_GUEST_PDPTE0_FULL:
5556 case VMX_VMCS64_GUEST_PDPTE1_FULL:
5557 case VMX_VMCS64_GUEST_PDPTE2_FULL:
5558 case VMX_VMCS64_GUEST_PDPTE3_FULL:
5559 /* 64-bit Host-state fields. */
5560 case VMX_VMCS64_HOST_PAT_FULL:
5561 case VMX_VMCS64_HOST_EFER_FULL:
5562 case VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL:
5563 {
5564 rc = VMXWriteVmcs32(idxField, u64Val);
5565 rc |= VMXWriteVmcs32(idxField + 1, (uint32_t)(u64Val >> 32));
5566 break;
5567 }
5568
5569 /*
5570 * These fields do not have high and low parts. Queue up the VMWRITE by using the VMCS write-cache (for 64-bit
5571 * values). When we switch the host to 64-bit mode for running 64-bit guests, these VMWRITEs get executed then.
5572 */
5573 /* Natural-width Guest-state fields. */
5574 case VMX_VMCS_GUEST_CR3:
5575 case VMX_VMCS_GUEST_ES_BASE:
5576 case VMX_VMCS_GUEST_CS_BASE:
5577 case VMX_VMCS_GUEST_SS_BASE:
5578 case VMX_VMCS_GUEST_DS_BASE:
5579 case VMX_VMCS_GUEST_FS_BASE:
5580 case VMX_VMCS_GUEST_GS_BASE:
5581 case VMX_VMCS_GUEST_LDTR_BASE:
5582 case VMX_VMCS_GUEST_TR_BASE:
5583 case VMX_VMCS_GUEST_GDTR_BASE:
5584 case VMX_VMCS_GUEST_IDTR_BASE:
5585 case VMX_VMCS_GUEST_RSP:
5586 case VMX_VMCS_GUEST_RIP:
5587 case VMX_VMCS_GUEST_SYSENTER_ESP:
5588 case VMX_VMCS_GUEST_SYSENTER_EIP:
5589 {
5590 if (!(u64Val >> 32))
5591 {
5592 /* If this field is 64-bit, VT-x will zero out the top bits. */
5593 rc = VMXWriteVmcs32(idxField, (uint32_t)u64Val);
5594 }
5595 else
5596 {
5597 /* Assert that only the 32->64 switcher case should ever come here. */
5598 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests);
5599 rc = VMXWriteCachedVmcsEx(pVCpu, idxField, u64Val);
5600 }
5601 break;
5602 }
5603
5604 default:
5605 {
5606 AssertMsgFailed(("VMXWriteVmcs64Ex: Invalid field %#RX32 (pVCpu=%p u64Val=%#RX64)\n", idxField, pVCpu, u64Val));
5607 rc = VERR_INVALID_PARAMETER;
5608 break;
5609 }
5610 }
5611 AssertRCReturn(rc, rc);
5612 return rc;
5613}
5614
5615
5616/**
5617 * Queue up a VMWRITE by using the VMCS write cache.
5618 * This is only used on 32-bit hosts (except darwin) for 64-bit guests.
5619 *
5620 * @param pVCpu The cross context virtual CPU structure.
5621 * @param idxField The VMCS field encoding.
5622 * @param u64Val 16, 32 or 64-bit value.
5623 */
5624VMMR0DECL(int) VMXWriteCachedVmcsEx(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
5625{
5626 AssertPtr(pVCpu);
5627 PVMCSCACHE pCache = &pVCpu->hm.s.vmx.VMCSCache;
5628
5629 AssertMsgReturn(pCache->Write.cValidEntries < VMCSCACHE_MAX_ENTRY - 1,
5630 ("entries=%u\n", pCache->Write.cValidEntries), VERR_ACCESS_DENIED);
5631
5632 /* Make sure there are no duplicates. */
5633 for (uint32_t i = 0; i < pCache->Write.cValidEntries; i++)
5634 {
5635 if (pCache->Write.aField[i] == idxField)
5636 {
5637 pCache->Write.aFieldVal[i] = u64Val;
5638 return VINF_SUCCESS;
5639 }
5640 }
5641
5642 pCache->Write.aField[pCache->Write.cValidEntries] = idxField;
5643 pCache->Write.aFieldVal[pCache->Write.cValidEntries] = u64Val;
5644 pCache->Write.cValidEntries++;
5645 return VINF_SUCCESS;
5646}
5647#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) */
5648
5649
5650/**
5651 * Sets up the usage of TSC-offsetting and updates the VMCS.
5652 *
5653 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
5654 * VMX preemption timer.
5655 *
5656 * @returns VBox status code.
5657 * @param pVM The cross context VM structure.
5658 * @param pVCpu The cross context virtual CPU structure.
5659 *
5660 * @remarks No-long-jump zone!!!
5661 */
5662static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVM pVM, PVMCPU pVCpu)
5663{
5664 int rc;
5665 bool fOffsettedTsc;
5666 bool fParavirtTsc;
5667 if (pVM->hm.s.vmx.fUsePreemptTimer)
5668 {
5669 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset,
5670 &fOffsettedTsc, &fParavirtTsc);
5671
5672 /* Make sure the returned values have sane upper and lower boundaries. */
5673 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
5674 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
5675 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
5676 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
5677
5678 uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
5679 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_PREEMPT_TIMER_VALUE, cPreemptionTickCount); AssertRC(rc);
5680 }
5681 else
5682 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset, &fParavirtTsc);
5683
5684 /** @todo later optimize this to be done elsewhere and not before every
5685 * VM-entry. */
5686 if (fParavirtTsc)
5687 {
5688 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
5689 information before every VM-entry, hence disable it for performance sake. */
5690#if 0
5691 rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
5692 AssertRC(rc);
5693#endif
5694 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
5695 }
5696
5697 if (fOffsettedTsc && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
5698 {
5699 /* Note: VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT takes precedence over TSC_OFFSET, applies to RDTSCP too. */
5700 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, pVCpu->hm.s.vmx.u64TSCOffset); AssertRC(rc);
5701
5702 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
5703 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
5704 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
5705 }
5706 else
5707 {
5708 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
5709 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
5710 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
5711 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
5712 }
5713}
5714
5715
5716/**
5717 * Determines if an exception is a contributory exception.
5718 *
5719 * Contributory exceptions are ones which can cause double-faults unless the
5720 * original exception was a benign exception. Page-fault is intentionally not
5721 * included here as it's a conditional contributory exception.
5722 *
5723 * @returns true if the exception is contributory, false otherwise.
5724 * @param uVector The exception vector.
5725 */
5726DECLINLINE(bool) hmR0VmxIsContributoryXcpt(const uint32_t uVector)
5727{
5728 switch (uVector)
5729 {
5730 case X86_XCPT_GP:
5731 case X86_XCPT_SS:
5732 case X86_XCPT_NP:
5733 case X86_XCPT_TS:
5734 case X86_XCPT_DE:
5735 return true;
5736 default:
5737 break;
5738 }
5739 return false;
5740}
5741
5742
5743/**
5744 * Sets an event as a pending event to be injected into the guest.
5745 *
5746 * @param pVCpu The cross context virtual CPU structure.
5747 * @param u32IntInfo The VM-entry interruption-information field.
5748 * @param cbInstr The VM-entry instruction length in bytes (for software
5749 * interrupts, exceptions and privileged software
5750 * exceptions).
5751 * @param u32ErrCode The VM-entry exception error code.
5752 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
5753 * page-fault.
5754 *
5755 * @remarks Statistics counter assumes this is a guest event being injected or
5756 * re-injected into the guest, i.e. 'StatInjectPendingReflect' is
5757 * always incremented.
5758 */
5759DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
5760 RTGCUINTPTR GCPtrFaultAddress)
5761{
5762 Assert(!pVCpu->hm.s.Event.fPending);
5763 pVCpu->hm.s.Event.fPending = true;
5764 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
5765 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
5766 pVCpu->hm.s.Event.cbInstr = cbInstr;
5767 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
5768}
5769
5770
5771/**
5772 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
5773 *
5774 * @param pVCpu The cross context virtual CPU structure.
5775 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5776 * out-of-sync. Make sure to update the required fields
5777 * before using them.
5778 */
5779DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5780{
5781 NOREF(pMixedCtx);
5782 uint32_t u32IntInfo = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
5783 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
5784 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
5785 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
5786}
5787
5788
5789/**
5790 * Handle a condition that occurred while delivering an event through the guest
5791 * IDT.
5792 *
5793 * @returns Strict VBox status code (i.e. informational status codes too).
5794 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
5795 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
5796 * to continue execution of the guest which will delivery the \#DF.
5797 * @retval VINF_EM_RESET if we detected a triple-fault condition.
5798 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
5799 *
5800 * @param pVCpu The cross context virtual CPU structure.
5801 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5802 * out-of-sync. Make sure to update the required fields
5803 * before using them.
5804 * @param pVmxTransient Pointer to the VMX transient structure.
5805 *
5806 * @remarks No-long-jump zone!!!
5807 */
5808static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
5809{
5810 uint32_t uExitVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
5811
5812 int rc2 = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient); AssertRCReturn(rc2, rc2);
5813 rc2 = hmR0VmxReadExitIntInfoVmcs(pVmxTransient); AssertRCReturn(rc2, rc2);
5814
5815 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
5816 if (VMX_IDT_VECTORING_INFO_VALID(pVmxTransient->uIdtVectoringInfo))
5817 {
5818 uint32_t uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
5819 uint32_t uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
5820
5821 typedef enum
5822 {
5823 VMXREFLECTXCPT_XCPT, /* Reflect the exception to the guest or for further evaluation by VMM. */
5824 VMXREFLECTXCPT_DF, /* Reflect the exception as a double-fault to the guest. */
5825 VMXREFLECTXCPT_TF, /* Indicate a triple faulted state to the VMM. */
5826 VMXREFLECTXCPT_HANG, /* Indicate bad VM trying to deadlock the CPU. */
5827 VMXREFLECTXCPT_NONE /* Nothing to reflect. */
5828 } VMXREFLECTXCPT;
5829
5830 /* See Intel spec. 30.7.1.1 "Reflecting Exceptions to Guest Software". */
5831 VMXREFLECTXCPT enmReflect = VMXREFLECTXCPT_NONE;
5832 if (VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo))
5833 {
5834 if (uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT)
5835 {
5836 enmReflect = VMXREFLECTXCPT_XCPT;
5837#ifdef VBOX_STRICT
5838 if ( hmR0VmxIsContributoryXcpt(uIdtVector)
5839 && uExitVector == X86_XCPT_PF)
5840 {
5841 Log4(("IDT: vcpu[%RU32] Contributory #PF uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
5842 }
5843#endif
5844 if ( uExitVector == X86_XCPT_PF
5845 && uIdtVector == X86_XCPT_PF)
5846 {
5847 pVmxTransient->fVectoringDoublePF = true;
5848 Log4(("IDT: vcpu[%RU32] Vectoring Double #PF uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
5849 }
5850 else if ( uExitVector == X86_XCPT_AC
5851 && uIdtVector == X86_XCPT_AC)
5852 {
5853 enmReflect = VMXREFLECTXCPT_HANG;
5854 Log4(("IDT: Nested #AC - Bad guest\n"));
5855 }
5856 else if ( (pVCpu->hm.s.vmx.u32XcptBitmap & HMVMX_CONTRIBUTORY_XCPT_MASK)
5857 && hmR0VmxIsContributoryXcpt(uExitVector)
5858 && ( hmR0VmxIsContributoryXcpt(uIdtVector)
5859 || uIdtVector == X86_XCPT_PF))
5860 {
5861 enmReflect = VMXREFLECTXCPT_DF;
5862 }
5863 else if (uIdtVector == X86_XCPT_DF)
5864 enmReflect = VMXREFLECTXCPT_TF;
5865 }
5866 else if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT
5867 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI)
5868 {
5869 /*
5870 * Ignore software interrupts (INT n), software exceptions (#BP, #OF) and
5871 * privileged software exception (#DB from ICEBP) as they reoccur when restarting the instruction.
5872 */
5873 enmReflect = VMXREFLECTXCPT_XCPT;
5874
5875 if (uExitVector == X86_XCPT_PF)
5876 {
5877 pVmxTransient->fVectoringPF = true;
5878 Log4(("IDT: vcpu[%RU32] Vectoring #PF due to Ext-Int/NMI. uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
5879 }
5880 }
5881 }
5882 else if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
5883 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT
5884 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI)
5885 {
5886 /*
5887 * If event delivery caused an EPT violation/misconfig or APIC access VM-exit, then the VM-exit
5888 * interruption-information will not be valid as it's not an exception and we end up here. In such cases,
5889 * it is sufficient to reflect the original exception to the guest after handling the VM-exit.
5890 */
5891 enmReflect = VMXREFLECTXCPT_XCPT;
5892 }
5893
5894 /*
5895 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig etc.) occurred
5896 * while delivering the NMI, we need to clear the block-by-NMI field in the guest interruptibility-state before
5897 * re-delivering the NMI after handling the VM-exit. Otherwise the subsequent VM-entry would fail.
5898 *
5899 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception". See @bugref{7445}.
5900 */
5901 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
5902 && enmReflect == VMXREFLECTXCPT_XCPT
5903 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
5904 && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
5905 {
5906 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
5907 }
5908
5909 switch (enmReflect)
5910 {
5911 case VMXREFLECTXCPT_XCPT:
5912 {
5913 Assert( uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT
5914 && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
5915 && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT);
5916
5917 uint32_t u32ErrCode = 0;
5918 if (VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo))
5919 {
5920 rc2 = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
5921 AssertRCReturn(rc2, rc2);
5922 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
5923 }
5924
5925 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF. See hmR0VmxExitXcptPF(). */
5926 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
5927 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
5928 0 /* cbInstr */, u32ErrCode, pMixedCtx->cr2);
5929 rcStrict = VINF_SUCCESS;
5930 Log4(("IDT: vcpu[%RU32] Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->idCpu,
5931 pVCpu->hm.s.Event.u64IntInfo, pVCpu->hm.s.Event.u32ErrCode));
5932
5933 break;
5934 }
5935
5936 case VMXREFLECTXCPT_DF:
5937 {
5938 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
5939 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
5940 rcStrict = VINF_HM_DOUBLE_FAULT;
5941 Log4(("IDT: vcpu[%RU32] Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->idCpu,
5942 pVCpu->hm.s.Event.u64IntInfo, uIdtVector, uExitVector));
5943
5944 break;
5945 }
5946
5947 case VMXREFLECTXCPT_TF:
5948 {
5949 rcStrict = VINF_EM_RESET;
5950 Log4(("IDT: vcpu[%RU32] Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", pVCpu->idCpu, uIdtVector,
5951 uExitVector));
5952 break;
5953 }
5954
5955 case VMXREFLECTXCPT_HANG:
5956 {
5957 rcStrict = VERR_EM_GUEST_CPU_HANG;
5958 break;
5959 }
5960
5961 default:
5962 Assert(rcStrict == VINF_SUCCESS);
5963 break;
5964 }
5965 }
5966 else if ( VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo)
5967 && VMX_EXIT_INTERRUPTION_INFO_NMI_UNBLOCK_IRET(pVmxTransient->uExitIntInfo)
5968 && uExitVector != X86_XCPT_DF
5969 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
5970 {
5971 /*
5972 * Execution of IRET caused this fault when NMI blocking was in effect (i.e we're in the guest NMI handler).
5973 * We need to set the block-by-NMI field so that NMIs remain blocked until the IRET execution is restarted.
5974 * See Intel spec. 30.7.1.2 "Resuming guest software after handling an exception".
5975 */
5976 if (!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
5977 {
5978 Log4(("hmR0VmxCheckExitDueToEventDelivery: vcpu[%RU32] Setting VMCPU_FF_BLOCK_NMIS. Valid=%RTbool uExitReason=%u\n",
5979 pVCpu->idCpu, VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo), pVmxTransient->uExitReason));
5980 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
5981 }
5982 }
5983
5984 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
5985 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
5986 return rcStrict;
5987}
5988
5989
5990/**
5991 * Saves the guest's CR0 register from the VMCS into the guest-CPU context.
5992 *
5993 * @returns VBox status code.
5994 * @param pVCpu The cross context virtual CPU structure.
5995 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5996 * out-of-sync. Make sure to update the required fields
5997 * before using them.
5998 *
5999 * @remarks No-long-jump zone!!!
6000 */
6001static int hmR0VmxSaveGuestCR0(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6002{
6003 NOREF(pMixedCtx);
6004
6005 /*
6006 * While in the middle of saving guest-CR0, we could get preempted and re-invoked from the preemption hook,
6007 * see hmR0VmxLeave(). Safer to just make this code non-preemptible.
6008 */
6009 VMMRZCallRing3Disable(pVCpu);
6010 HM_DISABLE_PREEMPT();
6011
6012 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0))
6013 {
6014 uint32_t uVal = 0;
6015 uint32_t uShadow = 0;
6016 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &uVal);
6017 rc |= VMXReadVmcs32(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uShadow);
6018 AssertRCReturn(rc, rc);
6019
6020 uVal = (uShadow & pVCpu->hm.s.vmx.u32CR0Mask) | (uVal & ~pVCpu->hm.s.vmx.u32CR0Mask);
6021 CPUMSetGuestCR0(pVCpu, uVal);
6022 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0);
6023 }
6024
6025 HM_RESTORE_PREEMPT();
6026 VMMRZCallRing3Enable(pVCpu);
6027 return VINF_SUCCESS;
6028}
6029
6030
6031/**
6032 * Saves the guest's CR4 register from the VMCS into the guest-CPU context.
6033 *
6034 * @returns VBox status code.
6035 * @param pVCpu The cross context virtual CPU structure.
6036 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6037 * out-of-sync. Make sure to update the required fields
6038 * before using them.
6039 *
6040 * @remarks No-long-jump zone!!!
6041 */
6042static int hmR0VmxSaveGuestCR4(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6043{
6044 NOREF(pMixedCtx);
6045
6046 int rc = VINF_SUCCESS;
6047 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4))
6048 {
6049 uint32_t uVal = 0;
6050 uint32_t uShadow = 0;
6051 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &uVal);
6052 rc |= VMXReadVmcs32(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uShadow);
6053 AssertRCReturn(rc, rc);
6054
6055 uVal = (uShadow & pVCpu->hm.s.vmx.u32CR4Mask) | (uVal & ~pVCpu->hm.s.vmx.u32CR4Mask);
6056 CPUMSetGuestCR4(pVCpu, uVal);
6057 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4);
6058 }
6059 return rc;
6060}
6061
6062
6063/**
6064 * Saves the guest's RIP register from the VMCS into the guest-CPU context.
6065 *
6066 * @returns VBox status code.
6067 * @param pVCpu The cross context virtual CPU structure.
6068 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6069 * out-of-sync. Make sure to update the required fields
6070 * before using them.
6071 *
6072 * @remarks No-long-jump zone!!!
6073 */
6074static int hmR0VmxSaveGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6075{
6076 int rc = VINF_SUCCESS;
6077 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP))
6078 {
6079 uint64_t u64Val = 0;
6080 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RIP, &u64Val);
6081 AssertRCReturn(rc, rc);
6082
6083 pMixedCtx->rip = u64Val;
6084 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP);
6085 }
6086 return rc;
6087}
6088
6089
6090/**
6091 * Saves the guest's RSP register from the VMCS into the guest-CPU context.
6092 *
6093 * @returns VBox status code.
6094 * @param pVCpu The cross context virtual CPU structure.
6095 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6096 * out-of-sync. Make sure to update the required fields
6097 * before using them.
6098 *
6099 * @remarks No-long-jump zone!!!
6100 */
6101static int hmR0VmxSaveGuestRsp(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6102{
6103 int rc = VINF_SUCCESS;
6104 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RSP))
6105 {
6106 uint64_t u64Val = 0;
6107 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RSP, &u64Val);
6108 AssertRCReturn(rc, rc);
6109
6110 pMixedCtx->rsp = u64Val;
6111 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RSP);
6112 }
6113 return rc;
6114}
6115
6116
6117/**
6118 * Saves the guest's RFLAGS from the VMCS into the guest-CPU context.
6119 *
6120 * @returns VBox status code.
6121 * @param pVCpu The cross context virtual CPU structure.
6122 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6123 * out-of-sync. Make sure to update the required fields
6124 * before using them.
6125 *
6126 * @remarks No-long-jump zone!!!
6127 */
6128static int hmR0VmxSaveGuestRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6129{
6130 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS))
6131 {
6132 uint32_t uVal = 0;
6133 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &uVal);
6134 AssertRCReturn(rc, rc);
6135
6136 pMixedCtx->eflags.u32 = uVal;
6137 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active) /* Undo our real-on-v86-mode changes to eflags if necessary. */
6138 {
6139 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6140 Log4(("Saving real-mode EFLAGS VT-x view=%#RX32\n", pMixedCtx->eflags.u32));
6141
6142 pMixedCtx->eflags.Bits.u1VM = 0;
6143 pMixedCtx->eflags.Bits.u2IOPL = pVCpu->hm.s.vmx.RealMode.Eflags.Bits.u2IOPL;
6144 }
6145
6146 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS);
6147 }
6148 return VINF_SUCCESS;
6149}
6150
6151
6152/**
6153 * Wrapper for saving the guest's RIP, RSP and RFLAGS from the VMCS into the
6154 * guest-CPU context.
6155 */
6156DECLINLINE(int) hmR0VmxSaveGuestRipRspRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6157{
6158 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6159 rc |= hmR0VmxSaveGuestRsp(pVCpu, pMixedCtx);
6160 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
6161 return rc;
6162}
6163
6164
6165/**
6166 * Saves the guest's interruptibility-state ("interrupt shadow" as AMD calls it)
6167 * from the guest-state area in the VMCS.
6168 *
6169 * @param pVCpu The cross context virtual CPU structure.
6170 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6171 * out-of-sync. Make sure to update the required fields
6172 * before using them.
6173 *
6174 * @remarks No-long-jump zone!!!
6175 */
6176static void hmR0VmxSaveGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6177{
6178 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_INTR_STATE))
6179 {
6180 uint32_t uIntrState = 0;
6181 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
6182 AssertRC(rc);
6183
6184 if (!uIntrState)
6185 {
6186 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
6187 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
6188
6189 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6190 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
6191 }
6192 else
6193 {
6194 if (uIntrState & ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS
6195 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI))
6196 {
6197 rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6198 AssertRC(rc);
6199 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx); /* for hmR0VmxGetGuestIntrState(). */
6200 AssertRC(rc);
6201
6202 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
6203 Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
6204 }
6205 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
6206 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
6207
6208 if (uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI)
6209 {
6210 if (!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6211 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
6212 }
6213 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6214 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
6215 }
6216
6217 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_INTR_STATE);
6218 }
6219}
6220
6221
6222/**
6223 * Saves the guest's activity state.
6224 *
6225 * @returns VBox status code.
6226 * @param pVCpu The cross context virtual CPU structure.
6227 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6228 * out-of-sync. Make sure to update the required fields
6229 * before using them.
6230 *
6231 * @remarks No-long-jump zone!!!
6232 */
6233static int hmR0VmxSaveGuestActivityState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6234{
6235 NOREF(pMixedCtx);
6236 /* Nothing to do for now until we make use of different guest-CPU activity state. Just update the flag. */
6237 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_ACTIVITY_STATE);
6238 return VINF_SUCCESS;
6239}
6240
6241
6242/**
6243 * Saves the guest SYSENTER MSRs (SYSENTER_CS, SYSENTER_EIP, SYSENTER_ESP) from
6244 * the current VMCS into the guest-CPU context.
6245 *
6246 * @returns VBox status code.
6247 * @param pVCpu The cross context virtual CPU structure.
6248 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6249 * out-of-sync. Make sure to update the required fields
6250 * before using them.
6251 *
6252 * @remarks No-long-jump zone!!!
6253 */
6254static int hmR0VmxSaveGuestSysenterMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6255{
6256 int rc = VINF_SUCCESS;
6257 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR))
6258 {
6259 uint32_t u32Val = 0;
6260 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRCReturn(rc, rc);
6261 pMixedCtx->SysEnter.cs = u32Val;
6262 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR);
6263 }
6264
6265 uint64_t u64Val = 0;
6266 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR))
6267 {
6268 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, &u64Val); AssertRCReturn(rc, rc);
6269 pMixedCtx->SysEnter.eip = u64Val;
6270 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR);
6271 }
6272 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR))
6273 {
6274 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, &u64Val); AssertRCReturn(rc, rc);
6275 pMixedCtx->SysEnter.esp = u64Val;
6276 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR);
6277 }
6278 return rc;
6279}
6280
6281
6282/**
6283 * Saves the set of guest MSRs (that we restore lazily while leaving VT-x) from
6284 * the CPU back into the guest-CPU context.
6285 *
6286 * @returns VBox status code.
6287 * @param pVCpu The cross context virtual CPU structure.
6288 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6289 * out-of-sync. Make sure to update the required fields
6290 * before using them.
6291 *
6292 * @remarks No-long-jump zone!!!
6293 */
6294static int hmR0VmxSaveGuestLazyMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6295{
6296 /* Since this can be called from our preemption hook it's safer to make the guest-MSRs update non-preemptible. */
6297 VMMRZCallRing3Disable(pVCpu);
6298 HM_DISABLE_PREEMPT();
6299
6300 /* Doing the check here ensures we don't overwrite already-saved guest MSRs from a preemption hook. */
6301 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS))
6302 {
6303 hmR0VmxLazySaveGuestMsrs(pVCpu, pMixedCtx);
6304 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS);
6305 }
6306
6307 HM_RESTORE_PREEMPT();
6308 VMMRZCallRing3Enable(pVCpu);
6309
6310 return VINF_SUCCESS;
6311}
6312
6313
6314/**
6315 * Saves the auto load/store'd guest MSRs from the current VMCS into
6316 * the guest-CPU context.
6317 *
6318 * @returns VBox status code.
6319 * @param pVCpu The cross context virtual CPU structure.
6320 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6321 * out-of-sync. Make sure to update the required fields
6322 * before using them.
6323 *
6324 * @remarks No-long-jump zone!!!
6325 */
6326static int hmR0VmxSaveGuestAutoLoadStoreMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6327{
6328 if (HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS))
6329 return VINF_SUCCESS;
6330
6331 PVMXAUTOMSR pMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
6332 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
6333 Log4(("hmR0VmxSaveGuestAutoLoadStoreMsrs: cMsrs=%u\n", cMsrs));
6334 for (uint32_t i = 0; i < cMsrs; i++, pMsr++)
6335 {
6336 switch (pMsr->u32Msr)
6337 {
6338 case MSR_K8_TSC_AUX: CPUMR0SetGuestTscAux(pVCpu, pMsr->u64Value); break;
6339 case MSR_K8_LSTAR: pMixedCtx->msrLSTAR = pMsr->u64Value; break;
6340 case MSR_K6_STAR: pMixedCtx->msrSTAR = pMsr->u64Value; break;
6341 case MSR_K8_SF_MASK: pMixedCtx->msrSFMASK = pMsr->u64Value; break;
6342 case MSR_K8_KERNEL_GS_BASE: pMixedCtx->msrKERNELGSBASE = pMsr->u64Value; break;
6343 case MSR_K6_EFER: /* Nothing to do here since we intercept writes, see hmR0VmxLoadGuestMsrs(). */
6344 break;
6345
6346 default:
6347 {
6348 AssertMsgFailed(("Unexpected MSR in auto-load/store area. uMsr=%#RX32 cMsrs=%u\n", pMsr->u32Msr, cMsrs));
6349 pVCpu->hm.s.u32HMError = pMsr->u32Msr;
6350 return VERR_HM_UNEXPECTED_LD_ST_MSR;
6351 }
6352 }
6353 }
6354
6355 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS);
6356 return VINF_SUCCESS;
6357}
6358
6359
6360/**
6361 * Saves the guest control registers from the current VMCS into the guest-CPU
6362 * context.
6363 *
6364 * @returns VBox status code.
6365 * @param pVCpu The cross context virtual CPU structure.
6366 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6367 * out-of-sync. Make sure to update the required fields
6368 * before using them.
6369 *
6370 * @remarks No-long-jump zone!!!
6371 */
6372static int hmR0VmxSaveGuestControlRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6373{
6374 /* Guest CR0. Guest FPU. */
6375 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6376 AssertRCReturn(rc, rc);
6377
6378 /* Guest CR4. */
6379 rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
6380 AssertRCReturn(rc, rc);
6381
6382 /* Guest CR2 - updated always during the world-switch or in #PF. */
6383 /* Guest CR3. Only changes with Nested Paging. This must be done -after- saving CR0 and CR4 from the guest! */
6384 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR3))
6385 {
6386 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
6387 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4));
6388
6389 PVM pVM = pVCpu->CTX_SUFF(pVM);
6390 if ( pVM->hm.s.vmx.fUnrestrictedGuest
6391 || ( pVM->hm.s.fNestedPaging
6392 && CPUMIsGuestPagingEnabledEx(pMixedCtx)))
6393 {
6394 uint64_t u64Val = 0;
6395 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_CR3, &u64Val);
6396 if (pMixedCtx->cr3 != u64Val)
6397 {
6398 CPUMSetGuestCR3(pVCpu, u64Val);
6399 if (VMMRZCallRing3IsEnabled(pVCpu))
6400 {
6401 PGMUpdateCR3(pVCpu, u64Val);
6402 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6403 }
6404 else
6405 {
6406 /* Set the force flag to inform PGM about it when necessary. It is cleared by PGMUpdateCR3().*/
6407 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
6408 }
6409 }
6410
6411 /* If the guest is in PAE mode, sync back the PDPE's into the guest state. */
6412 if (CPUMIsGuestInPAEModeEx(pMixedCtx)) /* Reads CR0, CR4 and EFER MSR (EFER is always up-to-date). */
6413 {
6414 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u);
6415 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u);
6416 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u);
6417 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u);
6418 AssertRCReturn(rc, rc);
6419
6420 if (VMMRZCallRing3IsEnabled(pVCpu))
6421 {
6422 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6423 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6424 }
6425 else
6426 {
6427 /* Set the force flag to inform PGM about it when necessary. It is cleared by PGMGstUpdatePaePdpes(). */
6428 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
6429 }
6430 }
6431 }
6432
6433 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR3);
6434 }
6435
6436 /*
6437 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
6438 * -> VMMRZCallRing3Disable() -> hmR0VmxSaveGuestState() -> Set VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
6439 * -> continue with VM-exit handling -> hmR0VmxSaveGuestControlRegs() and here we are.
6440 *
6441 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
6442 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
6443 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
6444 * -NOT- check if HMVMX_UPDATED_GUEST_CR3 is already set or not!
6445 *
6446 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
6447 */
6448 if (VMMRZCallRing3IsEnabled(pVCpu))
6449 {
6450 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
6451 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
6452
6453 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
6454 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6455
6456 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6457 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6458 }
6459
6460 return rc;
6461}
6462
6463
6464/**
6465 * Reads a guest segment register from the current VMCS into the guest-CPU
6466 * context.
6467 *
6468 * @returns VBox status code.
6469 * @param pVCpu The cross context virtual CPU structure.
6470 * @param idxSel Index of the selector in the VMCS.
6471 * @param idxLimit Index of the segment limit in the VMCS.
6472 * @param idxBase Index of the segment base in the VMCS.
6473 * @param idxAccess Index of the access rights of the segment in the VMCS.
6474 * @param pSelReg Pointer to the segment selector.
6475 *
6476 * @remarks No-long-jump zone!!!
6477 * @remarks Never call this function directly!!! Use the VMXLOCAL_READ_SEG()
6478 * macro as that takes care of whether to read from the VMCS cache or
6479 * not.
6480 */
6481DECLINLINE(int) hmR0VmxReadSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase, uint32_t idxAccess,
6482 PCPUMSELREG pSelReg)
6483{
6484 NOREF(pVCpu);
6485
6486 uint32_t u32Val = 0;
6487 int rc = VMXReadVmcs32(idxSel, &u32Val);
6488 AssertRCReturn(rc, rc);
6489 pSelReg->Sel = (uint16_t)u32Val;
6490 pSelReg->ValidSel = (uint16_t)u32Val;
6491 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
6492
6493 rc = VMXReadVmcs32(idxLimit, &u32Val);
6494 AssertRCReturn(rc, rc);
6495 pSelReg->u32Limit = u32Val;
6496
6497 uint64_t u64Val = 0;
6498 rc = VMXReadVmcsGstNByIdxVal(idxBase, &u64Val);
6499 AssertRCReturn(rc, rc);
6500 pSelReg->u64Base = u64Val;
6501
6502 rc = VMXReadVmcs32(idxAccess, &u32Val);
6503 AssertRCReturn(rc, rc);
6504 pSelReg->Attr.u = u32Val;
6505
6506 /*
6507 * If VT-x marks the segment as unusable, most other bits remain undefined:
6508 * - For CS the L, D and G bits have meaning.
6509 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
6510 * - For the remaining data segments no bits are defined.
6511 *
6512 * The present bit and the unusable bit has been observed to be set at the
6513 * same time (the selector was supposed to be invalid as we started executing
6514 * a V8086 interrupt in ring-0).
6515 *
6516 * What should be important for the rest of the VBox code, is that the P bit is
6517 * cleared. Some of the other VBox code recognizes the unusable bit, but
6518 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
6519 * safe side here, we'll strip off P and other bits we don't care about. If
6520 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
6521 *
6522 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
6523 */
6524 if (pSelReg->Attr.u & X86DESCATTR_UNUSABLE)
6525 {
6526 Assert(idxSel != VMX_VMCS16_GUEST_TR_SEL); /* TR is the only selector that can never be unusable. */
6527
6528 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
6529 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
6530 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
6531
6532 Log4(("hmR0VmxReadSegmentReg: Unusable idxSel=%#x attr=%#x -> %#x\n", idxSel, u32Val, pSelReg->Attr.u));
6533#ifdef DEBUG_bird
6534 AssertMsg((u32Val & ~X86DESCATTR_P) == pSelReg->Attr.u,
6535 ("%#x: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
6536 idxSel, u32Val, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
6537#endif
6538 }
6539 return VINF_SUCCESS;
6540}
6541
6542
6543#ifdef VMX_USE_CACHED_VMCS_ACCESSES
6544# define VMXLOCAL_READ_SEG(Sel, CtxSel) \
6545 hmR0VmxReadSegmentReg(pVCpu, VMX_VMCS16_GUEST_##Sel##_SEL, VMX_VMCS32_GUEST_##Sel##_LIMIT, \
6546 VMX_VMCS_GUEST_##Sel##_BASE_CACHE_IDX, VMX_VMCS32_GUEST_##Sel##_ACCESS_RIGHTS, &pMixedCtx->CtxSel)
6547#else
6548# define VMXLOCAL_READ_SEG(Sel, CtxSel) \
6549 hmR0VmxReadSegmentReg(pVCpu, VMX_VMCS16_GUEST_##Sel##_SEL, VMX_VMCS32_GUEST_##Sel##_LIMIT, \
6550 VMX_VMCS_GUEST_##Sel##_BASE, VMX_VMCS32_GUEST_##Sel##_ACCESS_RIGHTS, &pMixedCtx->CtxSel)
6551#endif
6552
6553
6554/**
6555 * Saves the guest segment registers from the current VMCS into the guest-CPU
6556 * context.
6557 *
6558 * @returns VBox status code.
6559 * @param pVCpu The cross context virtual CPU structure.
6560 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6561 * out-of-sync. Make sure to update the required fields
6562 * before using them.
6563 *
6564 * @remarks No-long-jump zone!!!
6565 */
6566static int hmR0VmxSaveGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6567{
6568 /* Guest segment registers. */
6569 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SEGMENT_REGS))
6570 {
6571 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6572 AssertRCReturn(rc, rc);
6573
6574 rc = VMXLOCAL_READ_SEG(CS, cs);
6575 rc |= VMXLOCAL_READ_SEG(SS, ss);
6576 rc |= VMXLOCAL_READ_SEG(DS, ds);
6577 rc |= VMXLOCAL_READ_SEG(ES, es);
6578 rc |= VMXLOCAL_READ_SEG(FS, fs);
6579 rc |= VMXLOCAL_READ_SEG(GS, gs);
6580 AssertRCReturn(rc, rc);
6581
6582 /* Restore segment attributes for real-on-v86 mode hack. */
6583 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
6584 {
6585 pMixedCtx->cs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrCS.u;
6586 pMixedCtx->ss.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrSS.u;
6587 pMixedCtx->ds.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrDS.u;
6588 pMixedCtx->es.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrES.u;
6589 pMixedCtx->fs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrFS.u;
6590 pMixedCtx->gs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrGS.u;
6591 }
6592 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SEGMENT_REGS);
6593 }
6594
6595 return VINF_SUCCESS;
6596}
6597
6598
6599/**
6600 * Saves the guest descriptor table registers and task register from the current
6601 * VMCS into the guest-CPU context.
6602 *
6603 * @returns VBox status code.
6604 * @param pVCpu The cross context virtual CPU structure.
6605 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6606 * out-of-sync. Make sure to update the required fields
6607 * before using them.
6608 *
6609 * @remarks No-long-jump zone!!!
6610 */
6611static int hmR0VmxSaveGuestTableRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6612{
6613 int rc = VINF_SUCCESS;
6614
6615 /* Guest LDTR. */
6616 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LDTR))
6617 {
6618 rc = VMXLOCAL_READ_SEG(LDTR, ldtr);
6619 AssertRCReturn(rc, rc);
6620 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LDTR);
6621 }
6622
6623 /* Guest GDTR. */
6624 uint64_t u64Val = 0;
6625 uint32_t u32Val = 0;
6626 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_GDTR))
6627 {
6628 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
6629 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRCReturn(rc, rc);
6630 pMixedCtx->gdtr.pGdt = u64Val;
6631 pMixedCtx->gdtr.cbGdt = u32Val;
6632 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_GDTR);
6633 }
6634
6635 /* Guest IDTR. */
6636 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_IDTR))
6637 {
6638 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
6639 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRCReturn(rc, rc);
6640 pMixedCtx->idtr.pIdt = u64Val;
6641 pMixedCtx->idtr.cbIdt = u32Val;
6642 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_IDTR);
6643 }
6644
6645 /* Guest TR. */
6646 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_TR))
6647 {
6648 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6649 AssertRCReturn(rc, rc);
6650
6651 /* For real-mode emulation using virtual-8086 mode we have the fake TSS (pRealModeTSS) in TR, don't save the fake one. */
6652 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
6653 {
6654 rc = VMXLOCAL_READ_SEG(TR, tr);
6655 AssertRCReturn(rc, rc);
6656 }
6657 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_TR);
6658 }
6659 return rc;
6660}
6661
6662#undef VMXLOCAL_READ_SEG
6663
6664
6665/**
6666 * Saves the guest debug-register DR7 from the current VMCS into the guest-CPU
6667 * context.
6668 *
6669 * @returns VBox status code.
6670 * @param pVCpu The cross context virtual CPU structure.
6671 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6672 * out-of-sync. Make sure to update the required fields
6673 * before using them.
6674 *
6675 * @remarks No-long-jump zone!!!
6676 */
6677static int hmR0VmxSaveGuestDR7(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6678{
6679 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_DEBUG))
6680 {
6681 if (!pVCpu->hm.s.fUsingHyperDR7)
6682 {
6683 /* Upper 32-bits are always zero. See Intel spec. 2.7.3 "Loading and Storing Debug Registers". */
6684 uint32_t u32Val;
6685 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_DR7, &u32Val); AssertRCReturn(rc, rc);
6686 pMixedCtx->dr[7] = u32Val;
6687 }
6688
6689 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_DEBUG);
6690 }
6691 return VINF_SUCCESS;
6692}
6693
6694
6695/**
6696 * Saves the guest APIC state from the current VMCS into the guest-CPU context.
6697 *
6698 * @returns VBox status code.
6699 * @param pVCpu The cross context virtual CPU structure.
6700 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6701 * out-of-sync. Make sure to update the required fields
6702 * before using them.
6703 *
6704 * @remarks No-long-jump zone!!!
6705 */
6706static int hmR0VmxSaveGuestApicState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6707{
6708 NOREF(pMixedCtx);
6709
6710 /* Updating TPR is already done in hmR0VmxPostRunGuest(). Just update the flag. */
6711 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_APIC_STATE);
6712 return VINF_SUCCESS;
6713}
6714
6715
6716/**
6717 * Saves the entire guest state from the currently active VMCS into the
6718 * guest-CPU context.
6719 *
6720 * This essentially VMREADs all guest-data.
6721 *
6722 * @returns VBox status code.
6723 * @param pVCpu The cross context virtual CPU structure.
6724 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6725 * out-of-sync. Make sure to update the required fields
6726 * before using them.
6727 */
6728static int hmR0VmxSaveGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6729{
6730 Assert(pVCpu);
6731 Assert(pMixedCtx);
6732
6733 if (HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL)
6734 return VINF_SUCCESS;
6735
6736 /* Though we can longjmp to ring-3 due to log-flushes here and get recalled
6737 again on the ring-3 callback path, there is no real need to. */
6738 if (VMMRZCallRing3IsEnabled(pVCpu))
6739 VMMR0LogFlushDisable(pVCpu);
6740 else
6741 Assert(VMMR0IsLogFlushDisabled(pVCpu));
6742 Log4Func(("vcpu[%RU32]\n", pVCpu->idCpu));
6743
6744 int rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
6745 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestRipRspRflags failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6746
6747 rc = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
6748 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestControlRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6749
6750 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
6751 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSegmentRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6752
6753 rc = hmR0VmxSaveGuestTableRegs(pVCpu, pMixedCtx);
6754 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestTableRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6755
6756 rc = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
6757 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestDR7 failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6758
6759 rc = hmR0VmxSaveGuestSysenterMsrs(pVCpu, pMixedCtx);
6760 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSysenterMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6761
6762 rc = hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
6763 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestLazyMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6764
6765 rc = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
6766 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestAutoLoadStoreMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6767
6768 rc = hmR0VmxSaveGuestActivityState(pVCpu, pMixedCtx);
6769 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestActivityState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6770
6771 rc = hmR0VmxSaveGuestApicState(pVCpu, pMixedCtx);
6772 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestApicState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6773
6774 AssertMsg(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL,
6775 ("Missed guest state bits while saving state; missing %RX32 (got %RX32, want %RX32) - check log for any previous errors!\n",
6776 HMVMX_UPDATED_GUEST_ALL ^ HMVMXCPU_GST_VALUE(pVCpu), HMVMXCPU_GST_VALUE(pVCpu), HMVMX_UPDATED_GUEST_ALL));
6777
6778 if (VMMRZCallRing3IsEnabled(pVCpu))
6779 VMMR0LogFlushEnable(pVCpu);
6780
6781 return VINF_SUCCESS;
6782}
6783
6784
6785/**
6786 * Saves basic guest registers needed for IEM instruction execution.
6787 *
6788 * @returns VBox status code (OR-able).
6789 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
6790 * @param pMixedCtx Pointer to the CPU context of the guest.
6791 * @param fMemory Whether the instruction being executed operates on
6792 * memory or not. Only CR0 is synced up if clear.
6793 * @param fNeedRsp Need RSP (any instruction working on GPRs or stack).
6794 */
6795static int hmR0VmxSaveGuestRegsForIemExec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fMemory, bool fNeedRsp)
6796{
6797 /*
6798 * We assume all general purpose registers other than RSP are available.
6799 *
6800 * RIP is a must, as it will be incremented or otherwise changed.
6801 *
6802 * RFLAGS are always required to figure the CPL.
6803 *
6804 * RSP isn't always required, however it's a GPR, so frequently required.
6805 *
6806 * SS and CS are the only segment register needed if IEM doesn't do memory
6807 * access (CPL + 16/32/64-bit mode), but we can only get all segment registers.
6808 *
6809 * CR0 is always required by IEM for the CPL, while CR3 and CR4 will only
6810 * be required for memory accesses.
6811 *
6812 * Note! Before IEM dispatches an exception, it will call us to sync in everything.
6813 */
6814 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6815 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
6816 if (fNeedRsp)
6817 rc |= hmR0VmxSaveGuestRsp(pVCpu, pMixedCtx);
6818 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
6819 if (!fMemory)
6820 rc |= hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6821 else
6822 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
6823 AssertRCReturn(rc, rc);
6824 return rc;
6825}
6826
6827
6828/**
6829 * Ensures that we've got a complete basic guest-context.
6830 *
6831 * This excludes the FPU, SSE, AVX, and similar extended state. The interface
6832 * is for the interpreter.
6833 *
6834 * @returns VBox status code.
6835 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
6836 * @param pMixedCtx Pointer to the guest-CPU context which may have data
6837 * needing to be synced in.
6838 * @thread EMT(pVCpu)
6839 */
6840VMMR0_INT_DECL(int) HMR0EnsureCompleteBasicContext(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6841{
6842 /* Note! Since this is only applicable to VT-x, the implementation is placed
6843 in the VT-x part of the sources instead of the generic stuff. */
6844 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported)
6845 {
6846 /* For now, imply that the caller might change everything too. */
6847 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
6848 return hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
6849 }
6850 return VINF_SUCCESS;
6851}
6852
6853
6854/**
6855 * Check per-VM and per-VCPU force flag actions that require us to go back to
6856 * ring-3 for one reason or another.
6857 *
6858 * @returns Strict VBox status code (i.e. informational status codes too)
6859 * @retval VINF_SUCCESS if we don't have any actions that require going back to
6860 * ring-3.
6861 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
6862 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
6863 * interrupts)
6864 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
6865 * all EMTs to be in ring-3.
6866 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
6867 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
6868 * to the EM loop.
6869 *
6870 * @param pVM The cross context VM structure.
6871 * @param pVCpu The cross context virtual CPU structure.
6872 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6873 * out-of-sync. Make sure to update the required fields
6874 * before using them.
6875 * @param fStepping Running in hmR0VmxRunGuestCodeStep().
6876 */
6877static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fStepping)
6878{
6879 Assert(VMMRZCallRing3IsEnabled(pVCpu));
6880
6881 /*
6882 * Anything pending? Should be more likely than not if we're doing a good job.
6883 */
6884 if ( !fStepping
6885 ? !VM_FF_IS_PENDING(pVM, VM_FF_HP_R0_PRE_HM_MASK)
6886 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
6887 : !VM_FF_IS_PENDING(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
6888 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
6889 return VINF_SUCCESS;
6890
6891 /* We need the control registers now, make sure the guest-CPU context is updated. */
6892 int rc3 = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
6893 AssertRCReturn(rc3, rc3);
6894
6895 /* Pending HM CR3 sync. */
6896 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
6897 {
6898 int rc2 = PGMUpdateCR3(pVCpu, pMixedCtx->cr3);
6899 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
6900 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
6901 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6902 }
6903
6904 /* Pending HM PAE PDPEs. */
6905 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
6906 {
6907 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6908 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6909 }
6910
6911 /* Pending PGM C3 sync. */
6912 if (VMCPU_FF_IS_PENDING(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
6913 {
6914 VBOXSTRICTRC rcStrict2 = PGMSyncCR3(pVCpu, pMixedCtx->cr0, pMixedCtx->cr3, pMixedCtx->cr4,
6915 VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
6916 if (rcStrict2 != VINF_SUCCESS)
6917 {
6918 AssertRC(VBOXSTRICTRC_VAL(rcStrict2));
6919 Log4(("hmR0VmxCheckForceFlags: PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict2)));
6920 return rcStrict2;
6921 }
6922 }
6923
6924 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
6925 if ( VM_FF_IS_PENDING(pVM, VM_FF_HM_TO_R3_MASK)
6926 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
6927 {
6928 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
6929 int rc2 = RT_UNLIKELY(VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_NO_MEMORY : VINF_EM_RAW_TO_R3;
6930 Log4(("hmR0VmxCheckForceFlags: HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc2));
6931 return rc2;
6932 }
6933
6934 /* Pending VM request packets, such as hardware interrupts. */
6935 if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST)
6936 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
6937 {
6938 Log4(("hmR0VmxCheckForceFlags: Pending VM request forcing us back to ring-3\n"));
6939 return VINF_EM_PENDING_REQUEST;
6940 }
6941
6942 /* Pending PGM pool flushes. */
6943 if (VM_FF_IS_PENDING(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
6944 {
6945 Log4(("hmR0VmxCheckForceFlags: PGM pool flush pending forcing us back to ring-3\n"));
6946 return VINF_PGM_POOL_FLUSH_PENDING;
6947 }
6948
6949 /* Pending DMA requests. */
6950 if (VM_FF_IS_PENDING(pVM, VM_FF_PDM_DMA))
6951 {
6952 Log4(("hmR0VmxCheckForceFlags: Pending DMA request forcing us back to ring-3\n"));
6953 return VINF_EM_RAW_TO_R3;
6954 }
6955
6956 return VINF_SUCCESS;
6957}
6958
6959
6960/**
6961 * Converts any TRPM trap into a pending HM event. This is typically used when
6962 * entering from ring-3 (not longjmp returns).
6963 *
6964 * @param pVCpu The cross context virtual CPU structure.
6965 */
6966static void hmR0VmxTrpmTrapToPendingEvent(PVMCPU pVCpu)
6967{
6968 Assert(TRPMHasTrap(pVCpu));
6969 Assert(!pVCpu->hm.s.Event.fPending);
6970
6971 uint8_t uVector;
6972 TRPMEVENT enmTrpmEvent;
6973 RTGCUINT uErrCode;
6974 RTGCUINTPTR GCPtrFaultAddress;
6975 uint8_t cbInstr;
6976
6977 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
6978 AssertRC(rc);
6979
6980 /* Refer Intel spec. 24.8.3 "VM-entry Controls for Event Injection" for the format of u32IntInfo. */
6981 uint32_t u32IntInfo = uVector | VMX_EXIT_INTERRUPTION_INFO_VALID;
6982 if (enmTrpmEvent == TRPM_TRAP)
6983 {
6984 switch (uVector)
6985 {
6986 case X86_XCPT_NMI:
6987 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6988 break;
6989
6990 case X86_XCPT_BP:
6991 case X86_XCPT_OF:
6992 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6993 break;
6994
6995 case X86_XCPT_PF:
6996 case X86_XCPT_DF:
6997 case X86_XCPT_TS:
6998 case X86_XCPT_NP:
6999 case X86_XCPT_SS:
7000 case X86_XCPT_GP:
7001 case X86_XCPT_AC:
7002 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7003 /* no break! */
7004 default:
7005 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7006 break;
7007 }
7008 }
7009 else if (enmTrpmEvent == TRPM_HARDWARE_INT)
7010 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7011 else if (enmTrpmEvent == TRPM_SOFTWARE_INT)
7012 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7013 else
7014 AssertMsgFailed(("Invalid TRPM event type %d\n", enmTrpmEvent));
7015
7016 rc = TRPMResetTrap(pVCpu);
7017 AssertRC(rc);
7018 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
7019 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
7020
7021 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
7022}
7023
7024
7025/**
7026 * Converts the pending HM event into a TRPM trap.
7027 *
7028 * @param pVCpu The cross context virtual CPU structure.
7029 */
7030static void hmR0VmxPendingEventToTrpmTrap(PVMCPU pVCpu)
7031{
7032 Assert(pVCpu->hm.s.Event.fPending);
7033
7034 uint32_t uVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
7035 uint32_t uVector = VMX_IDT_VECTORING_INFO_VECTOR(pVCpu->hm.s.Event.u64IntInfo);
7036 bool fErrorCodeValid = VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVCpu->hm.s.Event.u64IntInfo);
7037 uint32_t uErrorCode = pVCpu->hm.s.Event.u32ErrCode;
7038
7039 /* If a trap was already pending, we did something wrong! */
7040 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
7041
7042 TRPMEVENT enmTrapType;
7043 switch (uVectorType)
7044 {
7045 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
7046 enmTrapType = TRPM_HARDWARE_INT;
7047 break;
7048
7049 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
7050 enmTrapType = TRPM_SOFTWARE_INT;
7051 break;
7052
7053 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
7054 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
7055 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT: /* #BP and #OF */
7056 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
7057 enmTrapType = TRPM_TRAP;
7058 break;
7059
7060 default:
7061 AssertMsgFailed(("Invalid trap type %#x\n", uVectorType));
7062 enmTrapType = TRPM_32BIT_HACK;
7063 break;
7064 }
7065
7066 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
7067
7068 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
7069 AssertRC(rc);
7070
7071 if (fErrorCodeValid)
7072 TRPMSetErrorCode(pVCpu, uErrorCode);
7073
7074 if ( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
7075 && uVector == X86_XCPT_PF)
7076 {
7077 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
7078 }
7079 else if ( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
7080 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
7081 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
7082 {
7083 AssertMsg( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
7084 || (uVector == X86_XCPT_BP || uVector == X86_XCPT_OF),
7085 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
7086 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
7087 }
7088
7089 /* Clear any pending events from the VMCS. */
7090 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
7091 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, 0); AssertRC(rc);
7092
7093 /* We're now done converting the pending event. */
7094 pVCpu->hm.s.Event.fPending = false;
7095}
7096
7097
7098/**
7099 * Does the necessary state syncing before returning to ring-3 for any reason
7100 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
7101 *
7102 * @returns VBox status code.
7103 * @param pVCpu The cross context virtual CPU structure.
7104 * @param pMixedCtx Pointer to the guest-CPU context. The data may
7105 * be out-of-sync. Make sure to update the required
7106 * fields before using them.
7107 * @param fSaveGuestState Whether to save the guest state or not.
7108 *
7109 * @remarks No-long-jmp zone!!!
7110 */
7111static int hmR0VmxLeave(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fSaveGuestState)
7112{
7113 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7114 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7115
7116 RTCPUID idCpu = RTMpCpuId();
7117 Log4Func(("HostCpuId=%u\n", idCpu));
7118
7119 /*
7120 * !!! IMPORTANT !!!
7121 * If you modify code here, check whether hmR0VmxCallRing3Callback() needs to be updated too.
7122 */
7123
7124 /* Save the guest state if necessary. */
7125 if ( fSaveGuestState
7126 && HMVMXCPU_GST_VALUE(pVCpu) != HMVMX_UPDATED_GUEST_ALL)
7127 {
7128 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
7129 AssertRCReturn(rc, rc);
7130 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
7131 }
7132
7133 /* Restore host FPU state if necessary and resync on next R0 reentry .*/
7134 if (CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu))
7135 {
7136 if (fSaveGuestState)
7137 {
7138 /* We shouldn't reload CR0 without saving it first. */
7139 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7140 AssertRCReturn(rc, rc);
7141 }
7142 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
7143 }
7144
7145 /* Restore host debug registers if necessary and resync on next R0 reentry. */
7146#ifdef VBOX_STRICT
7147 if (CPUMIsHyperDebugStateActive(pVCpu))
7148 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT);
7149#endif
7150 if (CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */))
7151 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
7152 Assert(!CPUMIsGuestDebugStateActive(pVCpu) && !CPUMIsGuestDebugStateActivePending(pVCpu));
7153 Assert(!CPUMIsHyperDebugStateActive(pVCpu) && !CPUMIsHyperDebugStateActivePending(pVCpu));
7154
7155#if HC_ARCH_BITS == 64
7156 /* Restore host-state bits that VT-x only restores partially. */
7157 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7158 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7159 {
7160 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
7161 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7162 }
7163 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7164#endif
7165
7166 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7167 if (pVCpu->hm.s.vmx.fLazyMsrs)
7168 {
7169 /* We shouldn't reload the guest MSRs without saving it first. */
7170 if (!fSaveGuestState)
7171 {
7172 int rc = hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
7173 AssertRCReturn(rc, rc);
7174 }
7175 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS));
7176 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7177 Assert(!pVCpu->hm.s.vmx.fLazyMsrs);
7178 }
7179
7180 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7181 pVCpu->hm.s.vmx.fUpdatedHostMsrs = false;
7182
7183 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
7184 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatLoadGuestState);
7185 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExit1);
7186 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExit2);
7187 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
7188 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
7189 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
7190 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7191
7192 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7193
7194 /** @todo This partially defeats the purpose of having preemption hooks.
7195 * The problem is, deregistering the hooks should be moved to a place that
7196 * lasts until the EMT is about to be destroyed not everytime while leaving HM
7197 * context.
7198 */
7199 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_ACTIVE)
7200 {
7201 int rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
7202 AssertRCReturn(rc, rc);
7203
7204 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
7205 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
7206 }
7207 Assert(!(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_LAUNCHED));
7208 NOREF(idCpu);
7209
7210 return VINF_SUCCESS;
7211}
7212
7213
7214/**
7215 * Leaves the VT-x session.
7216 *
7217 * @returns VBox status code.
7218 * @param pVCpu The cross context virtual CPU structure.
7219 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7220 * out-of-sync. Make sure to update the required fields
7221 * before using them.
7222 *
7223 * @remarks No-long-jmp zone!!!
7224 */
7225DECLINLINE(int) hmR0VmxLeaveSession(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7226{
7227 HM_DISABLE_PREEMPT();
7228 HMVMX_ASSERT_CPU_SAFE();
7229 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7230 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7231
7232 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
7233 and done this from the VMXR0ThreadCtxCallback(). */
7234 if (!pVCpu->hm.s.fLeaveDone)
7235 {
7236 int rc2 = hmR0VmxLeave(pVCpu, pMixedCtx, true /* fSaveGuestState */);
7237 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
7238 pVCpu->hm.s.fLeaveDone = true;
7239 }
7240 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
7241
7242 /*
7243 * !!! IMPORTANT !!!
7244 * If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
7245 */
7246
7247 /* Deregister hook now that we've left HM context before re-enabling preemption. */
7248 /** @todo Deregistering here means we need to VMCLEAR always
7249 * (longjmp/exit-to-r3) in VT-x which is not efficient. */
7250 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
7251 VMMR0ThreadCtxHookDisable(pVCpu);
7252
7253 /* Leave HM context. This takes care of local init (term). */
7254 int rc = HMR0LeaveCpu(pVCpu);
7255
7256 HM_RESTORE_PREEMPT();
7257 return rc;
7258}
7259
7260
7261/**
7262 * Does the necessary state syncing before doing a longjmp to ring-3.
7263 *
7264 * @returns VBox status code.
7265 * @param pVCpu The cross context virtual CPU structure.
7266 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7267 * out-of-sync. Make sure to update the required fields
7268 * before using them.
7269 *
7270 * @remarks No-long-jmp zone!!!
7271 */
7272DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7273{
7274 return hmR0VmxLeaveSession(pVCpu, pMixedCtx);
7275}
7276
7277
7278/**
7279 * Take necessary actions before going back to ring-3.
7280 *
7281 * An action requires us to go back to ring-3. This function does the necessary
7282 * steps before we can safely return to ring-3. This is not the same as longjmps
7283 * to ring-3, this is voluntary and prepares the guest so it may continue
7284 * executing outside HM (recompiler/IEM).
7285 *
7286 * @returns VBox status code.
7287 * @param pVM The cross context VM structure.
7288 * @param pVCpu The cross context virtual CPU structure.
7289 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7290 * out-of-sync. Make sure to update the required fields
7291 * before using them.
7292 * @param rcExit The reason for exiting to ring-3. Can be
7293 * VINF_VMM_UNKNOWN_RING3_CALL.
7294 */
7295static int hmR0VmxExitToRing3(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, VBOXSTRICTRC rcExit)
7296{
7297 Assert(pVM);
7298 Assert(pVCpu);
7299 Assert(pMixedCtx);
7300 HMVMX_ASSERT_PREEMPT_SAFE();
7301
7302 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
7303 {
7304 VMXGetActivatedVmcs(&pVCpu->hm.s.vmx.LastError.u64VMCSPhys);
7305 pVCpu->hm.s.vmx.LastError.u32VMCSRevision = *(uint32_t *)pVCpu->hm.s.vmx.pvVmcs;
7306 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
7307 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
7308 }
7309
7310 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
7311 VMMRZCallRing3Disable(pVCpu);
7312 Log4(("hmR0VmxExitToRing3: pVCpu=%p idCpu=%RU32 rcExit=%d\n", pVCpu, pVCpu->idCpu, VBOXSTRICTRC_VAL(rcExit)));
7313
7314 /* We need to do this only while truly exiting the "inner loop" back to ring-3 and -not- for any longjmp to ring3. */
7315 if (pVCpu->hm.s.Event.fPending)
7316 {
7317 hmR0VmxPendingEventToTrpmTrap(pVCpu);
7318 Assert(!pVCpu->hm.s.Event.fPending);
7319 }
7320
7321 /* Clear interrupt-window and NMI-window controls as we re-evaluate it when we return from ring-3. */
7322 hmR0VmxClearIntNmiWindowsVmcs(pVCpu);
7323
7324 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
7325 and if we're injecting an event we should have a TRPM trap pending. */
7326 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
7327#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a tripple fault in progress. */
7328 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
7329#endif
7330
7331 /* Save guest state and restore host state bits. */
7332 int rc = hmR0VmxLeaveSession(pVCpu, pMixedCtx);
7333 AssertRCReturn(rc, rc);
7334 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7335 /* Thread-context hooks are unregistered at this point!!! */
7336
7337 /* Sync recompiler state. */
7338 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
7339 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
7340 | CPUM_CHANGED_LDTR
7341 | CPUM_CHANGED_GDTR
7342 | CPUM_CHANGED_IDTR
7343 | CPUM_CHANGED_TR
7344 | CPUM_CHANGED_HIDDEN_SEL_REGS);
7345 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
7346 if ( pVM->hm.s.fNestedPaging
7347 && CPUMIsGuestPagingEnabledEx(pMixedCtx))
7348 {
7349 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
7350 }
7351
7352 Assert(!pVCpu->hm.s.fClearTrapFlag);
7353
7354 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
7355 if (rcExit != VINF_EM_RAW_INTERRUPT)
7356 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
7357
7358 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
7359
7360 /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
7361 VMMRZCallRing3RemoveNotification(pVCpu);
7362 VMMRZCallRing3Enable(pVCpu);
7363
7364 return rc;
7365}
7366
7367
7368/**
7369 * VMMRZCallRing3() callback wrapper which saves the guest state before we
7370 * longjump to ring-3 and possibly get preempted.
7371 *
7372 * @returns VBox status code.
7373 * @param pVCpu The cross context virtual CPU structure.
7374 * @param enmOperation The operation causing the ring-3 longjump.
7375 * @param pvUser Opaque pointer to the guest-CPU context. The data
7376 * may be out-of-sync. Make sure to update the required
7377 * fields before using them.
7378 */
7379static DECLCALLBACK(int) hmR0VmxCallRing3Callback(PVMCPU pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
7380{
7381 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
7382 {
7383 /*
7384 * !!! IMPORTANT !!!
7385 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
7386 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
7387 */
7388 VMMRZCallRing3RemoveNotification(pVCpu);
7389 VMMRZCallRing3Disable(pVCpu);
7390 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
7391 RTThreadPreemptDisable(&PreemptState);
7392
7393 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
7394 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
7395
7396#if HC_ARCH_BITS == 64
7397 /* Restore host-state bits that VT-x only restores partially. */
7398 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7399 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7400 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7401 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7402#endif
7403 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7404 if (pVCpu->hm.s.vmx.fLazyMsrs)
7405 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7406
7407 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7408 pVCpu->hm.s.vmx.fUpdatedHostMsrs = false;
7409 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7410 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_ACTIVE)
7411 {
7412 VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
7413 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
7414 }
7415
7416 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
7417 VMMR0ThreadCtxHookDisable(pVCpu);
7418 HMR0LeaveCpu(pVCpu);
7419 RTThreadPreemptRestore(&PreemptState);
7420 return VINF_SUCCESS;
7421 }
7422
7423 Assert(pVCpu);
7424 Assert(pvUser);
7425 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7426 HMVMX_ASSERT_PREEMPT_SAFE();
7427
7428 VMMRZCallRing3Disable(pVCpu);
7429 Assert(VMMR0IsLogFlushDisabled(pVCpu));
7430
7431 Log4(("hmR0VmxCallRing3Callback->hmR0VmxLongJmpToRing3 pVCpu=%p idCpu=%RU32 enmOperation=%d\n", pVCpu, pVCpu->idCpu,
7432 enmOperation));
7433
7434 int rc = hmR0VmxLongJmpToRing3(pVCpu, (PCPUMCTX)pvUser);
7435 AssertRCReturn(rc, rc);
7436
7437 VMMRZCallRing3Enable(pVCpu);
7438 return VINF_SUCCESS;
7439}
7440
7441
7442/**
7443 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
7444 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
7445 *
7446 * @param pVCpu The cross context virtual CPU structure.
7447 */
7448DECLINLINE(void) hmR0VmxSetIntWindowExitVmcs(PVMCPU pVCpu)
7449{
7450 if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
7451 {
7452 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
7453 {
7454 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT;
7455 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7456 AssertRC(rc);
7457 Log4(("Setup interrupt-window exiting\n"));
7458 }
7459 } /* else we will deliver interrupts whenever the guest exits next and is in a state to receive events. */
7460}
7461
7462
7463/**
7464 * Clears the interrupt-window exiting control in the VMCS.
7465 *
7466 * @param pVCpu The cross context virtual CPU structure.
7467 */
7468DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMCPU pVCpu)
7469{
7470 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT);
7471 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT;
7472 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7473 AssertRC(rc);
7474 Log4(("Cleared interrupt-window exiting\n"));
7475}
7476
7477
7478/**
7479 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
7480 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
7481 *
7482 * @param pVCpu The cross context virtual CPU structure.
7483 */
7484DECLINLINE(void) hmR0VmxSetNmiWindowExitVmcs(PVMCPU pVCpu)
7485{
7486 if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT))
7487 {
7488 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT))
7489 {
7490 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT;
7491 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7492 AssertRC(rc);
7493 Log4(("Setup NMI-window exiting\n"));
7494 }
7495 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
7496}
7497
7498
7499/**
7500 * Clears the NMI-window exiting control in the VMCS.
7501 *
7502 * @param pVCpu The cross context virtual CPU structure.
7503 */
7504DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMCPU pVCpu)
7505{
7506 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT);
7507 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT;
7508 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7509 AssertRC(rc);
7510 Log4(("Cleared NMI-window exiting\n"));
7511}
7512
7513
7514/**
7515 * Evaluates the event to be delivered to the guest and sets it as the pending
7516 * event.
7517 *
7518 * @returns The VT-x guest-interruptibility state.
7519 * @param pVCpu The cross context virtual CPU structure.
7520 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7521 * out-of-sync. Make sure to update the required fields
7522 * before using them.
7523 */
7524static uint32_t hmR0VmxEvaluatePendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7525{
7526 /* Get the current interruptibility-state of the guest and then figure out what can be injected. */
7527 uint32_t const uIntrState = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx);
7528 bool const fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7529 bool const fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7530 bool const fBlockNmi = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI);
7531
7532 Assert(!fBlockSti || HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS));
7533 Assert(!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
7534 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
7535 Assert(!TRPMHasTrap(pVCpu));
7536
7537 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
7538 APICUpdatePendingInterrupts(pVCpu);
7539
7540 /*
7541 * Toggling of interrupt force-flags here is safe since we update TRPM on premature exits
7542 * to ring-3 before executing guest code, see hmR0VmxExitToRing3(). We must NOT restore these force-flags.
7543 */
7544 /** @todo SMI. SMIs take priority over NMIs. */
7545 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NMI)) /* NMI. NMIs take priority over regular interrupts. */
7546 {
7547 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
7548 if ( !pVCpu->hm.s.Event.fPending
7549 && !fBlockNmi
7550 && !fBlockSti
7551 && !fBlockMovSS)
7552 {
7553 Log4(("Pending NMI vcpu[%RU32]\n", pVCpu->idCpu));
7554 uint32_t u32IntInfo = X86_XCPT_NMI | VMX_EXIT_INTERRUPTION_INFO_VALID;
7555 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7556
7557 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7558 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
7559 }
7560 else
7561 hmR0VmxSetNmiWindowExitVmcs(pVCpu);
7562 }
7563 /*
7564 * Check if the guest can receive external interrupts (PIC/APIC). Once PDMGetInterrupt() returns
7565 * a valid interrupt we must- deliver the interrupt. We can no longer re-request it from the APIC.
7566 */
7567 else if ( VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
7568 && !pVCpu->hm.s.fSingleInstruction)
7569 {
7570 Assert(!DBGFIsStepping(pVCpu));
7571 int rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7572 AssertRC(rc);
7573 bool const fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
7574 if ( !pVCpu->hm.s.Event.fPending
7575 && !fBlockInt
7576 && !fBlockSti
7577 && !fBlockMovSS)
7578 {
7579 uint8_t u8Interrupt;
7580 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
7581 if (RT_SUCCESS(rc))
7582 {
7583 Log4(("Pending interrupt vcpu[%RU32] u8Interrupt=%#x \n", pVCpu->idCpu, u8Interrupt));
7584 uint32_t u32IntInfo = u8Interrupt | VMX_EXIT_INTERRUPTION_INFO_VALID;
7585 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7586
7587 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrfaultAddress */);
7588 }
7589 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
7590 {
7591 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
7592 hmR0VmxApicSetTprThreshold(pVCpu, u8Interrupt >> 4);
7593 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
7594 }
7595 else
7596 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
7597 }
7598 else
7599 hmR0VmxSetIntWindowExitVmcs(pVCpu);
7600 }
7601
7602 return uIntrState;
7603}
7604
7605
7606/**
7607 * Sets a pending-debug exception to be delivered to the guest if the guest is
7608 * single-stepping in the VMCS.
7609 *
7610 * @param pVCpu The cross context virtual CPU structure.
7611 */
7612DECLINLINE(void) hmR0VmxSetPendingDebugXcptVmcs(PVMCPU pVCpu)
7613{
7614 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS)); NOREF(pVCpu);
7615 int rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_BS);
7616 AssertRC(rc);
7617}
7618
7619
7620/**
7621 * Injects any pending events into the guest if the guest is in a state to
7622 * receive them.
7623 *
7624 * @returns Strict VBox status code (i.e. informational status codes too).
7625 * @param pVCpu The cross context virtual CPU structure.
7626 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7627 * out-of-sync. Make sure to update the required fields
7628 * before using them.
7629 * @param uIntrState The VT-x guest-interruptibility state.
7630 * @param fStepping Running in hmR0VmxRunGuestCodeStep() and we should
7631 * return VINF_EM_DBG_STEPPED if the event was
7632 * dispatched directly.
7633 */
7634static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t uIntrState, bool fStepping)
7635{
7636 HMVMX_ASSERT_PREEMPT_SAFE();
7637 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7638
7639 bool fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7640 bool fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7641
7642 Assert(!fBlockSti || HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS));
7643 Assert(!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
7644 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
7645 Assert(!TRPMHasTrap(pVCpu));
7646
7647 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
7648 if (pVCpu->hm.s.Event.fPending)
7649 {
7650 /*
7651 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
7652 * pending even while injecting an event and in this case, we want a VM-exit as soon as
7653 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
7654 *
7655 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
7656 */
7657 uint32_t const uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
7658#ifdef VBOX_STRICT
7659 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
7660 {
7661 bool const fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
7662 Assert(!fBlockInt);
7663 Assert(!fBlockSti);
7664 Assert(!fBlockMovSS);
7665 }
7666 else if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
7667 {
7668 bool const fBlockNmi = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI);
7669 Assert(!fBlockSti);
7670 Assert(!fBlockMovSS);
7671 Assert(!fBlockNmi);
7672 }
7673#endif
7674 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#x\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
7675 (uint8_t)uIntType));
7676 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, pVCpu->hm.s.Event.u64IntInfo, pVCpu->hm.s.Event.cbInstr,
7677 pVCpu->hm.s.Event.u32ErrCode, pVCpu->hm.s.Event.GCPtrFaultAddress,
7678 fStepping, &uIntrState);
7679 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
7680
7681 /* Update the interruptibility-state as it could have been changed by
7682 hmR0VmxInjectEventVmcs() (e.g. real-on-v86 guest injecting software interrupts) */
7683 fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7684 fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7685
7686 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
7687 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
7688 else
7689 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
7690 }
7691
7692 /* Deliver pending debug exception if the guest is single-stepping. Evaluate and set the BS bit. */
7693 if ( fBlockSti
7694 || fBlockMovSS)
7695 {
7696 if (!pVCpu->hm.s.fSingleInstruction)
7697 {
7698 /*
7699 * The pending-debug exceptions field is cleared on all VM-exits except VMX_EXIT_TPR_BELOW_THRESHOLD,
7700 * VMX_EXIT_MTF, VMX_EXIT_APIC_WRITE and VMX_EXIT_VIRTUALIZED_EOI.
7701 * See Intel spec. 27.3.4 "Saving Non-Register State".
7702 */
7703 Assert(!DBGFIsStepping(pVCpu));
7704 int rc2 = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7705 AssertRCReturn(rc2, rc2);
7706 if (pMixedCtx->eflags.Bits.u1TF)
7707 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
7708 }
7709 else if (pMixedCtx->eflags.Bits.u1TF)
7710 {
7711 /*
7712 * We are single-stepping in the hypervisor debugger using EFLAGS.TF. Clear interrupt inhibition as setting the
7713 * BS bit would mean delivering a #DB to the guest upon VM-entry when it shouldn't be.
7714 */
7715 Assert(!(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG));
7716 uIntrState = 0;
7717 }
7718 }
7719
7720 /*
7721 * There's no need to clear the VM-entry interruption-information field here if we're not injecting anything.
7722 * VT-x clears the valid bit on every VM-exit. See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
7723 */
7724 int rc2 = hmR0VmxLoadGuestIntrState(pVCpu, uIntrState);
7725 AssertRC(rc2);
7726
7727 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
7728 NOREF(fBlockMovSS); NOREF(fBlockSti);
7729 return rcStrict;
7730}
7731
7732
7733/**
7734 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
7735 *
7736 * @param pVCpu The cross context virtual CPU structure.
7737 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7738 * out-of-sync. Make sure to update the required fields
7739 * before using them.
7740 */
7741DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7742{
7743 NOREF(pMixedCtx);
7744 uint32_t u32IntInfo = X86_XCPT_UD | VMX_EXIT_INTERRUPTION_INFO_VALID;
7745 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7746}
7747
7748
7749/**
7750 * Injects a double-fault (\#DF) exception into the VM.
7751 *
7752 * @returns Strict VBox status code (i.e. informational status codes too).
7753 * @param pVCpu The cross context virtual CPU structure.
7754 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7755 * out-of-sync. Make sure to update the required fields
7756 * before using them.
7757 * @param fStepping Whether we're running in hmR0VmxRunGuestCodeStep()
7758 * and should return VINF_EM_DBG_STEPPED if the event
7759 * is injected directly (register modified by us, not
7760 * by hardware on VM-entry).
7761 * @param puIntrState Pointer to the current guest interruptibility-state.
7762 * This interruptibility-state will be updated if
7763 * necessary. This cannot not be NULL.
7764 */
7765DECLINLINE(VBOXSTRICTRC) hmR0VmxInjectXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fStepping, uint32_t *puIntrState)
7766{
7767 uint32_t u32IntInfo = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
7768 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7769 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7770 return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */,
7771 fStepping, puIntrState);
7772}
7773
7774
7775/**
7776 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
7777 *
7778 * @param pVCpu The cross context virtual CPU structure.
7779 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7780 * out-of-sync. Make sure to update the required fields
7781 * before using them.
7782 */
7783DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7784{
7785 NOREF(pMixedCtx);
7786 uint32_t u32IntInfo = X86_XCPT_DB | VMX_EXIT_INTERRUPTION_INFO_VALID;
7787 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7788 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7789}
7790
7791
7792/**
7793 * Sets an overflow (\#OF) exception as pending-for-injection into the VM.
7794 *
7795 * @param pVCpu The cross context virtual CPU structure.
7796 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7797 * out-of-sync. Make sure to update the required fields
7798 * before using them.
7799 * @param cbInstr The value of RIP that is to be pushed on the guest
7800 * stack.
7801 */
7802DECLINLINE(void) hmR0VmxSetPendingXcptOF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
7803{
7804 NOREF(pMixedCtx);
7805 uint32_t u32IntInfo = X86_XCPT_OF | VMX_EXIT_INTERRUPTION_INFO_VALID;
7806 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7807 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7808}
7809
7810
7811/**
7812 * Injects a general-protection (\#GP) fault into the VM.
7813 *
7814 * @returns Strict VBox status code (i.e. informational status codes too).
7815 * @param pVCpu The cross context virtual CPU structure.
7816 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7817 * out-of-sync. Make sure to update the required fields
7818 * before using them.
7819 * @param fErrorCodeValid Whether the error code is valid (depends on the CPU
7820 * mode, i.e. in real-mode it's not valid).
7821 * @param u32ErrorCode The error code associated with the \#GP.
7822 * @param fStepping Whether we're running in
7823 * hmR0VmxRunGuestCodeStep() and should return
7824 * VINF_EM_DBG_STEPPED if the event is injected
7825 * directly (register modified by us, not by
7826 * hardware on VM-entry).
7827 * @param puIntrState Pointer to the current guest interruptibility-state.
7828 * This interruptibility-state will be updated if
7829 * necessary. This cannot not be NULL.
7830 */
7831DECLINLINE(VBOXSTRICTRC) hmR0VmxInjectXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fErrorCodeValid, uint32_t u32ErrorCode,
7832 bool fStepping, uint32_t *puIntrState)
7833{
7834 uint32_t u32IntInfo = X86_XCPT_GP | VMX_EXIT_INTERRUPTION_INFO_VALID;
7835 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7836 if (fErrorCodeValid)
7837 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7838 return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */,
7839 fStepping, puIntrState);
7840}
7841
7842
7843#if 0 /* unused */
7844/**
7845 * Sets a general-protection (\#GP) exception as pending-for-injection into the
7846 * VM.
7847 *
7848 * @param pVCpu The cross context virtual CPU structure.
7849 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7850 * out-of-sync. Make sure to update the required fields
7851 * before using them.
7852 * @param u32ErrorCode The error code associated with the \#GP.
7853 */
7854DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t u32ErrorCode)
7855{
7856 NOREF(pMixedCtx);
7857 uint32_t u32IntInfo = X86_XCPT_GP | VMX_EXIT_INTERRUPTION_INFO_VALID;
7858 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7859 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7860 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */);
7861}
7862#endif /* unused */
7863
7864
7865/**
7866 * Sets a software interrupt (INTn) as pending-for-injection into the VM.
7867 *
7868 * @param pVCpu The cross context virtual CPU structure.
7869 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7870 * out-of-sync. Make sure to update the required fields
7871 * before using them.
7872 * @param uVector The software interrupt vector number.
7873 * @param cbInstr The value of RIP that is to be pushed on the guest
7874 * stack.
7875 */
7876DECLINLINE(void) hmR0VmxSetPendingIntN(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint16_t uVector, uint32_t cbInstr)
7877{
7878 NOREF(pMixedCtx);
7879 uint32_t u32IntInfo = uVector | VMX_EXIT_INTERRUPTION_INFO_VALID;
7880 if ( uVector == X86_XCPT_BP
7881 || uVector == X86_XCPT_OF)
7882 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7883 else
7884 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7885 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7886}
7887
7888
7889/**
7890 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
7891 * stack.
7892 *
7893 * @returns Strict VBox status code (i.e. informational status codes too).
7894 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
7895 * @param pVM The cross context VM structure.
7896 * @param pMixedCtx Pointer to the guest-CPU context.
7897 * @param uValue The value to push to the guest stack.
7898 */
7899DECLINLINE(VBOXSTRICTRC) hmR0VmxRealModeGuestStackPush(PVM pVM, PCPUMCTX pMixedCtx, uint16_t uValue)
7900{
7901 /*
7902 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
7903 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
7904 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
7905 */
7906 if (pMixedCtx->sp == 1)
7907 return VINF_EM_RESET;
7908 pMixedCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
7909 int rc = PGMPhysSimpleWriteGCPhys(pVM, pMixedCtx->ss.u64Base + pMixedCtx->sp, &uValue, sizeof(uint16_t));
7910 AssertRC(rc);
7911 return rc;
7912}
7913
7914
7915/**
7916 * Injects an event into the guest upon VM-entry by updating the relevant fields
7917 * in the VM-entry area in the VMCS.
7918 *
7919 * @returns Strict VBox status code (i.e. informational status codes too).
7920 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
7921 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
7922 *
7923 * @param pVCpu The cross context virtual CPU structure.
7924 * @param pMixedCtx Pointer to the guest-CPU context. The data may
7925 * be out-of-sync. Make sure to update the required
7926 * fields before using them.
7927 * @param u64IntInfo The VM-entry interruption-information field.
7928 * @param cbInstr The VM-entry instruction length in bytes (for
7929 * software interrupts, exceptions and privileged
7930 * software exceptions).
7931 * @param u32ErrCode The VM-entry exception error code.
7932 * @param GCPtrFaultAddress The page-fault address for \#PF exceptions.
7933 * @param puIntrState Pointer to the current guest interruptibility-state.
7934 * This interruptibility-state will be updated if
7935 * necessary. This cannot not be NULL.
7936 * @param fStepping Whether we're running in
7937 * hmR0VmxRunGuestCodeStep() and should return
7938 * VINF_EM_DBG_STEPPED if the event is injected
7939 * directly (register modified by us, not by
7940 * hardware on VM-entry).
7941 *
7942 * @remarks Requires CR0!
7943 * @remarks No-long-jump zone!!!
7944 */
7945static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
7946 uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, bool fStepping,
7947 uint32_t *puIntrState)
7948{
7949 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
7950 AssertMsg(u64IntInfo >> 32 == 0, ("%#RX64\n", u64IntInfo));
7951 Assert(puIntrState);
7952 uint32_t u32IntInfo = (uint32_t)u64IntInfo;
7953
7954 uint32_t const uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(u32IntInfo);
7955 uint32_t const uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntInfo);
7956
7957#ifdef VBOX_STRICT
7958 /* Validate the error-code-valid bit for hardware exceptions. */
7959 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT)
7960 {
7961 switch (uVector)
7962 {
7963 case X86_XCPT_PF:
7964 case X86_XCPT_DF:
7965 case X86_XCPT_TS:
7966 case X86_XCPT_NP:
7967 case X86_XCPT_SS:
7968 case X86_XCPT_GP:
7969 case X86_XCPT_AC:
7970 AssertMsg(VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(u32IntInfo),
7971 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
7972 /* fallthru */
7973 default:
7974 break;
7975 }
7976 }
7977#endif
7978
7979 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
7980 Assert( uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
7981 || !(*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS));
7982
7983 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
7984
7985 /* We require CR0 to check if the guest is in real-mode. */
7986 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7987 AssertRCReturn(rc, rc);
7988
7989 /*
7990 * Hardware interrupts & exceptions cannot be delivered through the software interrupt redirection bitmap to the real
7991 * mode task in virtual-8086 mode. We must jump to the interrupt handler in the (real-mode) guest.
7992 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode" for interrupt & exception classes.
7993 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
7994 */
7995 if (CPUMIsGuestInRealModeEx(pMixedCtx))
7996 {
7997 PVM pVM = pVCpu->CTX_SUFF(pVM);
7998 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
7999 {
8000 Assert(PDMVmmDevHeapIsEnabled(pVM));
8001 Assert(pVM->hm.s.vmx.pRealModeTSS);
8002
8003 /* We require RIP, RSP, RFLAGS, CS, IDTR. Save the required ones from the VMCS. */
8004 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
8005 rc |= hmR0VmxSaveGuestTableRegs(pVCpu, pMixedCtx);
8006 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
8007 AssertRCReturn(rc, rc);
8008 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP));
8009
8010 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8011 size_t const cbIdtEntry = sizeof(X86IDTR16);
8012 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pMixedCtx->idtr.cbIdt)
8013 {
8014 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8015 if (uVector == X86_XCPT_DF)
8016 return VINF_EM_RESET;
8017
8018 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault. */
8019 if (uVector == X86_XCPT_GP)
8020 return hmR0VmxInjectXcptDF(pVCpu, pMixedCtx, fStepping, puIntrState);
8021
8022 /* If we're injecting an interrupt/exception with no valid IDT entry, inject a general-protection fault. */
8023 /* No error codes for exceptions in real-mode. See Intel spec. 20.1.4 "Interrupt and Exception Handling" */
8024 return hmR0VmxInjectXcptGP(pVCpu, pMixedCtx, false /* fErrCodeValid */, 0 /* u32ErrCode */,
8025 fStepping, puIntrState);
8026 }
8027
8028 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8029 uint16_t uGuestIp = pMixedCtx->ip;
8030 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT)
8031 {
8032 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8033 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8034 uGuestIp = pMixedCtx->ip + (uint16_t)cbInstr;
8035 }
8036 else if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT)
8037 uGuestIp = pMixedCtx->ip + (uint16_t)cbInstr;
8038
8039 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8040 X86IDTR16 IdtEntry;
8041 RTGCPHYS GCPhysIdtEntry = (RTGCPHYS)pMixedCtx->idtr.pIdt + uVector * cbIdtEntry;
8042 rc = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8043 AssertRCReturn(rc, rc);
8044
8045 /* Construct the stack frame for the interrupt/exception handler. */
8046 VBOXSTRICTRC rcStrict;
8047 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, pMixedCtx->eflags.u32);
8048 if (rcStrict == VINF_SUCCESS)
8049 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, pMixedCtx->cs.Sel);
8050 if (rcStrict == VINF_SUCCESS)
8051 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, uGuestIp);
8052
8053 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8054 if (rcStrict == VINF_SUCCESS)
8055 {
8056 pMixedCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8057 pMixedCtx->rip = IdtEntry.offSel;
8058 pMixedCtx->cs.Sel = IdtEntry.uSel;
8059 pMixedCtx->cs.ValidSel = IdtEntry.uSel;
8060 pMixedCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8061 if ( uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
8062 && uVector == X86_XCPT_PF)
8063 pMixedCtx->cr2 = GCPtrFaultAddress;
8064
8065 /* If any other guest-state bits are changed here, make sure to update
8066 hmR0VmxPreRunGuestCommitted() when thread-context hooks are used. */
8067 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS
8068 | HM_CHANGED_GUEST_RIP
8069 | HM_CHANGED_GUEST_RFLAGS
8070 | HM_CHANGED_GUEST_RSP);
8071
8072 /* We're clearing interrupts, which means no block-by-STI interrupt-inhibition. */
8073 if (*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
8074 {
8075 Assert( uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
8076 && uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
8077 Log4(("Clearing inhibition due to STI.\n"));
8078 *puIntrState &= ~VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
8079 }
8080 Log4(("Injecting real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8081 u32IntInfo, u32ErrCode, cbInstr, pMixedCtx->eflags.u, pMixedCtx->cs.Sel, pMixedCtx->eip));
8082
8083 /* The event has been truly dispatched. Mark it as no longer pending so we don't attempt to 'undo'
8084 it, if we are returning to ring-3 before executing guest code. */
8085 pVCpu->hm.s.Event.fPending = false;
8086
8087 /* Make hmR0VmxPreRunGuest return if we're stepping since we've changed cs:rip. */
8088 if (fStepping)
8089 rcStrict = VINF_EM_DBG_STEPPED;
8090 }
8091 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8092 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8093 return rcStrict;
8094 }
8095
8096 /*
8097 * For unrestricted execution enabled CPUs running real-mode guests, we must not set the deliver-error-code bit.
8098 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8099 */
8100 u32IntInfo &= ~VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
8101 }
8102
8103 /* Validate. */
8104 Assert(VMX_EXIT_INTERRUPTION_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8105 Assert(!VMX_EXIT_INTERRUPTION_INFO_NMI_UNBLOCK_IRET(u32IntInfo)); /* Bit 12 MBZ. */
8106 Assert(!(u32IntInfo & 0x7ffff000)); /* Bits 30:12 MBZ. */
8107
8108 /* Inject. */
8109 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8110 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(u32IntInfo))
8111 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8112 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8113
8114 if ( VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
8115 && uVector == X86_XCPT_PF)
8116 pMixedCtx->cr2 = GCPtrFaultAddress;
8117
8118 Log4(("Injecting vcpu[%RU32] u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x pMixedCtx->uCR2=%#RX64\n", pVCpu->idCpu,
8119 u32IntInfo, u32ErrCode, cbInstr, pMixedCtx->cr2));
8120
8121 AssertRCReturn(rc, rc);
8122 return VINF_SUCCESS;
8123}
8124
8125
8126/**
8127 * Clears the interrupt-window exiting control in the VMCS and if necessary
8128 * clears the current event in the VMCS as well.
8129 *
8130 * @returns VBox status code.
8131 * @param pVCpu The cross context virtual CPU structure.
8132 *
8133 * @remarks Use this function only to clear events that have not yet been
8134 * delivered to the guest but are injected in the VMCS!
8135 * @remarks No-long-jump zone!!!
8136 */
8137static void hmR0VmxClearIntNmiWindowsVmcs(PVMCPU pVCpu)
8138{
8139 Log4Func(("vcpu[%d]\n", pVCpu->idCpu));
8140
8141 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT)
8142 hmR0VmxClearIntWindowExitVmcs(pVCpu);
8143
8144 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT)
8145 hmR0VmxClearNmiWindowExitVmcs(pVCpu);
8146}
8147
8148
8149/**
8150 * Enters the VT-x session.
8151 *
8152 * @returns VBox status code.
8153 * @param pVM The cross context VM structure.
8154 * @param pVCpu The cross context virtual CPU structure.
8155 * @param pCpu Pointer to the CPU info struct.
8156 */
8157VMMR0DECL(int) VMXR0Enter(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
8158{
8159 AssertPtr(pVM);
8160 AssertPtr(pVCpu);
8161 Assert(pVM->hm.s.vmx.fSupported);
8162 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8163 NOREF(pCpu); NOREF(pVM);
8164
8165 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8166 Assert(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE));
8167
8168#ifdef VBOX_STRICT
8169 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
8170 RTCCUINTREG uHostCR4 = ASMGetCR4();
8171 if (!(uHostCR4 & X86_CR4_VMXE))
8172 {
8173 LogRel(("VMXR0Enter: X86_CR4_VMXE bit in CR4 is not set!\n"));
8174 return VERR_VMX_X86_CR4_VMXE_CLEARED;
8175 }
8176#endif
8177
8178 /*
8179 * Load the VCPU's VMCS as the current (and active) one.
8180 */
8181 Assert(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_CLEAR);
8182 int rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
8183 if (RT_FAILURE(rc))
8184 return rc;
8185
8186 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
8187 pVCpu->hm.s.fLeaveDone = false;
8188 Log4Func(("Activated Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8189
8190 return VINF_SUCCESS;
8191}
8192
8193
8194/**
8195 * The thread-context callback (only on platforms which support it).
8196 *
8197 * @param enmEvent The thread-context event.
8198 * @param pVCpu The cross context virtual CPU structure.
8199 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
8200 * @thread EMT(pVCpu)
8201 */
8202VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPU pVCpu, bool fGlobalInit)
8203{
8204 NOREF(fGlobalInit);
8205
8206 switch (enmEvent)
8207 {
8208 case RTTHREADCTXEVENT_OUT:
8209 {
8210 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8211 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8212 VMCPU_ASSERT_EMT(pVCpu);
8213
8214 PCPUMCTX pMixedCtx = CPUMQueryGuestCtxPtr(pVCpu);
8215
8216 /* No longjmps (logger flushes, locks) in this fragile context. */
8217 VMMRZCallRing3Disable(pVCpu);
8218 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
8219
8220 /*
8221 * Restore host-state (FPU, debug etc.)
8222 */
8223 if (!pVCpu->hm.s.fLeaveDone)
8224 {
8225 /* Do -not- save guest-state here as we might already be in the middle of saving it (esp. bad if we are
8226 holding the PGM lock while saving the guest state (see hmR0VmxSaveGuestControlRegs()). */
8227 hmR0VmxLeave(pVCpu, pMixedCtx, false /* fSaveGuestState */);
8228 pVCpu->hm.s.fLeaveDone = true;
8229 }
8230
8231 /* Leave HM context, takes care of local init (term). */
8232 int rc = HMR0LeaveCpu(pVCpu);
8233 AssertRC(rc); NOREF(rc);
8234
8235 /* Restore longjmp state. */
8236 VMMRZCallRing3Enable(pVCpu);
8237 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
8238 break;
8239 }
8240
8241 case RTTHREADCTXEVENT_IN:
8242 {
8243 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8244 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8245 VMCPU_ASSERT_EMT(pVCpu);
8246
8247 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
8248 VMMRZCallRing3Disable(pVCpu);
8249 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
8250
8251 /* Initialize the bare minimum state required for HM. This takes care of
8252 initializing VT-x if necessary (onlined CPUs, local init etc.) */
8253 int rc = HMR0EnterCpu(pVCpu);
8254 AssertRC(rc);
8255 Assert(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE));
8256
8257 /* Load the active VMCS as the current one. */
8258 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_CLEAR)
8259 {
8260 rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
8261 AssertRC(rc); NOREF(rc);
8262 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
8263 Log4Func(("Resumed: Activated Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8264 }
8265 pVCpu->hm.s.fLeaveDone = false;
8266
8267 /* Restore longjmp state. */
8268 VMMRZCallRing3Enable(pVCpu);
8269 break;
8270 }
8271
8272 default:
8273 break;
8274 }
8275}
8276
8277
8278/**
8279 * Saves the host state in the VMCS host-state.
8280 * Sets up the VM-exit MSR-load area.
8281 *
8282 * The CPU state will be loaded from these fields on every successful VM-exit.
8283 *
8284 * @returns VBox status code.
8285 * @param pVM The cross context VM structure.
8286 * @param pVCpu The cross context virtual CPU structure.
8287 *
8288 * @remarks No-long-jump zone!!!
8289 */
8290static int hmR0VmxSaveHostState(PVM pVM, PVMCPU pVCpu)
8291{
8292 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8293
8294 int rc = VINF_SUCCESS;
8295 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT))
8296 {
8297 rc = hmR0VmxSaveHostControlRegs(pVM, pVCpu);
8298 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostControlRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8299
8300 rc = hmR0VmxSaveHostSegmentRegs(pVM, pVCpu);
8301 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostSegmentRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8302
8303 rc = hmR0VmxSaveHostMsrs(pVM, pVCpu);
8304 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostMsrs failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8305
8306 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_HOST_CONTEXT);
8307 }
8308 return rc;
8309}
8310
8311
8312/**
8313 * Saves the host state in the VMCS host-state.
8314 *
8315 * @returns VBox status code.
8316 * @param pVM The cross context VM structure.
8317 * @param pVCpu The cross context virtual CPU structure.
8318 *
8319 * @remarks No-long-jump zone!!!
8320 */
8321VMMR0DECL(int) VMXR0SaveHostState(PVM pVM, PVMCPU pVCpu)
8322{
8323 AssertPtr(pVM);
8324 AssertPtr(pVCpu);
8325
8326 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8327
8328 /* Save the host state here while entering HM context. When thread-context hooks are used, we might get preempted
8329 and have to resave the host state but most of the time we won't be, so do it here before we disable interrupts. */
8330 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8331 return hmR0VmxSaveHostState(pVM, pVCpu);
8332}
8333
8334
8335/**
8336 * Loads the guest state into the VMCS guest-state area.
8337 *
8338 * The will typically be done before VM-entry when the guest-CPU state and the
8339 * VMCS state may potentially be out of sync.
8340 *
8341 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
8342 * VM-entry controls.
8343 * Sets up the appropriate VMX non-root function to execute guest code based on
8344 * the guest CPU mode.
8345 *
8346 * @returns VBox strict status code.
8347 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8348 * without unrestricted guest access and the VMMDev is not presently
8349 * mapped (e.g. EFI32).
8350 *
8351 * @param pVM The cross context VM structure.
8352 * @param pVCpu The cross context virtual CPU structure.
8353 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8354 * out-of-sync. Make sure to update the required fields
8355 * before using them.
8356 *
8357 * @remarks No-long-jump zone!!! (Disables and enables long jmps for itself,
8358 * caller disables then again on successfull return. Confusing.)
8359 */
8360static VBOXSTRICTRC hmR0VmxLoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
8361{
8362 AssertPtr(pVM);
8363 AssertPtr(pVCpu);
8364 AssertPtr(pMixedCtx);
8365 HMVMX_ASSERT_PREEMPT_SAFE();
8366
8367 VMMRZCallRing3Disable(pVCpu);
8368 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8369
8370 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8371
8372 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestState, x);
8373
8374 /* Determine real-on-v86 mode. */
8375 pVCpu->hm.s.vmx.RealMode.fRealOnV86Active = false;
8376 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
8377 && CPUMIsGuestInRealModeEx(pMixedCtx))
8378 {
8379 pVCpu->hm.s.vmx.RealMode.fRealOnV86Active = true;
8380 }
8381
8382 /*
8383 * Load the guest-state into the VMCS.
8384 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
8385 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
8386 */
8387 int rc = hmR0VmxSetupVMRunHandler(pVCpu, pMixedCtx);
8388 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupVMRunHandler! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8389
8390 /* This needs to be done after hmR0VmxSetupVMRunHandler() as changing pfnStartVM may require VM-entry control updates. */
8391 rc = hmR0VmxLoadGuestEntryCtls(pVCpu, pMixedCtx);
8392 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestEntryCtls! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8393
8394 /* This needs to be done after hmR0VmxSetupVMRunHandler() as changing pfnStartVM may require VM-exit control updates. */
8395 rc = hmR0VmxLoadGuestExitCtls(pVCpu, pMixedCtx);
8396 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupExitCtls failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8397
8398 rc = hmR0VmxLoadGuestActivityState(pVCpu, pMixedCtx);
8399 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestActivityState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8400
8401 VBOXSTRICTRC rcStrict = hmR0VmxLoadGuestCR3AndCR4(pVCpu, pMixedCtx);
8402 if (rcStrict == VINF_SUCCESS)
8403 { /* likely */ }
8404 else
8405 {
8406 VMMRZCallRing3Enable(pVCpu);
8407 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
8408 return rcStrict;
8409 }
8410
8411 /* Assumes pMixedCtx->cr0 is up-to-date (strict builds require CR0 for segment register validation checks). */
8412 rc = hmR0VmxLoadGuestSegmentRegs(pVCpu, pMixedCtx);
8413 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestSegmentRegs: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8414
8415 /* This needs to be done after hmR0VmxLoadGuestEntryCtls() and hmR0VmxLoadGuestExitCtls() as it may alter controls if we
8416 determine we don't have to swap EFER after all. */
8417 rc = hmR0VmxLoadGuestMsrs(pVCpu, pMixedCtx);
8418 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadSharedMsrs! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8419
8420 rc = hmR0VmxLoadGuestApicState(pVCpu, pMixedCtx);
8421 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestApicState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8422
8423 rc = hmR0VmxLoadGuestXcptIntercepts(pVCpu, pMixedCtx);
8424 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestXcptIntercepts! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8425
8426 /*
8427 * Loading Rflags here is fine, even though Rflags.TF might depend on guest debug state (which is not loaded here).
8428 * It is re-evaluated and updated if necessary in hmR0VmxLoadSharedState().
8429 */
8430 rc = hmR0VmxLoadGuestRipRspRflags(pVCpu, pMixedCtx);
8431 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestRipRspRflags! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8432
8433 /* Clear any unused and reserved bits. */
8434 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR2);
8435
8436 VMMRZCallRing3Enable(pVCpu);
8437
8438 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
8439 return rc;
8440}
8441
8442
8443/**
8444 * Loads the state shared between the host and guest into the VMCS.
8445 *
8446 * @param pVM The cross context VM structure.
8447 * @param pVCpu The cross context virtual CPU structure.
8448 * @param pCtx Pointer to the guest-CPU context.
8449 *
8450 * @remarks No-long-jump zone!!!
8451 */
8452static void hmR0VmxLoadSharedState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
8453{
8454 NOREF(pVM);
8455
8456 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8457 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8458
8459 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
8460 {
8461 int rc = hmR0VmxLoadSharedCR0(pVCpu, pCtx);
8462 AssertRC(rc);
8463 }
8464
8465 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_DEBUG))
8466 {
8467 int rc = hmR0VmxLoadSharedDebugState(pVCpu, pCtx);
8468 AssertRC(rc);
8469
8470 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
8471 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RFLAGS))
8472 {
8473 rc = hmR0VmxLoadGuestRflags(pVCpu, pCtx);
8474 AssertRC(rc);
8475 }
8476 }
8477
8478 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS))
8479 {
8480 hmR0VmxLazyLoadGuestMsrs(pVCpu, pCtx);
8481 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS);
8482 }
8483
8484 /* Loading CR0, debug state might have changed intercepts, update VMCS. */
8485 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
8486 {
8487 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_AC));
8488 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
8489 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
8490 AssertRC(rc);
8491 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
8492 }
8493
8494 AssertMsg(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE),
8495 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8496}
8497
8498
8499/**
8500 * Worker for loading the guest-state bits in the inner VT-x execution loop.
8501 *
8502 * @returns Strict VBox status code (i.e. informational status codes too).
8503 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8504 * without unrestricted guest access and the VMMDev is not presently
8505 * mapped (e.g. EFI32).
8506 *
8507 * @param pVM The cross context VM structure.
8508 * @param pVCpu The cross context virtual CPU structure.
8509 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8510 * out-of-sync. Make sure to update the required fields
8511 * before using them.
8512 */
8513static VBOXSTRICTRC hmR0VmxLoadGuestStateOptimal(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
8514{
8515 HMVMX_ASSERT_PREEMPT_SAFE();
8516
8517 Log5(("LoadFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8518#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
8519 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
8520#endif
8521
8522 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
8523 if (HMCPU_CF_IS_SET_ONLY(pVCpu, HM_CHANGED_GUEST_RIP))
8524 {
8525 rcStrict = hmR0VmxLoadGuestRip(pVCpu, pMixedCtx);
8526 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8527 { /* likely */}
8528 else
8529 {
8530 AssertMsgFailedReturn(("hmR0VmxLoadGuestStateOptimal: hmR0VmxLoadGuestRip failed! rc=%Rrc\n",
8531 VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
8532 }
8533 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadMinimal);
8534 }
8535 else if (HMCPU_CF_VALUE(pVCpu))
8536 {
8537 rcStrict = hmR0VmxLoadGuestState(pVM, pVCpu, pMixedCtx);
8538 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8539 { /* likely */}
8540 else
8541 {
8542 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM,
8543 ("hmR0VmxLoadGuestStateOptimal: hmR0VmxLoadGuestState failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8544 return rcStrict;
8545 }
8546 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadFull);
8547 }
8548
8549 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
8550 AssertMsg( !HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_ALL_GUEST)
8551 || HMCPU_CF_IS_PENDING_ONLY(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE),
8552 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8553 return rcStrict;
8554}
8555
8556
8557/**
8558 * Does the preparations before executing guest code in VT-x.
8559 *
8560 * This may cause longjmps to ring-3 and may even result in rescheduling to the
8561 * recompiler/IEM. We must be cautious what we do here regarding committing
8562 * guest-state information into the VMCS assuming we assuredly execute the
8563 * guest in VT-x mode.
8564 *
8565 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
8566 * the common-state (TRPM/forceflags), we must undo those changes so that the
8567 * recompiler/IEM can (and should) use them when it resumes guest execution.
8568 * Otherwise such operations must be done when we can no longer exit to ring-3.
8569 *
8570 * @returns Strict VBox status code (i.e. informational status codes too).
8571 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
8572 * have been disabled.
8573 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
8574 * double-fault into the guest.
8575 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
8576 * dispatched directly.
8577 * @retval VINF_* scheduling changes, we have to go back to ring-3.
8578 *
8579 * @param pVM The cross context VM structure.
8580 * @param pVCpu The cross context virtual CPU structure.
8581 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8582 * out-of-sync. Make sure to update the required fields
8583 * before using them.
8584 * @param pVmxTransient Pointer to the VMX transient structure.
8585 * @param fStepping Set if called from hmR0VmxRunGuestCodeStep(). Makes
8586 * us ignore some of the reasons for returning to
8587 * ring-3, and return VINF_EM_DBG_STEPPED if event
8588 * dispatching took place.
8589 */
8590static VBOXSTRICTRC hmR0VmxPreRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, bool fStepping)
8591{
8592 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8593
8594#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
8595 PGMRZDynMapFlushAutoSet(pVCpu);
8596#endif
8597
8598 /* Check force flag actions that might require us to go back to ring-3. */
8599 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVM, pVCpu, pMixedCtx, fStepping);
8600 if (rcStrict == VINF_SUCCESS)
8601 { /* FFs doesn't get set all the time. */ }
8602 else
8603 return rcStrict;
8604
8605 /** @todo r=ramshankar: Why can't we do this when the APIC base changes
8606 * in hmR0VmxLoadGuestApicState()? Also we can stop caching the
8607 * APIC base in several places just for HM usage and just take the
8608 * function call hit in load-guest state. */
8609#ifndef IEM_VERIFICATION_MODE_FULL
8610 /* Setup the Virtualized APIC accesses. pMixedCtx->msrApicBase is always up-to-date. It's not part of the VMCS. */
8611 if ( pVCpu->hm.s.vmx.u64MsrApicBase != pMixedCtx->msrApicBase
8612 && (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC))
8613 {
8614 Assert(pVM->hm.s.vmx.HCPhysApicAccess);
8615 RTGCPHYS GCPhysApicBase;
8616 GCPhysApicBase = pMixedCtx->msrApicBase;
8617 GCPhysApicBase &= PAGE_BASE_GC_MASK;
8618
8619 /* Unalias any existing mapping. */
8620 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
8621 AssertRCReturn(rc, rc);
8622
8623 /* Map the HC APIC-access page into the GC space, this also updates the shadow page tables if necessary. */
8624 Log4(("Mapped HC APIC-access page into GC: GCPhysApicBase=%#RGp\n", GCPhysApicBase));
8625 rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
8626 AssertRCReturn(rc, rc);
8627
8628 pVCpu->hm.s.vmx.u64MsrApicBase = pMixedCtx->msrApicBase;
8629 }
8630#endif /* !IEM_VERIFICATION_MODE_FULL */
8631
8632 if (TRPMHasTrap(pVCpu))
8633 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
8634 uint32_t uIntrState = hmR0VmxEvaluatePendingEvent(pVCpu, pMixedCtx);
8635
8636 /*
8637 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus needs to be done with
8638 * longjmps or interrupts + preemption enabled. Event injection might also result in triple-faulting the VM.
8639 */
8640 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx, uIntrState, fStepping);
8641 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8642 { /* likely */ }
8643 else
8644 {
8645 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8646 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8647 return rcStrict;
8648 }
8649
8650 /*
8651 * Load the guest state bits, we can handle longjmps/getting preempted here.
8652 *
8653 * If we are injecting events to a real-on-v86 mode guest, we will have to update
8654 * RIP and some segment registers, i.e. hmR0VmxInjectPendingEvent()->hmR0VmxInjectEventVmcs().
8655 * Hence, this needs to be done -after- injection of events.
8656 */
8657 rcStrict = hmR0VmxLoadGuestStateOptimal(pVM, pVCpu, pMixedCtx);
8658 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8659 { /* likely */ }
8660 else
8661 return rcStrict;
8662
8663 /*
8664 * No longjmps to ring-3 from this point on!!!
8665 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
8666 * This also disables flushing of the R0-logger instance (if any).
8667 */
8668 VMMRZCallRing3Disable(pVCpu);
8669
8670 /*
8671 * We disable interrupts so that we don't miss any interrupts that would flag preemption (IPI/timers etc.)
8672 * when thread-context hooks aren't used and we've been running with preemption disabled for a while.
8673 *
8674 * We need to check for force-flags that could've possible been altered since we last checked them (e.g.
8675 * by PDMGetInterrupt() leaving the PDM critical section, see @bugref{6398}).
8676 *
8677 * We also check a couple of other force-flags as a last opportunity to get the EMT back to ring-3 before
8678 * executing guest code.
8679 */
8680 pVmxTransient->fEFlags = ASMIntDisableFlags();
8681
8682 if ( ( !VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
8683 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
8684 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
8685 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
8686 {
8687 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
8688 {
8689 /* We've injected any pending events. This is really the point of no return (to ring-3). */
8690 pVCpu->hm.s.Event.fPending = false;
8691
8692 return VINF_SUCCESS;
8693 }
8694
8695 STAM_COUNTER_INC(&pVCpu->hm.s.StatPendingHostIrq);
8696 rcStrict = VINF_EM_RAW_INTERRUPT;
8697 }
8698 else
8699 {
8700 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
8701 rcStrict = VINF_EM_RAW_TO_R3;
8702 }
8703
8704 ASMSetFlags(pVmxTransient->fEFlags);
8705 VMMRZCallRing3Enable(pVCpu);
8706
8707 return rcStrict;
8708}
8709
8710
8711/**
8712 * Prepares to run guest code in VT-x and we've committed to doing so. This
8713 * means there is no backing out to ring-3 or anywhere else at this
8714 * point.
8715 *
8716 * @param pVM The cross context VM structure.
8717 * @param pVCpu The cross context virtual CPU structure.
8718 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8719 * out-of-sync. Make sure to update the required fields
8720 * before using them.
8721 * @param pVmxTransient Pointer to the VMX transient structure.
8722 *
8723 * @remarks Called with preemption disabled.
8724 * @remarks No-long-jump zone!!!
8725 */
8726static void hmR0VmxPreRunGuestCommitted(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8727{
8728 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8729 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8730 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8731
8732 /*
8733 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
8734 */
8735 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
8736 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
8737
8738#ifdef HMVMX_ALWAYS_SWAP_FPU_STATE
8739 if (!CPUMIsGuestFPUStateActive(pVCpu))
8740 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
8741 HMCPU_CF_SET(pVCpu, HM_CHANGED_HOST_CONTEXT);
8742 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
8743#endif
8744
8745 if ( pVCpu->hm.s.fPreloadGuestFpu
8746 && !CPUMIsGuestFPUStateActive(pVCpu))
8747 {
8748 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
8749 HMCPU_CF_SET(pVCpu, HM_CHANGED_HOST_CONTEXT);
8750 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
8751 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
8752 }
8753
8754 /*
8755 * Lazy-update of the host MSRs values in the auto-load/store MSR area.
8756 */
8757 if ( !pVCpu->hm.s.vmx.fUpdatedHostMsrs
8758 && pVCpu->hm.s.vmx.cMsrs > 0)
8759 {
8760 hmR0VmxUpdateAutoLoadStoreHostMsrs(pVCpu);
8761 }
8762
8763 /*
8764 * Load the host state bits as we may've been preempted (only happens when
8765 * thread-context hooks are used or when hmR0VmxSetupVMRunHandler() changes pfnStartVM).
8766 * Note that the 64-on-32 switcher saves the (64-bit) host state into the VMCS and
8767 * if we change the switcher back to 32-bit, we *must* save the 32-bit host state here.
8768 * See @bugref{8432}.
8769 */
8770 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT))
8771 {
8772 int rc = hmR0VmxSaveHostState(pVM, pVCpu);
8773 AssertRC(rc);
8774 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreemptSaveHostState);
8775 }
8776 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT));
8777
8778 /*
8779 * Load the state shared between host and guest (FPU, debug, lazy MSRs).
8780 */
8781 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE))
8782 hmR0VmxLoadSharedState(pVM, pVCpu, pMixedCtx);
8783 AssertMsg(!HMCPU_CF_VALUE(pVCpu), ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8784
8785 /* Store status of the shared guest-host state at the time of VM-entry. */
8786#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
8787 if (CPUMIsGuestInLongModeEx(pMixedCtx))
8788 {
8789 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActivePending(pVCpu);
8790 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActivePending(pVCpu);
8791 }
8792 else
8793#endif
8794 {
8795 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
8796 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
8797 }
8798 pVmxTransient->fWasGuestFPUStateActive = CPUMIsGuestFPUStateActive(pVCpu);
8799
8800 /*
8801 * Cache the TPR-shadow for checking on every VM-exit if it might have changed.
8802 */
8803 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
8804 pVmxTransient->u8GuestTpr = pVCpu->hm.s.vmx.pbVirtApic[0x80];
8805
8806 PHMGLOBALCPUINFO pCpu = HMR0GetCurrentCpu();
8807 RTCPUID idCurrentCpu = pCpu->idCpu;
8808 if ( pVmxTransient->fUpdateTscOffsettingAndPreemptTimer
8809 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
8810 {
8811 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVM, pVCpu);
8812 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = false;
8813 }
8814
8815 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
8816 hmR0VmxFlushTaggedTlb(pVCpu, pCpu); /* Invalidate the appropriate guest entries from the TLB. */
8817 Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
8818 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Update the error reporting info. with the current host CPU. */
8819
8820 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
8821
8822 TMNotifyStartOfExecution(pVCpu); /* Finally, notify TM to resume its clocks as we're about
8823 to start executing. */
8824
8825 /*
8826 * Load the TSC_AUX MSR when we are not intercepting RDTSCP.
8827 */
8828 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP)
8829 {
8830 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
8831 {
8832 bool fMsrUpdated;
8833 int rc2 = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
8834 AssertRC(rc2);
8835 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS));
8836
8837 rc2 = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_TSC_AUX, CPUMR0GetGuestTscAux(pVCpu), true /* fUpdateHostMsr */,
8838 &fMsrUpdated);
8839 AssertRC(rc2);
8840 Assert(fMsrUpdated || pVCpu->hm.s.vmx.fUpdatedHostMsrs);
8841
8842 /* Finally, mark that all host MSR values are updated so we don't redo it without leaving VT-x. See @bugref{6956}. */
8843 pVCpu->hm.s.vmx.fUpdatedHostMsrs = true;
8844 }
8845 else
8846 {
8847 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, MSR_K8_TSC_AUX);
8848 Assert(!pVCpu->hm.s.vmx.cMsrs || pVCpu->hm.s.vmx.fUpdatedHostMsrs);
8849 }
8850 }
8851
8852#ifdef VBOX_STRICT
8853 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu);
8854 hmR0VmxCheckHostEferMsr(pVCpu);
8855 AssertRC(hmR0VmxCheckVmcsCtls(pVCpu));
8856#endif
8857#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
8858 uint32_t uInvalidReason = hmR0VmxCheckGuestState(pVM, pVCpu, pMixedCtx);
8859 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
8860 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
8861#endif
8862}
8863
8864
8865/**
8866 * Performs some essential restoration of state after running guest code in
8867 * VT-x.
8868 *
8869 * @param pVM The cross context VM structure.
8870 * @param pVCpu The cross context virtual CPU structure.
8871 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
8872 * out-of-sync. Make sure to update the required fields
8873 * before using them.
8874 * @param pVmxTransient Pointer to the VMX transient structure.
8875 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
8876 *
8877 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
8878 *
8879 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
8880 * unconditionally when it is safe to do so.
8881 */
8882static void hmR0VmxPostRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, int rcVMRun)
8883{
8884 NOREF(pVM);
8885
8886 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8887
8888 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
8889 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
8890 HMVMXCPU_GST_RESET_TO(pVCpu, 0); /* Exits/longjmps to ring-3 requires saving the guest state. */
8891 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
8892 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
8893 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
8894
8895 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
8896 TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVCpu->hm.s.vmx.u64TSCOffset);
8897
8898 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatExit1, x);
8899 TMNotifyEndOfExecution(pVCpu); /* Notify TM that the guest is no longer running. */
8900 Assert(!ASMIntAreEnabled());
8901 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
8902
8903#ifdef HMVMX_ALWAYS_SWAP_FPU_STATE
8904 if (CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVM, pVCpu))
8905 {
8906 hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
8907 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
8908 }
8909#endif
8910
8911#if HC_ARCH_BITS == 64
8912 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Host state messed up by VT-x, we must restore. */
8913#endif
8914#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
8915 /* The 64-on-32 switcher maintains uVmcsState on its own and we need to leave it alone here. */
8916 if (pVCpu->hm.s.vmx.pfnStartVM != VMXR0SwitcherStartVM64)
8917 pVCpu->hm.s.vmx.uVmcsState |= HMVMX_VMCS_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
8918#else
8919 pVCpu->hm.s.vmx.uVmcsState |= HMVMX_VMCS_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
8920#endif
8921#ifdef VBOX_STRICT
8922 hmR0VmxCheckHostEferMsr(pVCpu); /* Verify that VMRUN/VMLAUNCH didn't modify host EFER. */
8923#endif
8924 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
8925 VMMRZCallRing3Enable(pVCpu); /* It is now safe to do longjmps to ring-3!!! */
8926
8927 /* Save the basic VM-exit reason. Refer Intel spec. 24.9.1 "Basic VM-exit Information". */
8928 uint32_t uExitReason;
8929 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8930 rc |= hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
8931 AssertRC(rc);
8932 pVmxTransient->uExitReason = (uint16_t)VMX_EXIT_REASON_BASIC(uExitReason);
8933 pVmxTransient->fVMEntryFailed = VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uEntryIntInfo);
8934
8935 /* Update the VM-exit history array. */
8936 HMCPU_EXIT_HISTORY_ADD(pVCpu, pVmxTransient->uExitReason);
8937
8938 /* If the VMLAUNCH/VMRESUME failed, we can bail out early. This does -not- cover VMX_EXIT_ERR_*. */
8939 if (RT_UNLIKELY(rcVMRun != VINF_SUCCESS))
8940 {
8941 Log4(("VM-entry failure: pVCpu=%p idCpu=%RU32 rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", pVCpu, pVCpu->idCpu, rcVMRun,
8942 pVmxTransient->fVMEntryFailed));
8943 return;
8944 }
8945
8946 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
8947 {
8948 /** @todo We can optimize this by only syncing with our force-flags when
8949 * really needed and keeping the VMCS state as it is for most
8950 * VM-exits. */
8951 /* Update the guest interruptibility-state from the VMCS. */
8952 hmR0VmxSaveGuestIntrState(pVCpu, pMixedCtx);
8953
8954#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
8955 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
8956 AssertRC(rc);
8957#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
8958 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
8959 AssertRC(rc);
8960#endif
8961
8962 /*
8963 * If the TPR was raised by the guest, it wouldn't cause a VM-exit immediately. Instead we sync the TPR lazily whenever
8964 * we eventually get a VM-exit for any reason.
8965 *
8966 * This maybe expensive as PDMApicSetTPR() can longjmp to ring-3 and which is why it's done here as it's easier and
8967 * no less efficient to deal with it here than making hmR0VmxSaveGuestState() cope with longjmps safely
8968 * (see VMCPU_FF_HM_UPDATE_CR3 handling).
8969 */
8970 /** @todo r=ramshankar: The 2nd para in the above comment is
8971 * outdated, we no longer longjmp to ring-3 on setting
8972 * the TPR, but regardless we can probably rework this
8973 * portion of the code a bit. */
8974 if ( (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
8975 && pVmxTransient->u8GuestTpr != pVCpu->hm.s.vmx.pbVirtApic[0x80])
8976 {
8977 rc = APICSetTpr(pVCpu, pVCpu->hm.s.vmx.pbVirtApic[0x80]);
8978 AssertRC(rc);
8979 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
8980 }
8981 }
8982}
8983
8984
8985/**
8986 * Runs the guest code using VT-x the normal way.
8987 *
8988 * @returns VBox status code.
8989 * @param pVM The cross context VM structure.
8990 * @param pVCpu The cross context virtual CPU structure.
8991 * @param pCtx Pointer to the guest-CPU context.
8992 *
8993 * @note Mostly the same as hmR0VmxRunGuestCodeStep().
8994 */
8995static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
8996{
8997 VMXTRANSIENT VmxTransient;
8998 VmxTransient.fUpdateTscOffsettingAndPreemptTimer = true;
8999 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
9000 uint32_t cLoops = 0;
9001
9002 for (;; cLoops++)
9003 {
9004 Assert(!HMR0SuspendPending());
9005 HMVMX_ASSERT_CPU_SAFE();
9006
9007 /* Preparatory work for running guest code, this may force us to return
9008 to ring-3. This bugger disables interrupts on VINF_SUCCESS! */
9009 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
9010 rcStrict = hmR0VmxPreRunGuest(pVM, pVCpu, pCtx, &VmxTransient, false /* fStepping */);
9011 if (rcStrict != VINF_SUCCESS)
9012 break;
9013
9014 hmR0VmxPreRunGuestCommitted(pVM, pVCpu, pCtx, &VmxTransient);
9015 int rcRun = hmR0VmxRunGuest(pVM, pVCpu, pCtx);
9016 /* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
9017
9018 /* Restore any residual host-state and save any bits shared between host
9019 and guest into the guest-CPU state. Re-enables interrupts! */
9020 hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, VBOXSTRICTRC_TODO(rcStrict));
9021
9022 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
9023 if (RT_SUCCESS(rcRun))
9024 { /* very likely */ }
9025 else
9026 {
9027 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
9028 hmR0VmxReportWorldSwitchError(pVM, pVCpu, rcRun, pCtx, &VmxTransient);
9029 return rcRun;
9030 }
9031
9032 /* Profile the VM-exit. */
9033 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
9034 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
9035 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
9036 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
9037 HMVMX_START_EXIT_DISPATCH_PROF();
9038
9039 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, pCtx, VmxTransient.uExitReason);
9040
9041 /* Handle the VM-exit. */
9042#ifdef HMVMX_USE_FUNCTION_TABLE
9043 rcStrict = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, pCtx, &VmxTransient);
9044#else
9045 rcStrict = hmR0VmxHandleExit(pVCpu, pCtx, &VmxTransient, VmxTransient.uExitReason);
9046#endif
9047 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
9048 if (rcStrict == VINF_SUCCESS)
9049 {
9050 if (cLoops <= pVM->hm.s.cMaxResumeLoops)
9051 continue; /* likely */
9052 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
9053 rcStrict = VINF_EM_RAW_INTERRUPT;
9054 }
9055 break;
9056 }
9057
9058 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
9059 return rcStrict;
9060}
9061
9062
9063
9064/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
9065 * probes.
9066 *
9067 * The following few functions and associated structure contains the bloat
9068 * necessary for providing detailed debug events and dtrace probes as well as
9069 * reliable host side single stepping. This works on the principle of
9070 * "subclassing" the normal execution loop and workers. We replace the loop
9071 * method completely and override selected helpers to add necessary adjustments
9072 * to their core operation.
9073 *
9074 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
9075 * any performance for debug and analysis features.
9076 *
9077 * @{
9078 */
9079
9080typedef struct VMXRUNDBGSTATE
9081{
9082 /** The RIP we started executing at. This is for detecting that we stepped. */
9083 uint64_t uRipStart;
9084 /** The CS we started executing with. */
9085 uint16_t uCsStart;
9086
9087 /** Whether we've actually modified the 1st execution control field. */
9088 bool fModifiedProcCtls : 1;
9089 /** Whether we've actually modified the 2nd execution control field. */
9090 bool fModifiedProcCtls2 : 1;
9091 /** Whether we've actually modified the exception bitmap. */
9092 bool fModifiedXcptBitmap : 1;
9093
9094 /** We desire the modified the CR0 mask to be cleared. */
9095 bool fClearCr0Mask : 1;
9096 /** We desire the modified the CR4 mask to be cleared. */
9097 bool fClearCr4Mask : 1;
9098 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
9099 uint32_t fCpe1Extra;
9100 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
9101 uint32_t fCpe1Unwanted;
9102 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
9103 uint32_t fCpe2Extra;
9104 /** Extra stuff we need in */
9105 uint32_t bmXcptExtra;
9106 /** The sequence number of the Dtrace provider settings the state was
9107 * configured against. */
9108 uint32_t uDtraceSettingsSeqNo;
9109 /** Exits to check (one bit per exit). */
9110 uint32_t bmExitsToCheck[3];
9111
9112 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
9113 uint32_t fProcCtlsInitial;
9114 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
9115 uint32_t fProcCtls2Initial;
9116 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
9117 uint32_t bmXcptInitial;
9118} VMXRUNDBGSTATE;
9119AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
9120typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
9121
9122
9123/**
9124 * Initializes the VMXRUNDBGSTATE structure.
9125 *
9126 * @param pVCpu The cross context virtual CPU structure of the
9127 * calling EMT.
9128 * @param pCtx The CPU register context to go with @a pVCpu.
9129 * @param pDbgState The structure to initialize.
9130 */
9131DECLINLINE(void) hmR0VmxRunDebugStateInit(PVMCPU pVCpu, PCCPUMCTX pCtx, PVMXRUNDBGSTATE pDbgState)
9132{
9133 pDbgState->uRipStart = pCtx->rip;
9134 pDbgState->uCsStart = pCtx->cs.Sel;
9135
9136 pDbgState->fModifiedProcCtls = false;
9137 pDbgState->fModifiedProcCtls2 = false;
9138 pDbgState->fModifiedXcptBitmap = false;
9139 pDbgState->fClearCr0Mask = false;
9140 pDbgState->fClearCr4Mask = false;
9141 pDbgState->fCpe1Extra = 0;
9142 pDbgState->fCpe1Unwanted = 0;
9143 pDbgState->fCpe2Extra = 0;
9144 pDbgState->bmXcptExtra = 0;
9145 pDbgState->fProcCtlsInitial = pVCpu->hm.s.vmx.u32ProcCtls;
9146 pDbgState->fProcCtls2Initial = pVCpu->hm.s.vmx.u32ProcCtls2;
9147 pDbgState->bmXcptInitial = pVCpu->hm.s.vmx.u32XcptBitmap;
9148}
9149
9150
9151/**
9152 * Updates the VMSC fields with changes requested by @a pDbgState.
9153 *
9154 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
9155 * immediately before executing guest code, i.e. when interrupts are disabled.
9156 * We don't check status codes here as we cannot easily assert or return in the
9157 * latter case.
9158 *
9159 * @param pVCpu The cross context virtual CPU structure.
9160 * @param pDbgState The debug state.
9161 */
9162DECLINLINE(void) hmR0VmxPreRunGuestDebugStateApply(PVMCPU pVCpu, PVMXRUNDBGSTATE pDbgState)
9163{
9164 /*
9165 * Ensure desired flags in VMCS control fields are set.
9166 * (Ignoring write failure here, as we're committed and it's just debug extras.)
9167 *
9168 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
9169 * there should be no stale data in pCtx at this point.
9170 */
9171 if ( (pVCpu->hm.s.vmx.u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
9172 || (pVCpu->hm.s.vmx.u32ProcCtls & pDbgState->fCpe1Unwanted))
9173 {
9174 pVCpu->hm.s.vmx.u32ProcCtls |= pDbgState->fCpe1Extra;
9175 pVCpu->hm.s.vmx.u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
9176 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
9177 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVCpu->hm.s.vmx.u32ProcCtls));
9178 pDbgState->fModifiedProcCtls = true;
9179 }
9180
9181 if ((pVCpu->hm.s.vmx.u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
9182 {
9183 pVCpu->hm.s.vmx.u32ProcCtls2 |= pDbgState->fCpe2Extra;
9184 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVCpu->hm.s.vmx.u32ProcCtls2);
9185 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVCpu->hm.s.vmx.u32ProcCtls2));
9186 pDbgState->fModifiedProcCtls2 = true;
9187 }
9188
9189 if ((pVCpu->hm.s.vmx.u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
9190 {
9191 pVCpu->hm.s.vmx.u32XcptBitmap |= pDbgState->bmXcptExtra;
9192 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
9193 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVCpu->hm.s.vmx.u32XcptBitmap));
9194 pDbgState->fModifiedXcptBitmap = true;
9195 }
9196
9197 if (pDbgState->fClearCr0Mask && pVCpu->hm.s.vmx.u32CR0Mask != 0)
9198 {
9199 pVCpu->hm.s.vmx.u32CR0Mask = 0;
9200 VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_MASK, 0);
9201 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS_CTRL_CR0_MASK: 0\n"));
9202 }
9203
9204 if (pDbgState->fClearCr4Mask && pVCpu->hm.s.vmx.u32CR4Mask != 0)
9205 {
9206 pVCpu->hm.s.vmx.u32CR4Mask = 0;
9207 VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_MASK, 0);
9208 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS_CTRL_CR4_MASK: 0\n"));
9209 }
9210}
9211
9212
9213DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugStateRevert(PVMCPU pVCpu, PVMXRUNDBGSTATE pDbgState, VBOXSTRICTRC rcStrict)
9214{
9215 /*
9216 * Restore exit control settings as we may not reenter this function the
9217 * next time around.
9218 */
9219 /* We reload the initial value, trigger what we can of recalculations the
9220 next time around. From the looks of things, that's all that's required atm. */
9221 if (pDbgState->fModifiedProcCtls)
9222 {
9223 if (!(pDbgState->fProcCtlsInitial & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
9224 pDbgState->fProcCtlsInitial |= VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
9225 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
9226 AssertRCReturn(rc2, rc2);
9227 pVCpu->hm.s.vmx.u32ProcCtls = pDbgState->fProcCtlsInitial;
9228 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0 | HM_CHANGED_GUEST_DEBUG);
9229 }
9230
9231 /* We're currently the only ones messing with this one, so just restore the
9232 cached value and reload the field. */
9233 if ( pDbgState->fModifiedProcCtls2
9234 && pVCpu->hm.s.vmx.u32ProcCtls2 != pDbgState->fProcCtls2Initial)
9235 {
9236 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
9237 AssertRCReturn(rc2, rc2);
9238 pVCpu->hm.s.vmx.u32ProcCtls2 = pDbgState->fProcCtls2Initial;
9239 }
9240
9241 /* If we've modified the exception bitmap, we restore it and trigger
9242 reloading and partial recalculation the next time around. */
9243 if (pDbgState->fModifiedXcptBitmap)
9244 {
9245 pVCpu->hm.s.vmx.u32XcptBitmap = pDbgState->bmXcptInitial;
9246 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS | HM_CHANGED_GUEST_CR0);
9247 }
9248
9249 /* We assume hmR0VmxLoadSharedCR0 will recalculate and load the CR0 mask. */
9250 if (pDbgState->fClearCr0Mask)
9251 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9252
9253 /* We assume hmR0VmxLoadGuestCR3AndCR4 will recalculate and load the CR4 mask. */
9254 if (pDbgState->fClearCr4Mask)
9255 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
9256
9257 return rcStrict;
9258}
9259
9260
9261/**
9262 * Configures VM-exit controls for current DBGF and DTrace settings.
9263 *
9264 * This updates @a pDbgState and the VMCS execution control fields to reflect
9265 * the necessary exits demanded by DBGF and DTrace.
9266 *
9267 * @param pVM The cross context VM structure.
9268 * @param pVCpu The cross context virtual CPU structure.
9269 * @param pCtx Pointer to the guest-CPU context.
9270 * @param pDbgState The debug state.
9271 * @param pVmxTransient Pointer to the VMX transient structure. May update
9272 * fUpdateTscOffsettingAndPreemptTimer.
9273 */
9274static void hmR0VmxPreRunGuestDebugStateUpdate(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx,
9275 PVMXRUNDBGSTATE pDbgState, PVMXTRANSIENT pVmxTransient)
9276{
9277 /*
9278 * Take down the dtrace serial number so we can spot changes.
9279 */
9280 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
9281 ASMCompilerBarrier();
9282
9283 /*
9284 * We'll rebuild most of the middle block of data members (holding the
9285 * current settings) as we go along here, so start by clearing it all.
9286 */
9287 pDbgState->bmXcptExtra = 0;
9288 pDbgState->fCpe1Extra = 0;
9289 pDbgState->fCpe1Unwanted = 0;
9290 pDbgState->fCpe2Extra = 0;
9291 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
9292 pDbgState->bmExitsToCheck[i] = 0;
9293
9294 /*
9295 * Software interrupts (INT XXh) - no idea how to trigger these...
9296 */
9297 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
9298 || VBOXVMM_INT_SOFTWARE_ENABLED())
9299 {
9300 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
9301 }
9302
9303 /*
9304 * Exception bitmap and XCPT events+probes.
9305 */
9306 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
9307 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
9308 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
9309
9310 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
9311 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
9312 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
9313 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
9314 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
9315 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
9316 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
9317 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
9318 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
9319 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
9320 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
9321 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
9322 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
9323 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
9324 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
9325 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
9326 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
9327 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
9328
9329 if (pDbgState->bmXcptExtra)
9330 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
9331
9332 /*
9333 * Process events and probes for VM exits, making sure we get the wanted exits.
9334 *
9335 * Note! This is the reverse of waft hmR0VmxHandleExitDtraceEvents does.
9336 * So, when adding/changing/removing please don't forget to update it.
9337 *
9338 * Some of the macros are picking up local variables to save horizontal space,
9339 * (being able to see it in a table is the lesser evil here).
9340 */
9341#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
9342 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
9343 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
9344#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
9345 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9346 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9347 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9348 } else do { } while (0)
9349#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
9350 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9351 { \
9352 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
9353 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9354 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9355 } else do { } while (0)
9356#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
9357 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9358 { \
9359 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
9360 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9361 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9362 } else do { } while (0)
9363#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
9364 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9365 { \
9366 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
9367 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9368 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9369 } else do { } while (0)
9370
9371 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
9372 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
9373 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
9374 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
9375 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
9376
9377 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
9378 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
9379 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
9380 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
9381 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT); /* paranoia */
9382 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
9383 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
9384 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
9385 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT);
9386 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
9387 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_VMCS_CTRL_PROC_EXEC_RDPMC_EXIT);
9388 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
9389 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT);
9390 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
9391 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
9392 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
9393 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
9394 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
9395 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
9396 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
9397 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
9398 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
9399 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
9400 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
9401 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
9402 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
9403 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
9404 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
9405 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
9406 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
9407 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
9408 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
9409 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
9410 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
9411 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
9412 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
9413
9414 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
9415 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
9416 {
9417 int rc2 = hmR0VmxSaveGuestCR0(pVCpu, pCtx);
9418 rc2 |= hmR0VmxSaveGuestCR4(pVCpu, pCtx);
9419 rc2 |= hmR0VmxSaveGuestApicState(pVCpu, pCtx);
9420 AssertRC(rc2);
9421
9422#if 0 /** @todo fix me */
9423 pDbgState->fClearCr0Mask = true;
9424 pDbgState->fClearCr4Mask = true;
9425#endif
9426 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
9427 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT | VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT;
9428 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
9429 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT | VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT;
9430 pDbgState->fCpe1Unwanted |= VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW; /* risky? */
9431 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
9432 require clearing here and in the loop if we start using it. */
9433 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
9434 }
9435 else
9436 {
9437 if (pDbgState->fClearCr0Mask)
9438 {
9439 pDbgState->fClearCr0Mask = false;
9440 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9441 }
9442 if (pDbgState->fClearCr4Mask)
9443 {
9444 pDbgState->fClearCr4Mask = false;
9445 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
9446 }
9447 }
9448 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
9449 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
9450
9451 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
9452 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
9453 {
9454 /** @todo later, need to fix handler as it assumes this won't usually happen. */
9455 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
9456 }
9457 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
9458 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
9459
9460 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS); /* risky clearing this? */
9461 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
9462 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS);
9463 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
9464 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_VMCS_CTRL_PROC_EXEC_MWAIT_EXIT); /* paranoia */
9465 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
9466 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_VMCS_CTRL_PROC_EXEC_MONITOR_EXIT); /* paranoia */
9467 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
9468#if 0 /** @todo too slow, fix handler. */
9469 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_VMCS_CTRL_PROC_EXEC_PAUSE_EXIT);
9470#endif
9471 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
9472
9473 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
9474 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
9475 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
9476 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
9477 {
9478 pDbgState->fCpe2Extra |= VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT;
9479 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XDTR_ACCESS);
9480 }
9481 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_XDTR_ACCESS);
9482 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_XDTR_ACCESS);
9483 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_XDTR_ACCESS);
9484 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_XDTR_ACCESS);
9485
9486 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
9487 || IS_EITHER_ENABLED(pVM, INSTR_STR)
9488 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
9489 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
9490 {
9491 pDbgState->fCpe2Extra |= VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT;
9492 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_TR_ACCESS);
9493 }
9494 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_TR_ACCESS);
9495 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_TR_ACCESS);
9496 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_TR_ACCESS);
9497 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_TR_ACCESS);
9498
9499 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
9500 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
9501 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT);
9502 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
9503 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
9504 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
9505 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT);
9506 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
9507 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
9508 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
9509 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT);
9510 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
9511 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT);
9512 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
9513 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
9514 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
9515 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_VMCS_CTRL_PROC_EXEC2_RDSEED_EXIT);
9516 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
9517 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
9518 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
9519 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
9520 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
9521
9522#undef IS_EITHER_ENABLED
9523#undef SET_ONLY_XBM_IF_EITHER_EN
9524#undef SET_CPE1_XBM_IF_EITHER_EN
9525#undef SET_CPEU_XBM_IF_EITHER_EN
9526#undef SET_CPE2_XBM_IF_EITHER_EN
9527
9528 /*
9529 * Sanitize the control stuff.
9530 */
9531 pDbgState->fCpe2Extra &= pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1;
9532 if (pDbgState->fCpe2Extra)
9533 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL;
9534 pDbgState->fCpe1Extra &= pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1;
9535 pDbgState->fCpe1Unwanted &= ~pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0;
9536 if (pVCpu->hm.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
9537 {
9538 pVCpu->hm.s.fDebugWantRdTscExit ^= true;
9539 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
9540 }
9541
9542 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
9543 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
9544 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
9545 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
9546}
9547
9548
9549/**
9550 * Fires off DBGF events and dtrace probes for an exit, when it's appropriate.
9551 *
9552 * The caller has checked exit against the VMXRUNDBGSTATE::bmExitsToCheck
9553 * bitmap. The caller has checked for NMIs already, so we don't have to do that
9554 * either.
9555 *
9556 * @returns Strict VBox status code (i.e. informational status codes too).
9557 * @param pVM The cross context VM structure.
9558 * @param pVCpu The cross context virtual CPU structure.
9559 * @param pMixedCtx Pointer to the guest-CPU context.
9560 * @param pVmxTransient Pointer to the VMX-transient structure.
9561 * @param uExitReason The VM-exit reason.
9562 *
9563 * @remarks The name of this function is displayed by dtrace, so keep it short
9564 * and to the point. No longer than 33 chars long, please.
9565 */
9566static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx,
9567 PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
9568{
9569 /*
9570 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
9571 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
9572 *
9573 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
9574 * does. Must add/change/remove both places. Same ordering, please.
9575 *
9576 * Added/removed events must also be reflected in the next section
9577 * where we dispatch dtrace events.
9578 */
9579 bool fDtrace1 = false;
9580 bool fDtrace2 = false;
9581 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
9582 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
9583 uint32_t uEventArg = 0;
9584#define SET_EXIT(a_EventSubName) \
9585 do { \
9586 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
9587 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
9588 } while (0)
9589#define SET_BOTH(a_EventSubName) \
9590 do { \
9591 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
9592 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
9593 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
9594 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
9595 } while (0)
9596 switch (uExitReason)
9597 {
9598 case VMX_EXIT_MTF:
9599 return hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient);
9600
9601 case VMX_EXIT_XCPT_OR_NMI:
9602 {
9603 uint8_t const idxVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
9604 switch (VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo))
9605 {
9606 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT:
9607 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT:
9608 case VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT:
9609 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
9610 {
9611 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uExitIntInfo))
9612 {
9613 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
9614 uEventArg = pVmxTransient->uExitIntErrorCode;
9615 }
9616 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
9617 switch (enmEvent1)
9618 {
9619 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
9620 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
9621 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
9622 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
9623 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
9624 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
9625 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
9626 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
9627 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
9628 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
9629 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
9630 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
9631 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
9632 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
9633 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
9634 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
9635 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
9636 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
9637 default: break;
9638 }
9639 }
9640 else
9641 AssertFailed();
9642 break;
9643
9644 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT:
9645 uEventArg = idxVector;
9646 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
9647 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
9648 break;
9649 }
9650 break;
9651 }
9652
9653 case VMX_EXIT_TRIPLE_FAULT:
9654 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
9655 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
9656 break;
9657 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
9658 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
9659 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
9660 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
9661 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
9662
9663 /* Instruction specific VM-exits: */
9664 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
9665 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
9666 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
9667 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
9668 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
9669 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
9670 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
9671 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
9672 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
9673 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
9674 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
9675 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
9676 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
9677 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
9678 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
9679 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
9680 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
9681 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
9682 case VMX_EXIT_MOV_CRX:
9683 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9684/** @todo r=bird: I feel these macros aren't very descriptive and needs to be at least 30 chars longer! ;-)
9685* Sensible abbreviations strongly recommended here because even with 130 columns this stuff get too wide! */
9686 if ( VMX_EXIT_QUALIFICATION_CRX_ACCESS(pVmxTransient->uExitQualification)
9687 == VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ)
9688 SET_BOTH(CRX_READ);
9689 else
9690 SET_BOTH(CRX_WRITE);
9691 uEventArg = VMX_EXIT_QUALIFICATION_CRX_REGISTER(pVmxTransient->uExitQualification);
9692 break;
9693 case VMX_EXIT_MOV_DRX:
9694 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9695 if ( VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification)
9696 == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_READ)
9697 SET_BOTH(DRX_READ);
9698 else
9699 SET_BOTH(DRX_WRITE);
9700 uEventArg = VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification);
9701 break;
9702 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
9703 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
9704 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
9705 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
9706 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
9707 case VMX_EXIT_XDTR_ACCESS:
9708 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
9709 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_XDTR_INSINFO_INSTR_ID))
9710 {
9711 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
9712 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
9713 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
9714 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
9715 }
9716 break;
9717
9718 case VMX_EXIT_TR_ACCESS:
9719 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
9720 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_YYTR_INSINFO_INSTR_ID))
9721 {
9722 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
9723 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
9724 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
9725 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
9726 }
9727 break;
9728
9729 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
9730 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
9731 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
9732 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
9733 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
9734 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
9735 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
9736 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
9737 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
9738 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
9739 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
9740
9741 /* Events that aren't relevant at this point. */
9742 case VMX_EXIT_EXT_INT:
9743 case VMX_EXIT_INT_WINDOW:
9744 case VMX_EXIT_NMI_WINDOW:
9745 case VMX_EXIT_TPR_BELOW_THRESHOLD:
9746 case VMX_EXIT_PREEMPT_TIMER:
9747 case VMX_EXIT_IO_INSTR:
9748 break;
9749
9750 /* Errors and unexpected events. */
9751 case VMX_EXIT_INIT_SIGNAL:
9752 case VMX_EXIT_SIPI:
9753 case VMX_EXIT_IO_SMI:
9754 case VMX_EXIT_SMI:
9755 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
9756 case VMX_EXIT_ERR_MSR_LOAD:
9757 case VMX_EXIT_ERR_MACHINE_CHECK:
9758 break;
9759
9760 default:
9761 AssertMsgFailed(("Unexpected exit=%#x\n", uExitReason));
9762 break;
9763 }
9764#undef SET_BOTH
9765#undef SET_EXIT
9766
9767 /*
9768 * Dtrace tracepoints go first. We do them here at once so we don't
9769 * have to copy the guest state saving and stuff a few dozen times.
9770 * Down side is that we've got to repeat the switch, though this time
9771 * we use enmEvent since the probes are a subset of what DBGF does.
9772 */
9773 if (fDtrace1 || fDtrace2)
9774 {
9775 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9776 hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
9777 switch (enmEvent1)
9778 {
9779 /** @todo consider which extra parameters would be helpful for each probe. */
9780 case DBGFEVENT_END: break;
9781 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pMixedCtx); break;
9782 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pMixedCtx, pMixedCtx->dr[6]); break;
9783 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pMixedCtx); break;
9784 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pMixedCtx); break;
9785 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pMixedCtx); break;
9786 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pMixedCtx); break;
9787 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pMixedCtx); break;
9788 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pMixedCtx); break;
9789 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pMixedCtx, uEventArg); break;
9790 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pMixedCtx, uEventArg); break;
9791 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pMixedCtx, uEventArg); break;
9792 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pMixedCtx, uEventArg); break;
9793 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pMixedCtx, uEventArg, pMixedCtx->cr2); break;
9794 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pMixedCtx); break;
9795 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pMixedCtx); break;
9796 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pMixedCtx); break;
9797 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pMixedCtx); break;
9798 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pMixedCtx, uEventArg); break;
9799 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9800 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pMixedCtx, pMixedCtx->eax, pMixedCtx->ecx); break;
9801 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pMixedCtx); break;
9802 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pMixedCtx); break;
9803 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pMixedCtx); break;
9804 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pMixedCtx); break;
9805 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pMixedCtx); break;
9806 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pMixedCtx); break;
9807 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pMixedCtx); break;
9808 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9809 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9810 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9811 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9812 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pMixedCtx, pMixedCtx->ecx); break;
9813 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pMixedCtx, pMixedCtx->ecx,
9814 RT_MAKE_U64(pMixedCtx->eax, pMixedCtx->edx)); break;
9815 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pMixedCtx); break;
9816 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pMixedCtx); break;
9817 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pMixedCtx); break;
9818 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pMixedCtx); break;
9819 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pMixedCtx); break;
9820 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pMixedCtx); break;
9821 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pMixedCtx); break;
9822 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pMixedCtx); break;
9823 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pMixedCtx); break;
9824 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pMixedCtx); break;
9825 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pMixedCtx); break;
9826 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pMixedCtx); break;
9827 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pMixedCtx); break;
9828 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pMixedCtx); break;
9829 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pMixedCtx); break;
9830 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pMixedCtx); break;
9831 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pMixedCtx); break;
9832 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pMixedCtx); break;
9833 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pMixedCtx); break;
9834 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pMixedCtx); break;
9835 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pMixedCtx); break;
9836 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pMixedCtx); break;
9837 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pMixedCtx); break;
9838 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pMixedCtx); break;
9839 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pMixedCtx); break;
9840 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pMixedCtx); break;
9841 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pMixedCtx); break;
9842 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pMixedCtx); break;
9843 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pMixedCtx); break;
9844 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pMixedCtx); break;
9845 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pMixedCtx); break;
9846 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pMixedCtx); break;
9847 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
9848 }
9849 switch (enmEvent2)
9850 {
9851 /** @todo consider which extra parameters would be helpful for each probe. */
9852 case DBGFEVENT_END: break;
9853 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pMixedCtx); break;
9854 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pMixedCtx, pMixedCtx->eax, pMixedCtx->ecx); break;
9855 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pMixedCtx); break;
9856 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pMixedCtx); break;
9857 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pMixedCtx); break;
9858 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pMixedCtx); break;
9859 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pMixedCtx); break;
9860 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pMixedCtx); break;
9861 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pMixedCtx); break;
9862 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9863 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9864 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9865 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9866 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pMixedCtx, pMixedCtx->ecx); break;
9867 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pMixedCtx, pMixedCtx->ecx,
9868 RT_MAKE_U64(pMixedCtx->eax, pMixedCtx->edx)); break;
9869 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pMixedCtx); break;
9870 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pMixedCtx); break;
9871 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pMixedCtx); break;
9872 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pMixedCtx); break;
9873 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pMixedCtx); break;
9874 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pMixedCtx); break;
9875 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pMixedCtx); break;
9876 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pMixedCtx); break;
9877 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pMixedCtx); break;
9878 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pMixedCtx); break;
9879 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pMixedCtx); break;
9880 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pMixedCtx); break;
9881 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pMixedCtx); break;
9882 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pMixedCtx); break;
9883 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pMixedCtx); break;
9884 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pMixedCtx); break;
9885 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pMixedCtx); break;
9886 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pMixedCtx); break;
9887 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pMixedCtx); break;
9888 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pMixedCtx); break;
9889 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pMixedCtx); break;
9890 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pMixedCtx); break;
9891 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pMixedCtx); break;
9892 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pMixedCtx); break;
9893 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pMixedCtx); break;
9894 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pMixedCtx); break;
9895 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pMixedCtx); break;
9896 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pMixedCtx); break;
9897 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pMixedCtx); break;
9898 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pMixedCtx); break;
9899 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pMixedCtx); break;
9900 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pMixedCtx); break;
9901 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pMixedCtx); break;
9902 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pMixedCtx); break;
9903 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pMixedCtx); break;
9904 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pMixedCtx); break;
9905 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
9906 }
9907 }
9908
9909 /*
9910 * Fire of the DBGF event, if enabled (our check here is just a quick one,
9911 * the DBGF call will do a full check).
9912 *
9913 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
9914 * Note! If we have to events, we prioritize the first, i.e. the instruction
9915 * one, in order to avoid event nesting.
9916 */
9917 if ( enmEvent1 != DBGFEVENT_END
9918 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
9919 {
9920 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArg(pVM, pVCpu, enmEvent1, uEventArg, DBGFEVENTCTX_HM);
9921 if (rcStrict != VINF_SUCCESS)
9922 return rcStrict;
9923 }
9924 else if ( enmEvent2 != DBGFEVENT_END
9925 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
9926 {
9927 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArg(pVM, pVCpu, enmEvent2, uEventArg, DBGFEVENTCTX_HM);
9928 if (rcStrict != VINF_SUCCESS)
9929 return rcStrict;
9930 }
9931
9932 return VINF_SUCCESS;
9933}
9934
9935
9936/**
9937 * Single-stepping VM-exit filtering.
9938 *
9939 * This is preprocessing the exits and deciding whether we've gotten far enough
9940 * to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit handling is
9941 * performed.
9942 *
9943 * @returns Strict VBox status code (i.e. informational status codes too).
9944 * @param pVM The cross context VM structure.
9945 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
9946 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
9947 * out-of-sync. Make sure to update the required
9948 * fields before using them.
9949 * @param pVmxTransient Pointer to the VMX-transient structure.
9950 * @param uExitReason The VM-exit reason.
9951 * @param pDbgState The debug state.
9952 */
9953DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient,
9954 uint32_t uExitReason, PVMXRUNDBGSTATE pDbgState)
9955{
9956 /*
9957 * Expensive (saves context) generic dtrace exit probe.
9958 */
9959 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
9960 { /* more likely */ }
9961 else
9962 {
9963 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9964 hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
9965 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, pMixedCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQualification);
9966 }
9967
9968 /*
9969 * Check for host NMI, just to get that out of the way.
9970 */
9971 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
9972 { /* normally likely */ }
9973 else
9974 {
9975 int rc2 = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
9976 AssertRCReturn(rc2, rc2);
9977 uint32_t uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo);
9978 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
9979 return hmR0VmxExitXcptOrNmi(pVCpu, pMixedCtx, pVmxTransient);
9980 }
9981
9982 /*
9983 * Check for single stepping event if we're stepping.
9984 */
9985 if (pVCpu->hm.s.fSingleInstruction)
9986 {
9987 switch (uExitReason)
9988 {
9989 case VMX_EXIT_MTF:
9990 return hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient);
9991
9992 /* Various events: */
9993 case VMX_EXIT_XCPT_OR_NMI:
9994 case VMX_EXIT_EXT_INT:
9995 case VMX_EXIT_TRIPLE_FAULT:
9996 case VMX_EXIT_INT_WINDOW:
9997 case VMX_EXIT_NMI_WINDOW:
9998 case VMX_EXIT_TASK_SWITCH:
9999 case VMX_EXIT_TPR_BELOW_THRESHOLD:
10000 case VMX_EXIT_APIC_ACCESS:
10001 case VMX_EXIT_EPT_VIOLATION:
10002 case VMX_EXIT_EPT_MISCONFIG:
10003 case VMX_EXIT_PREEMPT_TIMER:
10004
10005 /* Instruction specific VM-exits: */
10006 case VMX_EXIT_CPUID:
10007 case VMX_EXIT_GETSEC:
10008 case VMX_EXIT_HLT:
10009 case VMX_EXIT_INVD:
10010 case VMX_EXIT_INVLPG:
10011 case VMX_EXIT_RDPMC:
10012 case VMX_EXIT_RDTSC:
10013 case VMX_EXIT_RSM:
10014 case VMX_EXIT_VMCALL:
10015 case VMX_EXIT_VMCLEAR:
10016 case VMX_EXIT_VMLAUNCH:
10017 case VMX_EXIT_VMPTRLD:
10018 case VMX_EXIT_VMPTRST:
10019 case VMX_EXIT_VMREAD:
10020 case VMX_EXIT_VMRESUME:
10021 case VMX_EXIT_VMWRITE:
10022 case VMX_EXIT_VMXOFF:
10023 case VMX_EXIT_VMXON:
10024 case VMX_EXIT_MOV_CRX:
10025 case VMX_EXIT_MOV_DRX:
10026 case VMX_EXIT_IO_INSTR:
10027 case VMX_EXIT_RDMSR:
10028 case VMX_EXIT_WRMSR:
10029 case VMX_EXIT_MWAIT:
10030 case VMX_EXIT_MONITOR:
10031 case VMX_EXIT_PAUSE:
10032 case VMX_EXIT_XDTR_ACCESS:
10033 case VMX_EXIT_TR_ACCESS:
10034 case VMX_EXIT_INVEPT:
10035 case VMX_EXIT_RDTSCP:
10036 case VMX_EXIT_INVVPID:
10037 case VMX_EXIT_WBINVD:
10038 case VMX_EXIT_XSETBV:
10039 case VMX_EXIT_RDRAND:
10040 case VMX_EXIT_INVPCID:
10041 case VMX_EXIT_VMFUNC:
10042 case VMX_EXIT_RDSEED:
10043 case VMX_EXIT_XSAVES:
10044 case VMX_EXIT_XRSTORS:
10045 {
10046 int rc2 = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
10047 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
10048 AssertRCReturn(rc2, rc2);
10049 if ( pMixedCtx->rip != pDbgState->uRipStart
10050 || pMixedCtx->cs.Sel != pDbgState->uCsStart)
10051 return VINF_EM_DBG_STEPPED;
10052 break;
10053 }
10054
10055 /* Errors and unexpected events: */
10056 case VMX_EXIT_INIT_SIGNAL:
10057 case VMX_EXIT_SIPI:
10058 case VMX_EXIT_IO_SMI:
10059 case VMX_EXIT_SMI:
10060 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
10061 case VMX_EXIT_ERR_MSR_LOAD:
10062 case VMX_EXIT_ERR_MACHINE_CHECK:
10063 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
10064 break;
10065
10066 default:
10067 AssertMsgFailed(("Unexpected exit=%#x\n", uExitReason));
10068 break;
10069 }
10070 }
10071
10072 /*
10073 * Check for debugger event breakpoints and dtrace probes.
10074 */
10075 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
10076 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
10077 {
10078 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVM, pVCpu, pMixedCtx, pVmxTransient, uExitReason);
10079 if (rcStrict != VINF_SUCCESS)
10080 return rcStrict;
10081 }
10082
10083 /*
10084 * Normal processing.
10085 */
10086#ifdef HMVMX_USE_FUNCTION_TABLE
10087 return g_apfnVMExitHandlers[uExitReason](pVCpu, pMixedCtx, pVmxTransient);
10088#else
10089 return hmR0VmxHandleExit(pVCpu, pMixedCtx, pVmxTransient, uExitReason);
10090#endif
10091}
10092
10093
10094/**
10095 * Single steps guest code using VT-x.
10096 *
10097 * @returns Strict VBox status code (i.e. informational status codes too).
10098 * @param pVM The cross context VM structure.
10099 * @param pVCpu The cross context virtual CPU structure.
10100 * @param pCtx Pointer to the guest-CPU context.
10101 *
10102 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
10103 */
10104static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10105{
10106 VMXTRANSIENT VmxTransient;
10107 VmxTransient.fUpdateTscOffsettingAndPreemptTimer = true;
10108
10109 /* Set HMCPU indicators. */
10110 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
10111 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
10112 pVCpu->hm.s.fDebugWantRdTscExit = false;
10113 pVCpu->hm.s.fUsingDebugLoop = true;
10114
10115 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
10116 VMXRUNDBGSTATE DbgState;
10117 hmR0VmxRunDebugStateInit(pVCpu, pCtx, &DbgState);
10118 hmR0VmxPreRunGuestDebugStateUpdate(pVM, pVCpu, pCtx, &DbgState, &VmxTransient);
10119
10120 /*
10121 * The loop.
10122 */
10123 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10124 for (uint32_t cLoops = 0; ; cLoops++)
10125 {
10126 Assert(!HMR0SuspendPending());
10127 HMVMX_ASSERT_CPU_SAFE();
10128 bool fStepping = pVCpu->hm.s.fSingleInstruction;
10129
10130 /*
10131 * Preparatory work for running guest code, this may force us to return
10132 * to ring-3. This bugger disables interrupts on VINF_SUCCESS!
10133 */
10134 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10135 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &DbgState); /* Set up execute controls the next to can respond to. */
10136 rcStrict = hmR0VmxPreRunGuest(pVM, pVCpu, pCtx, &VmxTransient, fStepping);
10137 if (rcStrict != VINF_SUCCESS)
10138 break;
10139
10140 hmR0VmxPreRunGuestCommitted(pVM, pVCpu, pCtx, &VmxTransient);
10141 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &DbgState); /* Override any obnoxious code in the above two calls. */
10142
10143 /*
10144 * Now we can run the guest code.
10145 */
10146 int rcRun = hmR0VmxRunGuest(pVM, pVCpu, pCtx);
10147
10148 /* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
10149
10150 /*
10151 * Restore any residual host-state and save any bits shared between host
10152 * and guest into the guest-CPU state. Re-enables interrupts!
10153 */
10154 hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, VBOXSTRICTRC_TODO(rcStrict));
10155
10156 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
10157 if (RT_SUCCESS(rcRun))
10158 { /* very likely */ }
10159 else
10160 {
10161 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
10162 hmR0VmxReportWorldSwitchError(pVM, pVCpu, rcRun, pCtx, &VmxTransient);
10163 return rcRun;
10164 }
10165
10166 /* Profile the VM-exit. */
10167 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10168 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10169 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10170 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
10171 HMVMX_START_EXIT_DISPATCH_PROF();
10172
10173 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, pCtx, VmxTransient.uExitReason);
10174
10175 /*
10176 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
10177 */
10178 rcStrict = hmR0VmxRunDebugHandleExit(pVM, pVCpu, pCtx, &VmxTransient, VmxTransient.uExitReason, &DbgState);
10179 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
10180 if (rcStrict != VINF_SUCCESS)
10181 break;
10182 if (cLoops > pVM->hm.s.cMaxResumeLoops)
10183 {
10184 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10185 rcStrict = VINF_EM_RAW_INTERRUPT;
10186 break;
10187 }
10188
10189 /*
10190 * Stepping: Did the RIP change, if so, consider it a single step.
10191 * Otherwise, make sure one of the TFs gets set.
10192 */
10193 if (fStepping)
10194 {
10195 int rc2 = hmR0VmxSaveGuestRip(pVCpu, pCtx);
10196 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pCtx);
10197 AssertRCReturn(rc2, rc2);
10198 if ( pCtx->rip != DbgState.uRipStart
10199 || pCtx->cs.Sel != DbgState.uCsStart)
10200 {
10201 rcStrict = VINF_EM_DBG_STEPPED;
10202 break;
10203 }
10204 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
10205 }
10206
10207 /*
10208 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
10209 */
10210 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
10211 hmR0VmxPreRunGuestDebugStateUpdate(pVM, pVCpu, pCtx, &DbgState, &VmxTransient);
10212 }
10213
10214 /*
10215 * Clear the X86_EFL_TF if necessary.
10216 */
10217 if (pVCpu->hm.s.fClearTrapFlag)
10218 {
10219 int rc2 = hmR0VmxSaveGuestRflags(pVCpu, pCtx);
10220 AssertRCReturn(rc2, rc2);
10221 pVCpu->hm.s.fClearTrapFlag = false;
10222 pCtx->eflags.Bits.u1TF = 0;
10223 }
10224 /** @todo there seems to be issues with the resume flag when the monitor trap
10225 * flag is pending without being used. Seen early in bios init when
10226 * accessing APIC page in protected mode. */
10227
10228 /*
10229 * Restore VM-exit control settings as we may not reenter this function the
10230 * next time around.
10231 */
10232 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &DbgState, rcStrict);
10233
10234 /* Restore HMCPU indicators. */
10235 pVCpu->hm.s.fUsingDebugLoop = false;
10236 pVCpu->hm.s.fDebugWantRdTscExit = false;
10237 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
10238
10239 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10240 return rcStrict;
10241}
10242
10243
10244/** @} */
10245
10246
10247/**
10248 * Checks if any expensive dtrace probes are enabled and we should go to the
10249 * debug loop.
10250 *
10251 * @returns true if we should use debug loop, false if not.
10252 */
10253static bool hmR0VmxAnyExpensiveProbesEnabled(void)
10254{
10255 /* It's probably faster to OR the raw 32-bit counter variables together.
10256 Since the variables are in an array and the probes are next to one
10257 another (more or less), we have good locality. So, better read
10258 eight-nine cache lines ever time and only have one conditional, than
10259 128+ conditionals, right? */
10260 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
10261 | VBOXVMM_XCPT_DE_ENABLED_RAW()
10262 | VBOXVMM_XCPT_DB_ENABLED_RAW()
10263 | VBOXVMM_XCPT_BP_ENABLED_RAW()
10264 | VBOXVMM_XCPT_OF_ENABLED_RAW()
10265 | VBOXVMM_XCPT_BR_ENABLED_RAW()
10266 | VBOXVMM_XCPT_UD_ENABLED_RAW()
10267 | VBOXVMM_XCPT_NM_ENABLED_RAW()
10268 | VBOXVMM_XCPT_DF_ENABLED_RAW()
10269 | VBOXVMM_XCPT_TS_ENABLED_RAW()
10270 | VBOXVMM_XCPT_NP_ENABLED_RAW()
10271 | VBOXVMM_XCPT_SS_ENABLED_RAW()
10272 | VBOXVMM_XCPT_GP_ENABLED_RAW()
10273 | VBOXVMM_XCPT_PF_ENABLED_RAW()
10274 | VBOXVMM_XCPT_MF_ENABLED_RAW()
10275 | VBOXVMM_XCPT_AC_ENABLED_RAW()
10276 | VBOXVMM_XCPT_XF_ENABLED_RAW()
10277 | VBOXVMM_XCPT_VE_ENABLED_RAW()
10278 | VBOXVMM_XCPT_SX_ENABLED_RAW()
10279 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
10280 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
10281 ) != 0
10282 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
10283 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
10284 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
10285 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
10286 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
10287 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
10288 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
10289 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
10290 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
10291 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
10292 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
10293 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
10294 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
10295 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
10296 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
10297 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
10298 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
10299 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
10300 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
10301 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
10302 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
10303 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
10304 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
10305 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
10306 | VBOXVMM_INSTR_STR_ENABLED_RAW()
10307 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
10308 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
10309 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
10310 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
10311 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
10312 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
10313 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
10314 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
10315 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
10316 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
10317 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
10318 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
10319 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
10320 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
10321 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
10322 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
10323 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
10324 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
10325 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
10326 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
10327 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
10328 ) != 0
10329 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
10330 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
10331 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
10332 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
10333 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
10334 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
10335 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
10336 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
10337 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
10338 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
10339 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
10340 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
10341 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
10342 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
10343 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
10344 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
10345 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
10346 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
10347 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
10348 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
10349 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
10350 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
10351 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
10352 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
10353 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
10354 | VBOXVMM_EXIT_STR_ENABLED_RAW()
10355 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
10356 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
10357 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
10358 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
10359 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
10360 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
10361 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
10362 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
10363 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
10364 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
10365 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
10366 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
10367 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
10368 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
10369 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
10370 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
10371 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
10372 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
10373 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
10374 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
10375 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
10376 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
10377 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
10378 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
10379 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
10380 ) != 0;
10381}
10382
10383
10384/**
10385 * Runs the guest code using VT-x.
10386 *
10387 * @returns Strict VBox status code (i.e. informational status codes too).
10388 * @param pVM The cross context VM structure.
10389 * @param pVCpu The cross context virtual CPU structure.
10390 * @param pCtx Pointer to the guest-CPU context.
10391 */
10392VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10393{
10394 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10395 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
10396 HMVMX_ASSERT_PREEMPT_SAFE();
10397
10398 VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pCtx);
10399
10400 VBOXSTRICTRC rcStrict;
10401 if ( !pVCpu->hm.s.fUseDebugLoop
10402 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
10403 && !DBGFIsStepping(pVCpu) )
10404 rcStrict = hmR0VmxRunGuestCodeNormal(pVM, pVCpu, pCtx);
10405 else
10406 rcStrict = hmR0VmxRunGuestCodeDebug(pVM, pVCpu, pCtx);
10407
10408 if (rcStrict == VERR_EM_INTERPRETER)
10409 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
10410 else if (rcStrict == VINF_EM_RESET)
10411 rcStrict = VINF_EM_TRIPLE_FAULT;
10412
10413 int rc2 = hmR0VmxExitToRing3(pVM, pVCpu, pCtx, rcStrict);
10414 if (RT_FAILURE(rc2))
10415 {
10416 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
10417 rcStrict = rc2;
10418 }
10419 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
10420 return rcStrict;
10421}
10422
10423
10424#ifndef HMVMX_USE_FUNCTION_TABLE
10425DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason)
10426{
10427# ifdef DEBUG_ramshankar
10428# define RETURN_EXIT_CALL(a_CallExpr) \
10429 do { \
10430 int rc2 = hmR0VmxSaveGuestState(pVCpu, pMixedCtx); AssertRC(rc2); \
10431 VBOXSTRICTRC rcStrict = a_CallExpr; \
10432 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST); \
10433 return rcStrict; \
10434 } while (0)
10435# else
10436# define RETURN_EXIT_CALL(a_CallExpr) return a_CallExpr
10437# endif
10438 switch (rcReason)
10439 {
10440 case VMX_EXIT_EPT_MISCONFIG: RETURN_EXIT_CALL(hmR0VmxExitEptMisconfig(pVCpu, pMixedCtx, pVmxTransient));
10441 case VMX_EXIT_EPT_VIOLATION: RETURN_EXIT_CALL(hmR0VmxExitEptViolation(pVCpu, pMixedCtx, pVmxTransient));
10442 case VMX_EXIT_IO_INSTR: RETURN_EXIT_CALL(hmR0VmxExitIoInstr(pVCpu, pMixedCtx, pVmxTransient));
10443 case VMX_EXIT_CPUID: RETURN_EXIT_CALL(hmR0VmxExitCpuid(pVCpu, pMixedCtx, pVmxTransient));
10444 case VMX_EXIT_RDTSC: RETURN_EXIT_CALL(hmR0VmxExitRdtsc(pVCpu, pMixedCtx, pVmxTransient));
10445 case VMX_EXIT_RDTSCP: RETURN_EXIT_CALL(hmR0VmxExitRdtscp(pVCpu, pMixedCtx, pVmxTransient));
10446 case VMX_EXIT_APIC_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitApicAccess(pVCpu, pMixedCtx, pVmxTransient));
10447 case VMX_EXIT_XCPT_OR_NMI: RETURN_EXIT_CALL(hmR0VmxExitXcptOrNmi(pVCpu, pMixedCtx, pVmxTransient));
10448 case VMX_EXIT_MOV_CRX: RETURN_EXIT_CALL(hmR0VmxExitMovCRx(pVCpu, pMixedCtx, pVmxTransient));
10449 case VMX_EXIT_EXT_INT: RETURN_EXIT_CALL(hmR0VmxExitExtInt(pVCpu, pMixedCtx, pVmxTransient));
10450 case VMX_EXIT_INT_WINDOW: RETURN_EXIT_CALL(hmR0VmxExitIntWindow(pVCpu, pMixedCtx, pVmxTransient));
10451 case VMX_EXIT_MWAIT: RETURN_EXIT_CALL(hmR0VmxExitMwait(pVCpu, pMixedCtx, pVmxTransient));
10452 case VMX_EXIT_MONITOR: RETURN_EXIT_CALL(hmR0VmxExitMonitor(pVCpu, pMixedCtx, pVmxTransient));
10453 case VMX_EXIT_TASK_SWITCH: RETURN_EXIT_CALL(hmR0VmxExitTaskSwitch(pVCpu, pMixedCtx, pVmxTransient));
10454 case VMX_EXIT_PREEMPT_TIMER: RETURN_EXIT_CALL(hmR0VmxExitPreemptTimer(pVCpu, pMixedCtx, pVmxTransient));
10455 case VMX_EXIT_RDMSR: RETURN_EXIT_CALL(hmR0VmxExitRdmsr(pVCpu, pMixedCtx, pVmxTransient));
10456 case VMX_EXIT_WRMSR: RETURN_EXIT_CALL(hmR0VmxExitWrmsr(pVCpu, pMixedCtx, pVmxTransient));
10457 case VMX_EXIT_MOV_DRX: RETURN_EXIT_CALL(hmR0VmxExitMovDRx(pVCpu, pMixedCtx, pVmxTransient));
10458 case VMX_EXIT_TPR_BELOW_THRESHOLD: RETURN_EXIT_CALL(hmR0VmxExitTprBelowThreshold(pVCpu, pMixedCtx, pVmxTransient));
10459 case VMX_EXIT_HLT: RETURN_EXIT_CALL(hmR0VmxExitHlt(pVCpu, pMixedCtx, pVmxTransient));
10460 case VMX_EXIT_INVD: RETURN_EXIT_CALL(hmR0VmxExitInvd(pVCpu, pMixedCtx, pVmxTransient));
10461 case VMX_EXIT_INVLPG: RETURN_EXIT_CALL(hmR0VmxExitInvlpg(pVCpu, pMixedCtx, pVmxTransient));
10462 case VMX_EXIT_RSM: RETURN_EXIT_CALL(hmR0VmxExitRsm(pVCpu, pMixedCtx, pVmxTransient));
10463 case VMX_EXIT_MTF: RETURN_EXIT_CALL(hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient));
10464 case VMX_EXIT_PAUSE: RETURN_EXIT_CALL(hmR0VmxExitPause(pVCpu, pMixedCtx, pVmxTransient));
10465 case VMX_EXIT_XDTR_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient));
10466 case VMX_EXIT_TR_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient));
10467 case VMX_EXIT_WBINVD: RETURN_EXIT_CALL(hmR0VmxExitWbinvd(pVCpu, pMixedCtx, pVmxTransient));
10468 case VMX_EXIT_XSETBV: RETURN_EXIT_CALL(hmR0VmxExitXsetbv(pVCpu, pMixedCtx, pVmxTransient));
10469 case VMX_EXIT_RDRAND: RETURN_EXIT_CALL(hmR0VmxExitRdrand(pVCpu, pMixedCtx, pVmxTransient));
10470 case VMX_EXIT_INVPCID: RETURN_EXIT_CALL(hmR0VmxExitInvpcid(pVCpu, pMixedCtx, pVmxTransient));
10471 case VMX_EXIT_GETSEC: RETURN_EXIT_CALL(hmR0VmxExitGetsec(pVCpu, pMixedCtx, pVmxTransient));
10472 case VMX_EXIT_RDPMC: RETURN_EXIT_CALL(hmR0VmxExitRdpmc(pVCpu, pMixedCtx, pVmxTransient));
10473 case VMX_EXIT_VMCALL: RETURN_EXIT_CALL(hmR0VmxExitVmcall(pVCpu, pMixedCtx, pVmxTransient));
10474
10475 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pMixedCtx, pVmxTransient);
10476 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pMixedCtx, pVmxTransient);
10477 case VMX_EXIT_INIT_SIGNAL: return hmR0VmxExitInitSignal(pVCpu, pMixedCtx, pVmxTransient);
10478 case VMX_EXIT_SIPI: return hmR0VmxExitSipi(pVCpu, pMixedCtx, pVmxTransient);
10479 case VMX_EXIT_IO_SMI: return hmR0VmxExitIoSmi(pVCpu, pMixedCtx, pVmxTransient);
10480 case VMX_EXIT_SMI: return hmR0VmxExitSmi(pVCpu, pMixedCtx, pVmxTransient);
10481 case VMX_EXIT_ERR_MSR_LOAD: return hmR0VmxExitErrMsrLoad(pVCpu, pMixedCtx, pVmxTransient);
10482 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pMixedCtx, pVmxTransient);
10483 case VMX_EXIT_ERR_MACHINE_CHECK: return hmR0VmxExitErrMachineCheck(pVCpu, pMixedCtx, pVmxTransient);
10484
10485 case VMX_EXIT_VMCLEAR:
10486 case VMX_EXIT_VMLAUNCH:
10487 case VMX_EXIT_VMPTRLD:
10488 case VMX_EXIT_VMPTRST:
10489 case VMX_EXIT_VMREAD:
10490 case VMX_EXIT_VMRESUME:
10491 case VMX_EXIT_VMWRITE:
10492 case VMX_EXIT_VMXOFF:
10493 case VMX_EXIT_VMXON:
10494 case VMX_EXIT_INVEPT:
10495 case VMX_EXIT_INVVPID:
10496 case VMX_EXIT_VMFUNC:
10497 case VMX_EXIT_XSAVES:
10498 case VMX_EXIT_XRSTORS:
10499 return hmR0VmxExitSetPendingXcptUD(pVCpu, pMixedCtx, pVmxTransient);
10500 case VMX_EXIT_RESERVED_60:
10501 case VMX_EXIT_RDSEED: /* only spurious exits, so undefined */
10502 case VMX_EXIT_RESERVED_62:
10503 default:
10504 return hmR0VmxExitErrUndefined(pVCpu, pMixedCtx, pVmxTransient);
10505 }
10506#undef RETURN_EXIT_CALL
10507}
10508#endif /* !HMVMX_USE_FUNCTION_TABLE */
10509
10510
10511#ifdef VBOX_STRICT
10512/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
10513# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
10514 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
10515
10516# define HMVMX_ASSERT_PREEMPT_CPUID() \
10517 do { \
10518 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
10519 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
10520 } while (0)
10521
10522# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS() \
10523 do { \
10524 AssertPtr(pVCpu); \
10525 AssertPtr(pMixedCtx); \
10526 AssertPtr(pVmxTransient); \
10527 Assert(pVmxTransient->fVMEntryFailed == false); \
10528 Assert(ASMIntAreEnabled()); \
10529 HMVMX_ASSERT_PREEMPT_SAFE(); \
10530 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
10531 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)); \
10532 HMVMX_ASSERT_PREEMPT_SAFE(); \
10533 if (VMMR0IsLogFlushDisabled(pVCpu)) \
10534 HMVMX_ASSERT_PREEMPT_CPUID(); \
10535 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
10536 } while (0)
10537
10538# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() \
10539 do { \
10540 Log4Func(("\n")); \
10541 } while (0)
10542#else /* nonstrict builds: */
10543# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS() \
10544 do { \
10545 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
10546 NOREF(pVCpu); NOREF(pMixedCtx); NOREF(pVmxTransient); \
10547 } while (0)
10548# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() do { } while (0)
10549#endif
10550
10551
10552/**
10553 * Advances the guest RIP by the specified number of bytes.
10554 *
10555 * @param pVCpu The cross context virtual CPU structure.
10556 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
10557 * out-of-sync. Make sure to update the required fields
10558 * before using them.
10559 * @param cbInstr Number of bytes to advance the RIP by.
10560 *
10561 * @remarks No-long-jump zone!!!
10562 */
10563DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
10564{
10565 /* Advance the RIP. */
10566 pMixedCtx->rip += cbInstr;
10567 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
10568
10569 /* Update interrupt inhibition. */
10570 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
10571 && pMixedCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
10572 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
10573}
10574
10575
10576/**
10577 * Advances the guest RIP after reading it from the VMCS.
10578 *
10579 * @returns VBox status code, no informational status codes.
10580 * @param pVCpu The cross context virtual CPU structure.
10581 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
10582 * out-of-sync. Make sure to update the required fields
10583 * before using them.
10584 * @param pVmxTransient Pointer to the VMX transient structure.
10585 *
10586 * @remarks No-long-jump zone!!!
10587 */
10588static int hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
10589{
10590 int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
10591 rc |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
10592 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
10593 AssertRCReturn(rc, rc);
10594
10595 hmR0VmxAdvanceGuestRipBy(pVCpu, pMixedCtx, pVmxTransient->cbInstr);
10596
10597 /*
10598 * Deliver a debug exception to the guest if it is single-stepping. Don't directly inject a #DB but use the
10599 * pending debug exception field as it takes care of priority of events.
10600 *
10601 * See Intel spec. 32.2.1 "Debug Exceptions".
10602 */
10603 if ( !pVCpu->hm.s.fSingleInstruction
10604 && pMixedCtx->eflags.Bits.u1TF)
10605 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
10606
10607 return VINF_SUCCESS;
10608}
10609
10610
10611/**
10612 * Tries to determine what part of the guest-state VT-x has deemed as invalid
10613 * and update error record fields accordingly.
10614 *
10615 * @return VMX_IGS_* return codes.
10616 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
10617 * wrong with the guest state.
10618 *
10619 * @param pVM The cross context VM structure.
10620 * @param pVCpu The cross context virtual CPU structure.
10621 * @param pCtx Pointer to the guest-CPU state.
10622 *
10623 * @remarks This function assumes our cache of the VMCS controls
10624 * are valid, i.e. hmR0VmxCheckVmcsCtls() succeeded.
10625 */
10626static uint32_t hmR0VmxCheckGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10627{
10628#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
10629#define HMVMX_CHECK_BREAK(expr, err) if (!(expr)) { \
10630 uError = (err); \
10631 break; \
10632 } else do { } while (0)
10633
10634 int rc;
10635 uint32_t uError = VMX_IGS_ERROR;
10636 uint32_t u32Val;
10637 bool fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuest;
10638
10639 do
10640 {
10641 /*
10642 * CR0.
10643 */
10644 uint32_t uSetCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
10645 uint32_t uZapCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
10646 /* Exceptions for unrestricted-guests for fixed CR0 bits (PE, PG).
10647 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
10648 if (fUnrestrictedGuest)
10649 uSetCR0 &= ~(X86_CR0_PE | X86_CR0_PG);
10650
10651 uint32_t u32GuestCR0;
10652 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32GuestCR0);
10653 AssertRCBreak(rc);
10654 HMVMX_CHECK_BREAK((u32GuestCR0 & uSetCR0) == uSetCR0, VMX_IGS_CR0_FIXED1);
10655 HMVMX_CHECK_BREAK(!(u32GuestCR0 & ~uZapCR0), VMX_IGS_CR0_FIXED0);
10656 if ( !fUnrestrictedGuest
10657 && (u32GuestCR0 & X86_CR0_PG)
10658 && !(u32GuestCR0 & X86_CR0_PE))
10659 {
10660 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
10661 }
10662
10663 /*
10664 * CR4.
10665 */
10666 uint64_t uSetCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
10667 uint64_t uZapCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
10668
10669 uint32_t u32GuestCR4;
10670 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &u32GuestCR4);
10671 AssertRCBreak(rc);
10672 HMVMX_CHECK_BREAK((u32GuestCR4 & uSetCR4) == uSetCR4, VMX_IGS_CR4_FIXED1);
10673 HMVMX_CHECK_BREAK(!(u32GuestCR4 & ~uZapCR4), VMX_IGS_CR4_FIXED0);
10674
10675 /*
10676 * IA32_DEBUGCTL MSR.
10677 */
10678 uint64_t u64Val;
10679 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
10680 AssertRCBreak(rc);
10681 if ( (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
10682 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
10683 {
10684 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
10685 }
10686 uint64_t u64DebugCtlMsr = u64Val;
10687
10688#ifdef VBOX_STRICT
10689 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
10690 AssertRCBreak(rc);
10691 Assert(u32Val == pVCpu->hm.s.vmx.u32EntryCtls);
10692#endif
10693 bool const fLongModeGuest = RT_BOOL(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST);
10694
10695 /*
10696 * RIP and RFLAGS.
10697 */
10698 uint32_t u32Eflags;
10699#if HC_ARCH_BITS == 64
10700 rc = VMXReadVmcs64(VMX_VMCS_GUEST_RIP, &u64Val);
10701 AssertRCBreak(rc);
10702 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
10703 if ( !fLongModeGuest
10704 || !pCtx->cs.Attr.n.u1Long)
10705 {
10706 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
10707 }
10708 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
10709 * must be identical if the "IA-32e mode guest" VM-entry
10710 * control is 1 and CS.L is 1. No check applies if the
10711 * CPU supports 64 linear-address bits. */
10712
10713 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
10714 rc = VMXReadVmcs64(VMX_VMCS_GUEST_RFLAGS, &u64Val);
10715 AssertRCBreak(rc);
10716 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
10717 VMX_IGS_RFLAGS_RESERVED);
10718 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
10719 u32Eflags = u64Val;
10720#else
10721 rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &u32Eflags);
10722 AssertRCBreak(rc);
10723 HMVMX_CHECK_BREAK(!(u32Eflags & 0xffc08028), VMX_IGS_RFLAGS_RESERVED); /* Bit 31:22, Bit 15, 5, 3 MBZ. */
10724 HMVMX_CHECK_BREAK((u32Eflags & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
10725#endif
10726
10727 if ( fLongModeGuest
10728 || ( fUnrestrictedGuest
10729 && !(u32GuestCR0 & X86_CR0_PE)))
10730 {
10731 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
10732 }
10733
10734 uint32_t u32EntryInfo;
10735 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
10736 AssertRCBreak(rc);
10737 if ( VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo)
10738 && VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
10739 {
10740 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
10741 }
10742
10743 /*
10744 * 64-bit checks.
10745 */
10746#if HC_ARCH_BITS == 64
10747 if (fLongModeGuest)
10748 {
10749 HMVMX_CHECK_BREAK(u32GuestCR0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
10750 HMVMX_CHECK_BREAK(u32GuestCR4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
10751 }
10752
10753 if ( !fLongModeGuest
10754 && (u32GuestCR4 & X86_CR4_PCIDE))
10755 {
10756 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
10757 }
10758
10759 /** @todo CR3 field must be such that bits 63:52 and bits in the range
10760 * 51:32 beyond the processor's physical-address width are 0. */
10761
10762 if ( (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
10763 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
10764 {
10765 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
10766 }
10767
10768 rc = VMXReadVmcs64(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
10769 AssertRCBreak(rc);
10770 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
10771
10772 rc = VMXReadVmcs64(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
10773 AssertRCBreak(rc);
10774 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
10775#endif
10776
10777 /*
10778 * PERF_GLOBAL MSR.
10779 */
10780 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PERF_MSR)
10781 {
10782 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
10783 AssertRCBreak(rc);
10784 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
10785 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
10786 }
10787
10788 /*
10789 * PAT MSR.
10790 */
10791 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PAT_MSR)
10792 {
10793 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
10794 AssertRCBreak(rc);
10795 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
10796 for (unsigned i = 0; i < 8; i++)
10797 {
10798 uint8_t u8Val = (u64Val & 0xff);
10799 if ( u8Val != 0 /* UC */
10800 && u8Val != 1 /* WC */
10801 && u8Val != 4 /* WT */
10802 && u8Val != 5 /* WP */
10803 && u8Val != 6 /* WB */
10804 && u8Val != 7 /* UC- */)
10805 {
10806 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
10807 }
10808 u64Val >>= 8;
10809 }
10810 }
10811
10812 /*
10813 * EFER MSR.
10814 */
10815 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR)
10816 {
10817 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
10818 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
10819 AssertRCBreak(rc);
10820 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
10821 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
10822 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVCpu->hm.s.vmx.u32EntryCtls
10823 & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST),
10824 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
10825 HMVMX_CHECK_BREAK( fUnrestrictedGuest
10826 || !(u32GuestCR0 & X86_CR0_PG)
10827 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
10828 VMX_IGS_EFER_LMA_LME_MISMATCH);
10829 }
10830
10831 /*
10832 * Segment registers.
10833 */
10834 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10835 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
10836 if (!(u32Eflags & X86_EFL_VM))
10837 {
10838 /* CS */
10839 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
10840 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
10841 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
10842 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
10843 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
10844 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
10845 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
10846 /* CS cannot be loaded with NULL in protected mode. */
10847 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
10848 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
10849 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
10850 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
10851 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
10852 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
10853 else if (pVM->hm.s.vmx.fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
10854 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
10855 else
10856 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
10857
10858 /* SS */
10859 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10860 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
10861 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
10862 if ( !(pCtx->cr0 & X86_CR0_PE)
10863 || pCtx->cs.Attr.n.u4Type == 3)
10864 {
10865 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
10866 }
10867 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
10868 {
10869 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
10870 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
10871 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
10872 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
10873 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
10874 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
10875 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
10876 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
10877 }
10878
10879 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxWriteSegmentReg(). */
10880 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
10881 {
10882 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
10883 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
10884 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10885 || pCtx->ds.Attr.n.u4Type > 11
10886 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
10887 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
10888 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
10889 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
10890 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
10891 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
10892 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
10893 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10894 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
10895 }
10896 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
10897 {
10898 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
10899 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
10900 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10901 || pCtx->es.Attr.n.u4Type > 11
10902 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
10903 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
10904 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
10905 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
10906 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
10907 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
10908 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
10909 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10910 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
10911 }
10912 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
10913 {
10914 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
10915 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
10916 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10917 || pCtx->fs.Attr.n.u4Type > 11
10918 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
10919 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
10920 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
10921 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
10922 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
10923 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
10924 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
10925 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10926 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
10927 }
10928 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
10929 {
10930 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
10931 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
10932 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10933 || pCtx->gs.Attr.n.u4Type > 11
10934 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
10935 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
10936 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
10937 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
10938 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10939 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
10940 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10941 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10942 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
10943 }
10944 /* 64-bit capable CPUs. */
10945#if HC_ARCH_BITS == 64
10946 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10947 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10948 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10949 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10950 HMVMX_CHECK_BREAK(!(pCtx->cs.u64Base >> 32), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10951 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ss.u64Base >> 32),
10952 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10953 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ds.u64Base >> 32),
10954 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10955 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->es.u64Base >> 32),
10956 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10957#endif
10958 }
10959 else
10960 {
10961 /* V86 mode checks. */
10962 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
10963 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
10964 {
10965 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
10966 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
10967 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
10968 }
10969 else
10970 {
10971 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
10972 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
10973 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
10974 }
10975
10976 /* CS */
10977 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
10978 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
10979 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
10980 /* SS */
10981 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
10982 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
10983 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
10984 /* DS */
10985 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
10986 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
10987 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
10988 /* ES */
10989 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
10990 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
10991 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
10992 /* FS */
10993 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
10994 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
10995 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
10996 /* GS */
10997 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
10998 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
10999 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
11000 /* 64-bit capable CPUs. */
11001#if HC_ARCH_BITS == 64
11002 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
11003 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
11004 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
11005 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
11006 HMVMX_CHECK_BREAK(!(pCtx->cs.u64Base >> 32), VMX_IGS_LONGMODE_CS_BASE_INVALID);
11007 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ss.u64Base >> 32),
11008 VMX_IGS_LONGMODE_SS_BASE_INVALID);
11009 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ds.u64Base >> 32),
11010 VMX_IGS_LONGMODE_DS_BASE_INVALID);
11011 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->es.u64Base >> 32),
11012 VMX_IGS_LONGMODE_ES_BASE_INVALID);
11013#endif
11014 }
11015
11016 /*
11017 * TR.
11018 */
11019 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
11020 /* 64-bit capable CPUs. */
11021#if HC_ARCH_BITS == 64
11022 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
11023#endif
11024 if (fLongModeGuest)
11025 {
11026 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
11027 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
11028 }
11029 else
11030 {
11031 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
11032 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
11033 VMX_IGS_TR_ATTR_TYPE_INVALID);
11034 }
11035 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
11036 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
11037 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
11038 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
11039 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
11040 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
11041 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
11042 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
11043
11044 /*
11045 * GDTR and IDTR.
11046 */
11047#if HC_ARCH_BITS == 64
11048 rc = VMXReadVmcs64(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
11049 AssertRCBreak(rc);
11050 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
11051
11052 rc = VMXReadVmcs64(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
11053 AssertRCBreak(rc);
11054 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
11055#endif
11056
11057 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
11058 AssertRCBreak(rc);
11059 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
11060
11061 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
11062 AssertRCBreak(rc);
11063 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
11064
11065 /*
11066 * Guest Non-Register State.
11067 */
11068 /* Activity State. */
11069 uint32_t u32ActivityState;
11070 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
11071 AssertRCBreak(rc);
11072 HMVMX_CHECK_BREAK( !u32ActivityState
11073 || (u32ActivityState & MSR_IA32_VMX_MISC_ACTIVITY_STATES(pVM->hm.s.vmx.Msrs.u64Misc)),
11074 VMX_IGS_ACTIVITY_STATE_INVALID);
11075 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
11076 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
11077 uint32_t u32IntrState;
11078 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &u32IntrState);
11079 AssertRCBreak(rc);
11080 if ( u32IntrState == VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS
11081 || u32IntrState == VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
11082 {
11083 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
11084 }
11085
11086 /** @todo Activity state and injecting interrupts. Left as a todo since we
11087 * currently don't use activity states but ACTIVE. */
11088
11089 HMVMX_CHECK_BREAK( !(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_ENTRY_SMM)
11090 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
11091
11092 /* Guest interruptibility-state. */
11093 HMVMX_CHECK_BREAK(!(u32IntrState & 0xfffffff0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
11094 HMVMX_CHECK_BREAK((u32IntrState & ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI
11095 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS))
11096 != ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI
11097 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
11098 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
11099 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
11100 || !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI),
11101 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
11102 if (VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo))
11103 {
11104 if (VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
11105 {
11106 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
11107 && !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
11108 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
11109 }
11110 else if (VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11111 {
11112 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
11113 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
11114 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI),
11115 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
11116 }
11117 }
11118 /** @todo Assumes the processor is not in SMM. */
11119 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI),
11120 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
11121 HMVMX_CHECK_BREAK( !(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_ENTRY_SMM)
11122 || (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI),
11123 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
11124 if ( (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
11125 && VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo)
11126 && VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11127 {
11128 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI),
11129 VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
11130 }
11131
11132 /* Pending debug exceptions. */
11133#if HC_ARCH_BITS == 64
11134 rc = VMXReadVmcs64(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, &u64Val);
11135 AssertRCBreak(rc);
11136 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
11137 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
11138 u32Val = u64Val; /* For pending debug exceptions checks below. */
11139#else
11140 rc = VMXReadVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, &u32Val);
11141 AssertRCBreak(rc);
11142 /* Bits 31:15, Bit 13, Bits 11:4 MBZ. */
11143 HMVMX_CHECK_BREAK(!(u32Val & 0xffffaff0), VMX_IGS_PENDING_DEBUG_RESERVED);
11144#endif
11145
11146 if ( (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
11147 || (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS)
11148 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
11149 {
11150 if ( (u32Eflags & X86_EFL_TF)
11151 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
11152 {
11153 /* Bit 14 is PendingDebug.BS. */
11154 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
11155 }
11156 if ( !(u32Eflags & X86_EFL_TF)
11157 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
11158 {
11159 /* Bit 14 is PendingDebug.BS. */
11160 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
11161 }
11162 }
11163
11164 /* VMCS link pointer. */
11165 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
11166 AssertRCBreak(rc);
11167 if (u64Val != UINT64_C(0xffffffffffffffff))
11168 {
11169 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
11170 /** @todo Bits beyond the processor's physical-address width MBZ. */
11171 /** @todo 32-bit located in memory referenced by value of this field (as a
11172 * physical address) must contain the processor's VMCS revision ID. */
11173 /** @todo SMM checks. */
11174 }
11175
11176 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
11177 * not using Nested Paging? */
11178 if ( pVM->hm.s.fNestedPaging
11179 && !fLongModeGuest
11180 && CPUMIsGuestInPAEModeEx(pCtx))
11181 {
11182 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
11183 AssertRCBreak(rc);
11184 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11185
11186 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
11187 AssertRCBreak(rc);
11188 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11189
11190 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
11191 AssertRCBreak(rc);
11192 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11193
11194 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
11195 AssertRCBreak(rc);
11196 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11197 }
11198
11199 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
11200 if (uError == VMX_IGS_ERROR)
11201 uError = VMX_IGS_REASON_NOT_FOUND;
11202 } while (0);
11203
11204 pVCpu->hm.s.u32HMError = uError;
11205 return uError;
11206
11207#undef HMVMX_ERROR_BREAK
11208#undef HMVMX_CHECK_BREAK
11209}
11210
11211/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
11212/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
11213/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
11214
11215/** @name VM-exit handlers.
11216 * @{
11217 */
11218
11219/**
11220 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
11221 */
11222HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11223{
11224 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11225 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
11226 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
11227 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
11228 return VINF_SUCCESS;
11229 return VINF_EM_RAW_INTERRUPT;
11230}
11231
11232
11233/**
11234 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
11235 */
11236HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11237{
11238 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11239 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
11240
11241 int rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
11242 AssertRCReturn(rc, rc);
11243
11244 uint32_t uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo);
11245 Assert( !(pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT)
11246 && uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
11247 Assert(VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
11248
11249 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11250 {
11251 /*
11252 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we injected it ourselves and
11253 * anything we inject is not going to cause a VM-exit directly for the event being injected.
11254 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
11255 *
11256 * Dispatch the NMI to the host. See Intel spec. 27.5.5 "Updating Non-Register State".
11257 */
11258 VMXDispatchHostNmi();
11259 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
11260 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11261 return VINF_SUCCESS;
11262 }
11263
11264 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
11265 VBOXSTRICTRC rcStrictRc1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
11266 if (RT_UNLIKELY(rcStrictRc1 == VINF_SUCCESS))
11267 { /* likely */ }
11268 else
11269 {
11270 if (rcStrictRc1 == VINF_HM_DOUBLE_FAULT)
11271 rcStrictRc1 = VINF_SUCCESS;
11272 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11273 return rcStrictRc1;
11274 }
11275
11276 uint32_t uExitIntInfo = pVmxTransient->uExitIntInfo;
11277 uint32_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(uExitIntInfo);
11278 switch (uIntType)
11279 {
11280 case VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT: /* Privileged software exception. (#DB from ICEBP) */
11281 Assert(uVector == X86_XCPT_DB);
11282 /* no break */
11283 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT: /* Software exception. (#BP or #OF) */
11284 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT);
11285 /* no break */
11286 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT:
11287 {
11288 /*
11289 * If there's any exception caused as a result of event injection, go back to
11290 * the interpreter. The page-fault case is complicated and we manually handle
11291 * any currently pending event in hmR0VmxExitXcptPF. Nested #ACs are already
11292 * handled in hmR0VmxCheckExitDueToEventDelivery.
11293 */
11294 if (!pVCpu->hm.s.Event.fPending)
11295 { /* likely */ }
11296 else if ( uVector != X86_XCPT_PF
11297 && uVector != X86_XCPT_AC)
11298 {
11299 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
11300 rc = VERR_EM_INTERPRETER;
11301 break;
11302 }
11303
11304 switch (uVector)
11305 {
11306 case X86_XCPT_PF: rc = hmR0VmxExitXcptPF(pVCpu, pMixedCtx, pVmxTransient); break;
11307 case X86_XCPT_GP: rc = hmR0VmxExitXcptGP(pVCpu, pMixedCtx, pVmxTransient); break;
11308 case X86_XCPT_NM: rc = hmR0VmxExitXcptNM(pVCpu, pMixedCtx, pVmxTransient); break;
11309 case X86_XCPT_MF: rc = hmR0VmxExitXcptMF(pVCpu, pMixedCtx, pVmxTransient); break;
11310 case X86_XCPT_DB: rc = hmR0VmxExitXcptDB(pVCpu, pMixedCtx, pVmxTransient); break;
11311 case X86_XCPT_BP: rc = hmR0VmxExitXcptBP(pVCpu, pMixedCtx, pVmxTransient); break;
11312 case X86_XCPT_AC: rc = hmR0VmxExitXcptAC(pVCpu, pMixedCtx, pVmxTransient); break;
11313
11314 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF);
11315 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11316 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE);
11317 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11318 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD);
11319 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11320 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS);
11321 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11322 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP);
11323 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11324 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS);
11325 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11326 default:
11327 {
11328 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11329 AssertRCReturn(rc, rc);
11330
11331 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
11332 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
11333 {
11334 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
11335 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
11336 Assert(CPUMIsGuestInRealModeEx(pMixedCtx));
11337
11338 rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
11339 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
11340 AssertRCReturn(rc, rc);
11341 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(uExitIntInfo),
11342 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode,
11343 0 /* GCPtrFaultAddress */);
11344 AssertRCReturn(rc, rc);
11345 }
11346 else
11347 {
11348 AssertMsgFailed(("Unexpected VM-exit caused by exception %#x\n", uVector));
11349 pVCpu->hm.s.u32HMError = uVector;
11350 rc = VERR_VMX_UNEXPECTED_EXCEPTION;
11351 }
11352 break;
11353 }
11354 }
11355 break;
11356 }
11357
11358 default:
11359 {
11360 pVCpu->hm.s.u32HMError = uExitIntInfo;
11361 rc = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
11362 AssertMsgFailed(("Unexpected interruption info %#x\n", VMX_EXIT_INTERRUPTION_INFO_TYPE(uExitIntInfo)));
11363 break;
11364 }
11365 }
11366 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11367 return rc;
11368}
11369
11370
11371/**
11372 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
11373 */
11374HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11375{
11376 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11377
11378 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
11379 hmR0VmxClearIntWindowExitVmcs(pVCpu);
11380
11381 /* Deliver the pending interrupts via hmR0VmxEvaluatePendingEvent() and resume guest execution. */
11382 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
11383 return VINF_SUCCESS;
11384}
11385
11386
11387/**
11388 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
11389 */
11390HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11391{
11392 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11393 if (RT_UNLIKELY(!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT)))
11394 {
11395 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
11396 HMVMX_RETURN_UNEXPECTED_EXIT();
11397 }
11398
11399 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS));
11400
11401 /*
11402 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
11403 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
11404 */
11405 uint32_t uIntrState = 0;
11406 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
11407 AssertRCReturn(rc, rc);
11408
11409 bool const fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
11410 if ( fBlockSti
11411 && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
11412 {
11413 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
11414 }
11415
11416 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
11417 hmR0VmxClearNmiWindowExitVmcs(pVCpu);
11418
11419 /* Deliver the pending NMI via hmR0VmxEvaluatePendingEvent() and resume guest execution. */
11420 return VINF_SUCCESS;
11421}
11422
11423
11424/**
11425 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
11426 */
11427HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11428{
11429 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11430 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWbinvd);
11431 return hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11432}
11433
11434
11435/**
11436 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
11437 */
11438HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11439{
11440 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11441 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvd);
11442 return hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11443}
11444
11445
11446/**
11447 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
11448 */
11449HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11450{
11451 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11452 PVM pVM = pVCpu->CTX_SUFF(pVM);
11453 int rc = EMInterpretCpuId(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11454 if (RT_LIKELY(rc == VINF_SUCCESS))
11455 {
11456 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11457 Assert(pVmxTransient->cbInstr == 2);
11458 }
11459 else
11460 {
11461 AssertMsgFailed(("hmR0VmxExitCpuid: EMInterpretCpuId failed with %Rrc\n", rc));
11462 rc = VERR_EM_INTERPRETER;
11463 }
11464 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCpuid);
11465 return rc;
11466}
11467
11468
11469/**
11470 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
11471 */
11472HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11473{
11474 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11475 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11476 AssertRCReturn(rc, rc);
11477
11478 if (pMixedCtx->cr4 & X86_CR4_SMXE)
11479 return VINF_EM_RAW_EMULATE_INSTR;
11480
11481 AssertMsgFailed(("hmR0VmxExitGetsec: unexpected VM-exit when CR4.SMXE is 0.\n"));
11482 HMVMX_RETURN_UNEXPECTED_EXIT();
11483}
11484
11485
11486/**
11487 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
11488 */
11489HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11490{
11491 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11492 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11493 AssertRCReturn(rc, rc);
11494
11495 PVM pVM = pVCpu->CTX_SUFF(pVM);
11496 rc = EMInterpretRdtsc(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11497 if (RT_LIKELY(rc == VINF_SUCCESS))
11498 {
11499 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11500 Assert(pVmxTransient->cbInstr == 2);
11501 /* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
11502 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING)
11503 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11504 }
11505 else
11506 rc = VERR_EM_INTERPRETER;
11507 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
11508 return rc;
11509}
11510
11511
11512/**
11513 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
11514 */
11515HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11516{
11517 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11518 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11519 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx); /* For MSR_K8_TSC_AUX */
11520 AssertRCReturn(rc, rc);
11521
11522 PVM pVM = pVCpu->CTX_SUFF(pVM);
11523 rc = EMInterpretRdtscp(pVM, pVCpu, pMixedCtx);
11524 if (RT_SUCCESS(rc))
11525 {
11526 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11527 Assert(pVmxTransient->cbInstr == 3);
11528 /* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
11529 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING)
11530 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11531 }
11532 else
11533 {
11534 AssertMsgFailed(("hmR0VmxExitRdtscp: EMInterpretRdtscp failed with %Rrc\n", rc));
11535 rc = VERR_EM_INTERPRETER;
11536 }
11537 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
11538 return rc;
11539}
11540
11541
11542/**
11543 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
11544 */
11545HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11546{
11547 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11548 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11549 rc |= hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11550 AssertRCReturn(rc, rc);
11551
11552 PVM pVM = pVCpu->CTX_SUFF(pVM);
11553 rc = EMInterpretRdpmc(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11554 if (RT_LIKELY(rc == VINF_SUCCESS))
11555 {
11556 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11557 Assert(pVmxTransient->cbInstr == 2);
11558 }
11559 else
11560 {
11561 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
11562 rc = VERR_EM_INTERPRETER;
11563 }
11564 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdpmc);
11565 return rc;
11566}
11567
11568
11569/**
11570 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
11571 */
11572HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11573{
11574 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11575 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
11576
11577 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
11578 if (pVCpu->hm.s.fHypercallsEnabled)
11579 {
11580#if 0
11581 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
11582#else
11583 /* Aggressive state sync. for now. */
11584 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
11585 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* For long-mode checks in gimKvmHypercall(). */
11586 AssertRCReturn(rc, rc);
11587#endif
11588
11589 /* Perform the hypercall. */
11590 rcStrict = GIMHypercall(pVCpu, pMixedCtx);
11591 if (rcStrict == VINF_SUCCESS)
11592 {
11593 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11594 AssertRCReturn(rc, rc);
11595 }
11596 else
11597 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
11598 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
11599 || RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)));
11600
11601 /* If the hypercall changes anything other than guest's general-purpose registers,
11602 we would need to reload the guest changed bits here before VM-entry. */
11603 }
11604 else
11605 Log4(("hmR0VmxExitVmcall: Hypercalls not enabled\n"));
11606
11607 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
11608 if (RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)))
11609 {
11610 hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
11611 rcStrict = VINF_SUCCESS;
11612 }
11613
11614 return rcStrict;
11615}
11616
11617
11618/**
11619 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
11620 */
11621HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11622{
11623 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11624 PVM pVM = pVCpu->CTX_SUFF(pVM);
11625 Assert(!pVM->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
11626
11627 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
11628 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
11629 AssertRCReturn(rc, rc);
11630
11631 VBOXSTRICTRC rcStrict = EMInterpretInvlpg(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), pVmxTransient->uExitQualification);
11632 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
11633 rcStrict = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11634 else
11635 AssertMsg(rcStrict == VERR_EM_INTERPRETER, ("hmR0VmxExitInvlpg: EMInterpretInvlpg %#RX64 failed with %Rrc\n",
11636 pVmxTransient->uExitQualification, VBOXSTRICTRC_VAL(rcStrict)));
11637 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvlpg);
11638 return rcStrict;
11639}
11640
11641
11642/**
11643 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
11644 */
11645HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11646{
11647 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11648 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11649 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
11650 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
11651 AssertRCReturn(rc, rc);
11652
11653 PVM pVM = pVCpu->CTX_SUFF(pVM);
11654 rc = EMInterpretMonitor(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11655 if (RT_LIKELY(rc == VINF_SUCCESS))
11656 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11657 else
11658 {
11659 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMonitor: EMInterpretMonitor failed with %Rrc\n", rc));
11660 rc = VERR_EM_INTERPRETER;
11661 }
11662 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMonitor);
11663 return rc;
11664}
11665
11666
11667/**
11668 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
11669 */
11670HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11671{
11672 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11673 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11674 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
11675 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
11676 AssertRCReturn(rc, rc);
11677
11678 PVM pVM = pVCpu->CTX_SUFF(pVM);
11679 VBOXSTRICTRC rc2 = EMInterpretMWait(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11680 rc = VBOXSTRICTRC_VAL(rc2);
11681 if (RT_LIKELY( rc == VINF_SUCCESS
11682 || rc == VINF_EM_HALT))
11683 {
11684 int rc3 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11685 AssertRCReturn(rc3, rc3);
11686
11687 if ( rc == VINF_EM_HALT
11688 && EMMonitorWaitShouldContinue(pVCpu, pMixedCtx))
11689 {
11690 rc = VINF_SUCCESS;
11691 }
11692 }
11693 else
11694 {
11695 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMwait: EMInterpretMWait failed with %Rrc\n", rc));
11696 rc = VERR_EM_INTERPRETER;
11697 }
11698 AssertMsg(rc == VINF_SUCCESS || rc == VINF_EM_HALT || rc == VERR_EM_INTERPRETER,
11699 ("hmR0VmxExitMwait: failed, invalid error code %Rrc\n", rc));
11700 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMwait);
11701 return rc;
11702}
11703
11704
11705/**
11706 * VM-exit handler for RSM (VMX_EXIT_RSM). Unconditional VM-exit.
11707 */
11708HMVMX_EXIT_NSRC_DECL hmR0VmxExitRsm(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11709{
11710 /*
11711 * Execution of RSM outside of SMM mode causes #UD regardless of VMX root or VMX non-root mode. In theory, we should never
11712 * get this VM-exit. This can happen only if dual-monitor treatment of SMI and VMX is enabled, which can (only?) be done by
11713 * executing VMCALL in VMX root operation. If we get here, something funny is going on.
11714 * See Intel spec. "33.15.5 Enabling the Dual-Monitor Treatment".
11715 */
11716 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11717 AssertMsgFailed(("Unexpected RSM VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11718 HMVMX_RETURN_UNEXPECTED_EXIT();
11719}
11720
11721
11722/**
11723 * VM-exit handler for SMI (VMX_EXIT_SMI). Unconditional VM-exit.
11724 */
11725HMVMX_EXIT_NSRC_DECL hmR0VmxExitSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11726{
11727 /*
11728 * This can only happen if we support dual-monitor treatment of SMI, which can be activated by executing VMCALL in VMX
11729 * root operation. Only an STM (SMM transfer monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL
11730 * in VMX root mode or receive an SMI. If we get here, something funny is going on.
11731 * See Intel spec. "33.15.6 Activating the Dual-Monitor Treatment" and Intel spec. 25.3 "Other Causes of VM-Exits"
11732 */
11733 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11734 AssertMsgFailed(("Unexpected SMI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11735 HMVMX_RETURN_UNEXPECTED_EXIT();
11736}
11737
11738
11739/**
11740 * VM-exit handler for IO SMI (VMX_EXIT_IO_SMI). Unconditional VM-exit.
11741 */
11742HMVMX_EXIT_NSRC_DECL hmR0VmxExitIoSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11743{
11744 /* Same treatment as VMX_EXIT_SMI. See comment in hmR0VmxExitSmi(). */
11745 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11746 AssertMsgFailed(("Unexpected IO SMI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11747 HMVMX_RETURN_UNEXPECTED_EXIT();
11748}
11749
11750
11751/**
11752 * VM-exit handler for SIPI (VMX_EXIT_SIPI). Conditional VM-exit.
11753 */
11754HMVMX_EXIT_NSRC_DECL hmR0VmxExitSipi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11755{
11756 /*
11757 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest activity state is used. We currently
11758 * don't make use of it (see hmR0VmxLoadGuestActivityState()) as our guests don't have direct access to the host LAPIC.
11759 * See Intel spec. 25.3 "Other Causes of VM-exits".
11760 */
11761 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11762 AssertMsgFailed(("Unexpected SIPI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11763 HMVMX_RETURN_UNEXPECTED_EXIT();
11764}
11765
11766
11767/**
11768 * VM-exit handler for INIT signal (VMX_EXIT_INIT_SIGNAL). Unconditional
11769 * VM-exit.
11770 */
11771HMVMX_EXIT_NSRC_DECL hmR0VmxExitInitSignal(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11772{
11773 /*
11774 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
11775 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery" and Intel spec. 29.3 "VMX Instructions" for "VMXON".
11776 *
11777 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these VM-exits.
11778 * See Intel spec. "23.8 Restrictions on VMX operation".
11779 */
11780 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11781 return VINF_SUCCESS;
11782}
11783
11784
11785/**
11786 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
11787 * VM-exit.
11788 */
11789HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11790{
11791 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11792 return VINF_EM_RESET;
11793}
11794
11795
11796/**
11797 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
11798 */
11799HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11800{
11801 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11802 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT);
11803
11804 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11805 AssertRCReturn(rc, rc);
11806
11807 if (EMShouldContinueAfterHalt(pVCpu, pMixedCtx)) /* Requires eflags. */
11808 rc = VINF_SUCCESS;
11809 else
11810 rc = VINF_EM_HALT;
11811
11812 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
11813 if (rc != VINF_SUCCESS)
11814 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
11815 return rc;
11816}
11817
11818
11819/**
11820 * VM-exit handler for instructions that result in a \#UD exception delivered to
11821 * the guest.
11822 */
11823HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11824{
11825 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11826 hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
11827 return VINF_SUCCESS;
11828}
11829
11830
11831/**
11832 * VM-exit handler for expiry of the VMX preemption timer.
11833 */
11834HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11835{
11836 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11837
11838 /* If the preemption-timer has expired, reinitialize the preemption timer on next VM-entry. */
11839 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11840
11841 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
11842 PVM pVM = pVCpu->CTX_SUFF(pVM);
11843 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
11844 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
11845 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
11846}
11847
11848
11849/**
11850 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
11851 */
11852HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11853{
11854 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11855
11856 int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
11857 rc |= hmR0VmxSaveGuestRegsForIemExec(pVCpu, pMixedCtx, false /*fMemory*/, false /*fNeedRsp*/);
11858 rc |= hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11859 AssertRCReturn(rc, rc);
11860
11861 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbInstr);
11862 HMCPU_CF_SET(pVCpu, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS : HM_CHANGED_ALL_GUEST);
11863
11864 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pMixedCtx->cr4 & X86_CR4_OSXSAVE) && pMixedCtx->aXcr[0] != ASMGetXcr0();
11865
11866 return rcStrict;
11867}
11868
11869
11870/**
11871 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
11872 */
11873HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11874{
11875 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11876
11877 /* The guest should not invalidate the host CPU's TLBs, fallback to interpreter. */
11878 /** @todo implement EMInterpretInvpcid() */
11879 return VERR_EM_INTERPRETER;
11880}
11881
11882
11883/**
11884 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE).
11885 * Error VM-exit.
11886 */
11887HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11888{
11889 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
11890 AssertRCReturn(rc, rc);
11891
11892 rc = hmR0VmxCheckVmcsCtls(pVCpu);
11893 AssertRCReturn(rc, rc);
11894
11895 uint32_t uInvalidReason = hmR0VmxCheckGuestState(pVCpu->CTX_SUFF(pVM), pVCpu, pMixedCtx);
11896 NOREF(uInvalidReason);
11897
11898#ifdef VBOX_STRICT
11899 uint32_t uIntrState;
11900 RTHCUINTREG uHCReg;
11901 uint64_t u64Val;
11902 uint32_t u32Val;
11903
11904 rc = hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
11905 rc |= hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
11906 rc |= hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
11907 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
11908 AssertRCReturn(rc, rc);
11909
11910 Log4(("uInvalidReason %u\n", uInvalidReason));
11911 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
11912 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
11913 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
11914 Log4(("VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE %#RX32\n", uIntrState));
11915
11916 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32Val); AssertRC(rc);
11917 Log4(("VMX_VMCS_GUEST_CR0 %#RX32\n", u32Val));
11918 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
11919 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
11920 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
11921 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
11922 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
11923 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
11924 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
11925 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
11926 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
11927 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
11928#else
11929 NOREF(pVmxTransient);
11930#endif
11931
11932 HMDumpRegs(pVCpu->CTX_SUFF(pVM), pVCpu, pMixedCtx);
11933 return VERR_VMX_INVALID_GUEST_STATE;
11934}
11935
11936
11937/**
11938 * VM-exit handler for VM-entry failure due to an MSR-load
11939 * (VMX_EXIT_ERR_MSR_LOAD). Error VM-exit.
11940 */
11941HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrMsrLoad(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11942{
11943 NOREF(pVmxTransient);
11944 AssertMsgFailed(("Unexpected MSR-load exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx)); NOREF(pMixedCtx);
11945 HMVMX_RETURN_UNEXPECTED_EXIT();
11946}
11947
11948
11949/**
11950 * VM-exit handler for VM-entry failure due to a machine-check event
11951 * (VMX_EXIT_ERR_MACHINE_CHECK). Error VM-exit.
11952 */
11953HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrMachineCheck(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11954{
11955 NOREF(pVmxTransient);
11956 AssertMsgFailed(("Unexpected machine-check event exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx)); NOREF(pMixedCtx);
11957 HMVMX_RETURN_UNEXPECTED_EXIT();
11958}
11959
11960
11961/**
11962 * VM-exit handler for all undefined reasons. Should never ever happen.. in
11963 * theory.
11964 */
11965HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUndefined(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11966{
11967 AssertMsgFailed(("Huh!? Undefined VM-exit reason %d. pVCpu=%p pMixedCtx=%p\n", pVmxTransient->uExitReason, pVCpu, pMixedCtx));
11968 NOREF(pVCpu); NOREF(pMixedCtx); NOREF(pVmxTransient);
11969 return VERR_VMX_UNDEFINED_EXIT_CODE;
11970}
11971
11972
11973/**
11974 * VM-exit handler for XDTR (LGDT, SGDT, LIDT, SIDT) accesses
11975 * (VMX_EXIT_XDTR_ACCESS) and LDT and TR access (LLDT, LTR, SLDT, STR).
11976 * Conditional VM-exit.
11977 */
11978HMVMX_EXIT_DECL hmR0VmxExitXdtrAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11979{
11980 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11981
11982 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT. */
11983 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitXdtrAccess);
11984 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT)
11985 return VERR_EM_INTERPRETER;
11986 AssertMsgFailed(("Unexpected XDTR access. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11987 HMVMX_RETURN_UNEXPECTED_EXIT();
11988}
11989
11990
11991/**
11992 * VM-exit handler for RDRAND (VMX_EXIT_RDRAND). Conditional VM-exit.
11993 */
11994HMVMX_EXIT_DECL hmR0VmxExitRdrand(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11995{
11996 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11997
11998 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT. */
11999 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdrand);
12000 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT)
12001 return VERR_EM_INTERPRETER;
12002 AssertMsgFailed(("Unexpected RDRAND exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12003 HMVMX_RETURN_UNEXPECTED_EXIT();
12004}
12005
12006
12007/**
12008 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
12009 */
12010HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12011{
12012 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12013
12014 /* EMInterpretRdmsr() requires CR0, Eflags and SS segment register. */
12015 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
12016 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
12017 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12018 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
12019 {
12020 rc |= hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
12021 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
12022 }
12023 AssertRCReturn(rc, rc);
12024 Log4(("ecx=%#RX32\n", pMixedCtx->ecx));
12025
12026#ifdef VBOX_STRICT
12027 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
12028 {
12029 if ( hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx)
12030 && pMixedCtx->ecx != MSR_K6_EFER)
12031 {
12032 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
12033 pMixedCtx->ecx));
12034 HMVMX_RETURN_UNEXPECTED_EXIT();
12035 }
12036 if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
12037 {
12038 VMXMSREXITREAD enmRead;
12039 VMXMSREXITWRITE enmWrite;
12040 int rc2 = hmR0VmxGetMsrPermission(pVCpu, pMixedCtx->ecx, &enmRead, &enmWrite);
12041 AssertRCReturn(rc2, rc2);
12042 if (enmRead == VMXMSREXIT_PASSTHRU_READ)
12043 {
12044 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", pMixedCtx->ecx));
12045 HMVMX_RETURN_UNEXPECTED_EXIT();
12046 }
12047 }
12048 }
12049#endif
12050
12051 PVM pVM = pVCpu->CTX_SUFF(pVM);
12052 rc = EMInterpretRdmsr(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
12053 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER,
12054 ("hmR0VmxExitRdmsr: failed, invalid error code %Rrc\n", rc));
12055 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
12056 if (RT_SUCCESS(rc))
12057 {
12058 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12059 Assert(pVmxTransient->cbInstr == 2);
12060 }
12061 return rc;
12062}
12063
12064
12065/**
12066 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
12067 */
12068HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12069{
12070 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12071 PVM pVM = pVCpu->CTX_SUFF(pVM);
12072 int rc = VINF_SUCCESS;
12073
12074 /* EMInterpretWrmsr() requires CR0, EFLAGS and SS segment register. */
12075 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
12076 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
12077 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12078 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
12079 {
12080 rc |= hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
12081 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
12082 }
12083 AssertRCReturn(rc, rc);
12084 Log4(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", pMixedCtx->ecx, pMixedCtx->edx, pMixedCtx->eax));
12085
12086 rc = EMInterpretWrmsr(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
12087 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER, ("hmR0VmxExitWrmsr: failed, invalid error code %Rrc\n", rc));
12088 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
12089
12090 if (RT_SUCCESS(rc))
12091 {
12092 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12093
12094 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
12095 if ( pMixedCtx->ecx >= MSR_IA32_X2APIC_START
12096 && pMixedCtx->ecx <= MSR_IA32_X2APIC_END)
12097 {
12098 /* We've already saved the APIC related guest-state (TPR) in hmR0VmxPostRunGuest(). When full APIC register
12099 * virtualization is implemented we'll have to make sure APIC state is saved from the VMCS before
12100 EMInterpretWrmsr() changes it. */
12101 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
12102 }
12103 else if (pMixedCtx->ecx == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
12104 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
12105 else if (pMixedCtx->ecx == MSR_K6_EFER)
12106 {
12107 /*
12108 * If the guest touches EFER we need to update the VM-Entry and VM-Exit controls as well,
12109 * even if it is -not- touching bits that cause paging mode changes (LMA/LME). We care about
12110 * the other bits as well, SCE and NXE. See @bugref{7368}.
12111 */
12112 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_CTLS | HM_CHANGED_VMX_EXIT_CTLS);
12113 }
12114
12115 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not supported. */
12116 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
12117 {
12118 switch (pMixedCtx->ecx)
12119 {
12120 case MSR_IA32_SYSENTER_CS: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
12121 case MSR_IA32_SYSENTER_EIP: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
12122 case MSR_IA32_SYSENTER_ESP: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
12123 case MSR_K8_FS_BASE: /* no break */
12124 case MSR_K8_GS_BASE: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS); break;
12125 case MSR_K6_EFER: /* already handled above */ break;
12126 default:
12127 {
12128 if (hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx))
12129 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
12130 else if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
12131 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS);
12132 break;
12133 }
12134 }
12135 }
12136#ifdef VBOX_STRICT
12137 else
12138 {
12139 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
12140 switch (pMixedCtx->ecx)
12141 {
12142 case MSR_IA32_SYSENTER_CS:
12143 case MSR_IA32_SYSENTER_EIP:
12144 case MSR_IA32_SYSENTER_ESP:
12145 case MSR_K8_FS_BASE:
12146 case MSR_K8_GS_BASE:
12147 {
12148 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", pMixedCtx->ecx));
12149 HMVMX_RETURN_UNEXPECTED_EXIT();
12150 }
12151
12152 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
12153 default:
12154 {
12155 if (hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx))
12156 {
12157 /* EFER writes are always intercepted, see hmR0VmxLoadGuestMsrs(). */
12158 if (pMixedCtx->ecx != MSR_K6_EFER)
12159 {
12160 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
12161 pMixedCtx->ecx));
12162 HMVMX_RETURN_UNEXPECTED_EXIT();
12163 }
12164 }
12165
12166 if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
12167 {
12168 VMXMSREXITREAD enmRead;
12169 VMXMSREXITWRITE enmWrite;
12170 int rc2 = hmR0VmxGetMsrPermission(pVCpu, pMixedCtx->ecx, &enmRead, &enmWrite);
12171 AssertRCReturn(rc2, rc2);
12172 if (enmWrite == VMXMSREXIT_PASSTHRU_WRITE)
12173 {
12174 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", pMixedCtx->ecx));
12175 HMVMX_RETURN_UNEXPECTED_EXIT();
12176 }
12177 }
12178 break;
12179 }
12180 }
12181 }
12182#endif /* VBOX_STRICT */
12183 }
12184 return rc;
12185}
12186
12187
12188/**
12189 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
12190 */
12191HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12192{
12193 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12194
12195 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPause);
12196 return VINF_EM_RAW_INTERRUPT;
12197}
12198
12199
12200/**
12201 * VM-exit handler for when the TPR value is lowered below the specified
12202 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
12203 */
12204HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12205{
12206 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12207 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW);
12208
12209 /*
12210 * The TPR has already been updated, see hmR0VMXPostRunGuest(). RIP is also updated as part of the VM-exit by VT-x. Update
12211 * the threshold in the VMCS, deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectPendingEvent() and
12212 * resume guest execution.
12213 */
12214 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
12215 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
12216 return VINF_SUCCESS;
12217}
12218
12219
12220/**
12221 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
12222 * VM-exit.
12223 *
12224 * @retval VINF_SUCCESS when guest execution can continue.
12225 * @retval VINF_PGM_CHANGE_MODE when shadow paging mode changed, back to ring-3.
12226 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
12227 * @retval VERR_EM_INTERPRETER when something unexpected happened, fallback to
12228 * interpreter.
12229 */
12230HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12231{
12232 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12233 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
12234 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12235 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12236 AssertRCReturn(rc, rc);
12237
12238 RTGCUINTPTR const uExitQualification = pVmxTransient->uExitQualification;
12239 uint32_t const uAccessType = VMX_EXIT_QUALIFICATION_CRX_ACCESS(uExitQualification);
12240 PVM pVM = pVCpu->CTX_SUFF(pVM);
12241 VBOXSTRICTRC rcStrict;
12242 rc = hmR0VmxSaveGuestRegsForIemExec(pVCpu, pMixedCtx, false /*fMemory*/, true /*fNeedRsp*/);
12243 switch (uAccessType)
12244 {
12245 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_WRITE: /* MOV to CRx */
12246 {
12247 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12248 AssertRCReturn(rc, rc);
12249
12250 rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, pVmxTransient->cbInstr,
12251 VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification),
12252 VMX_EXIT_QUALIFICATION_CRX_GENREG(uExitQualification));
12253 AssertMsg( rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT || rcStrict == VINF_PGM_CHANGE_MODE
12254 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12255 switch (VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification))
12256 {
12257 case 0: /* CR0 */
12258 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
12259 Log4(("CRX CR0 write rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr0));
12260 break;
12261 case 2: /* CR2 */
12262 /* Nothing to do here, CR2 it's not part of the VMCS. */
12263 break;
12264 case 3: /* CR3 */
12265 Assert(!pVM->hm.s.fNestedPaging || !CPUMIsGuestPagingEnabledEx(pMixedCtx) || pVCpu->hm.s.fUsingDebugLoop);
12266 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR3);
12267 Log4(("CRX CR3 write rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr3));
12268 break;
12269 case 4: /* CR4 */
12270 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
12271 Log4(("CRX CR4 write rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n",
12272 VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr4, pVCpu->hm.s.fLoadSaveGuestXcr0));
12273 break;
12274 case 8: /* CR8 */
12275 Assert(!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW));
12276 /* CR8 contains the APIC TPR. Was updated by IEMExecDecodedMovCRxWrite(). */
12277 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
12278 break;
12279 default:
12280 AssertMsgFailed(("Invalid CRx register %#x\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)));
12281 break;
12282 }
12283
12284 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxWrite[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
12285 break;
12286 }
12287
12288 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ: /* MOV from CRx */
12289 {
12290 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12291 AssertRCReturn(rc, rc);
12292
12293 Assert( !pVM->hm.s.fNestedPaging
12294 || !CPUMIsGuestPagingEnabledEx(pMixedCtx)
12295 || pVCpu->hm.s.fUsingDebugLoop
12296 || VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification) != 3);
12297
12298 /* CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
12299 Assert( VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification) != 8
12300 || !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW));
12301
12302 rcStrict = IEMExecDecodedMovCRxRead(pVCpu, pVmxTransient->cbInstr,
12303 VMX_EXIT_QUALIFICATION_CRX_GENREG(uExitQualification),
12304 VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification));
12305 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12306 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxRead[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
12307 Log4(("CRX CR%d Read access rcStrict=%Rrc\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification),
12308 VBOXSTRICTRC_VAL(rcStrict)));
12309 break;
12310 }
12311
12312 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_CLTS: /* CLTS (Clear Task-Switch Flag in CR0) */
12313 {
12314 AssertRCReturn(rc, rc);
12315 rcStrict = IEMExecDecodedClts(pVCpu, pVmxTransient->cbInstr);
12316 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12317 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
12318 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
12319 Log4(("CRX CLTS rcStrict=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
12320 break;
12321 }
12322
12323 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
12324 {
12325 AssertRCReturn(rc, rc);
12326 rcStrict = IEMExecDecodedLmsw(pVCpu, pVmxTransient->cbInstr,
12327 VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(uExitQualification));
12328 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT || rcStrict == VINF_PGM_CHANGE_MODE,
12329 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12330 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
12331 Log4(("CRX LMSW rcStrict=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
12332 break;
12333 }
12334
12335 default:
12336 AssertMsgFailedReturn(("Invalid access-type in Mov CRx VM-exit qualification %#x\n", uAccessType),
12337 VERR_VMX_UNEXPECTED_EXCEPTION);
12338 }
12339
12340 HMCPU_CF_SET(pVCpu, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS : HM_CHANGED_ALL_GUEST);
12341 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
12342 NOREF(pVM);
12343 return rcStrict;
12344}
12345
12346
12347/**
12348 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
12349 * VM-exit.
12350 */
12351HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12352{
12353 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12354 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
12355
12356 int rc2 = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12357 rc2 |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12358 rc2 |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
12359 rc2 |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx); /* Eflag checks in EMInterpretDisasCurrent(). */
12360 rc2 |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx); /* CR0 checks & PGM* in EMInterpretDisasCurrent(). */
12361 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* SELM checks in EMInterpretDisasCurrent(). */
12362 /* EFER also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
12363 AssertRCReturn(rc2, rc2);
12364
12365 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
12366 uint32_t uIOPort = VMX_EXIT_QUALIFICATION_IO_PORT(pVmxTransient->uExitQualification);
12367 uint8_t uIOWidth = VMX_EXIT_QUALIFICATION_IO_WIDTH(pVmxTransient->uExitQualification);
12368 bool fIOWrite = ( VMX_EXIT_QUALIFICATION_IO_DIRECTION(pVmxTransient->uExitQualification)
12369 == VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT);
12370 bool fIOString = VMX_EXIT_QUALIFICATION_IO_IS_STRING(pVmxTransient->uExitQualification);
12371 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
12372 bool fDbgStepping = pVCpu->hm.s.fSingleInstruction;
12373 AssertReturn(uIOWidth <= 3 && uIOWidth != 2, VERR_VMX_IPE_1);
12374
12375 /* I/O operation lookup arrays. */
12376 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses. */
12377 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving the result (in AL/AX/EAX). */
12378
12379 VBOXSTRICTRC rcStrict;
12380 uint32_t const cbValue = s_aIOSizes[uIOWidth];
12381 uint32_t const cbInstr = pVmxTransient->cbInstr;
12382 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
12383 PVM pVM = pVCpu->CTX_SUFF(pVM);
12384 if (fIOString)
12385 {
12386#ifdef VBOX_WITH_2ND_IEM_STEP /* This used to gurus with debian 32-bit guest without NP (on ATA reads).
12387 See @bugref{5752#c158}. Should work now. */
12388 /*
12389 * INS/OUTS - I/O String instruction.
12390 *
12391 * Use instruction-information if available, otherwise fall back on
12392 * interpreting the instruction.
12393 */
12394 Log4(("CS:RIP=%04x:%08RX64 %#06x/%u %c str\n", pMixedCtx->cs.Sel, pMixedCtx->rip, uIOPort, cbValue,
12395 fIOWrite ? 'w' : 'r'));
12396 AssertReturn(pMixedCtx->dx == uIOPort, VERR_VMX_IPE_2);
12397 if (MSR_IA32_VMX_BASIC_INFO_VMCS_INS_OUTS(pVM->hm.s.vmx.Msrs.u64BasicInfo))
12398 {
12399 rc2 = hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12400 /** @todo optimize this, IEM should request the additional state if it needs it (GP, PF, ++). */
12401 rc2 |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12402 AssertRCReturn(rc2, rc2);
12403 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
12404 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
12405 IEMMODE enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
12406 bool fRep = VMX_EXIT_QUALIFICATION_IO_IS_REP(pVmxTransient->uExitQualification);
12407 if (fIOWrite)
12408 {
12409 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
12410 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
12411 }
12412 else
12413 {
12414 /*
12415 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
12416 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
12417 * See Intel Instruction spec. for "INS".
12418 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
12419 */
12420 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
12421 }
12422 }
12423 else
12424 {
12425 /** @todo optimize this, IEM should request the additional state if it needs it (GP, PF, ++). */
12426 rc2 = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12427 AssertRCReturn(rc2, rc2);
12428 rcStrict = IEMExecOne(pVCpu);
12429 }
12430 /** @todo IEM needs to be setting these flags somehow. */
12431 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
12432 fUpdateRipAlready = true;
12433#else
12434 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
12435 rcStrict = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL /* pcbInstr */);
12436 if (RT_SUCCESS(rcStrict))
12437 {
12438 if (fIOWrite)
12439 {
12440 rcStrict = IOMInterpretOUTSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix,
12441 (DISCPUMODE)pDis->uAddrMode, cbValue);
12442 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringWrite);
12443 }
12444 else
12445 {
12446 rcStrict = IOMInterpretINSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix,
12447 (DISCPUMODE)pDis->uAddrMode, cbValue);
12448 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringRead);
12449 }
12450 }
12451 else
12452 {
12453 AssertMsg(rcStrict == VERR_EM_INTERPRETER, ("rcStrict=%Rrc RIP=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict),
12454 pMixedCtx->rip));
12455 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
12456 }
12457#endif
12458 }
12459 else
12460 {
12461 /*
12462 * IN/OUT - I/O instruction.
12463 */
12464 Log4(("CS:RIP=%04x:%08RX64 %#06x/%u %c\n", pMixedCtx->cs.Sel, pMixedCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
12465 uint32_t const uAndVal = s_aIOOpAnd[uIOWidth];
12466 Assert(!VMX_EXIT_QUALIFICATION_IO_IS_REP(pVmxTransient->uExitQualification));
12467 if (fIOWrite)
12468 {
12469 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pMixedCtx->eax & uAndVal, cbValue);
12470 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
12471 }
12472 else
12473 {
12474 uint32_t u32Result = 0;
12475 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
12476 if (IOM_SUCCESS(rcStrict))
12477 {
12478 /* Save result of I/O IN instr. in AL/AX/EAX. */
12479 pMixedCtx->eax = (pMixedCtx->eax & ~uAndVal) | (u32Result & uAndVal);
12480 }
12481 else if (rcStrict == VINF_IOM_R3_IOPORT_READ)
12482 HMR0SavePendingIOPortRead(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbValue);
12483 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
12484 }
12485 }
12486
12487 if (IOM_SUCCESS(rcStrict))
12488 {
12489 if (!fUpdateRipAlready)
12490 {
12491 hmR0VmxAdvanceGuestRipBy(pVCpu, pMixedCtx, cbInstr);
12492 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
12493 }
12494
12495 /*
12496 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru while booting Fedora 17 64-bit guest.
12497 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
12498 */
12499 if (fIOString)
12500 {
12501 /** @todo Single-step for INS/OUTS with REP prefix? */
12502 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
12503 }
12504 else if ( !fDbgStepping
12505 && fGstStepping)
12506 {
12507 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
12508 }
12509
12510 /*
12511 * If any I/O breakpoints are armed, we need to check if one triggered
12512 * and take appropriate action.
12513 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
12514 */
12515 rc2 = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
12516 AssertRCReturn(rc2, rc2);
12517
12518 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
12519 * execution engines about whether hyper BPs and such are pending. */
12520 uint32_t const uDr7 = pMixedCtx->dr[7];
12521 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
12522 && X86_DR7_ANY_RW_IO(uDr7)
12523 && (pMixedCtx->cr4 & X86_CR4_DE))
12524 || DBGFBpIsHwIoArmed(pVM)))
12525 {
12526 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
12527
12528 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
12529 VMMRZCallRing3Disable(pVCpu);
12530 HM_DISABLE_PREEMPT();
12531
12532 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
12533
12534 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pMixedCtx, uIOPort, cbValue);
12535 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
12536 {
12537 /* Raise #DB. */
12538 if (fIsGuestDbgActive)
12539 ASMSetDR6(pMixedCtx->dr[6]);
12540 if (pMixedCtx->dr[7] != uDr7)
12541 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
12542
12543 hmR0VmxSetPendingXcptDB(pVCpu, pMixedCtx);
12544 }
12545 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
12546 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
12547 else if ( rcStrict2 != VINF_SUCCESS
12548 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
12549 rcStrict = rcStrict2;
12550 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
12551
12552 HM_RESTORE_PREEMPT();
12553 VMMRZCallRing3Enable(pVCpu);
12554 }
12555 }
12556
12557#ifdef VBOX_STRICT
12558 if (rcStrict == VINF_IOM_R3_IOPORT_READ)
12559 Assert(!fIOWrite);
12560 else if (rcStrict == VINF_IOM_R3_IOPORT_WRITE || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE)
12561 Assert(fIOWrite);
12562 else
12563 {
12564#if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
12565 * statuses, that the VMM device and some others may return. See
12566 * IOM_SUCCESS() for guidance. */
12567 AssertMsg( RT_FAILURE(rcStrict)
12568 || rcStrict == VINF_SUCCESS
12569 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
12570 || rcStrict == VINF_EM_DBG_BREAKPOINT
12571 || rcStrict == VINF_EM_RAW_GUEST_TRAP
12572 || rcStrict == VINF_EM_RAW_TO_R3
12573 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12574#endif
12575 }
12576#endif
12577
12578 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
12579 return rcStrict;
12580}
12581
12582
12583/**
12584 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
12585 * VM-exit.
12586 */
12587HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12588{
12589 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12590
12591 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
12592 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12593 AssertRCReturn(rc, rc);
12594 if (VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_IDT)
12595 {
12596 rc = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
12597 AssertRCReturn(rc, rc);
12598 if (VMX_IDT_VECTORING_INFO_VALID(pVmxTransient->uIdtVectoringInfo))
12599 {
12600 uint32_t uIntType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
12601
12602 uint32_t uVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
12603 bool fErrorCodeValid = VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo);
12604
12605 /* Save it as a pending event and it'll be converted to a TRPM event on the way out to ring-3. */
12606 Assert(!pVCpu->hm.s.Event.fPending);
12607 pVCpu->hm.s.Event.fPending = true;
12608 pVCpu->hm.s.Event.u64IntInfo = pVmxTransient->uIdtVectoringInfo;
12609 rc = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
12610 AssertRCReturn(rc, rc);
12611 if (fErrorCodeValid)
12612 pVCpu->hm.s.Event.u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
12613 else
12614 pVCpu->hm.s.Event.u32ErrCode = 0;
12615 if ( uIntType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
12616 && uVector == X86_XCPT_PF)
12617 {
12618 pVCpu->hm.s.Event.GCPtrFaultAddress = pMixedCtx->cr2;
12619 }
12620
12621 Log4(("Pending event on TaskSwitch uIntType=%#x uVector=%#x\n", uIntType, uVector));
12622 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
12623 return VINF_EM_RAW_INJECT_TRPM_EVENT;
12624 }
12625 }
12626
12627 /* Fall back to the interpreter to emulate the task-switch. */
12628 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
12629 return VERR_EM_INTERPRETER;
12630}
12631
12632
12633/**
12634 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
12635 */
12636HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12637{
12638 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12639 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG);
12640 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG;
12641 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
12642 AssertRCReturn(rc, rc);
12643 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMtf);
12644 return VINF_EM_DBG_STEPPED;
12645}
12646
12647
12648/**
12649 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
12650 */
12651HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12652{
12653 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12654
12655 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
12656
12657 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
12658 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
12659 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
12660 {
12661 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
12662 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
12663 {
12664 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
12665 return VERR_EM_INTERPRETER;
12666 }
12667 }
12668 else
12669 {
12670 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
12671 rcStrict1 = VINF_SUCCESS;
12672 return rcStrict1;
12673 }
12674
12675#if 0
12676 /** @todo Investigate if IOMMMIOPhysHandler() requires a lot of state, for now
12677 * just sync the whole thing. */
12678 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12679#else
12680 /* Aggressive state sync. for now. */
12681 int rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
12682 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12683 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12684#endif
12685 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12686 AssertRCReturn(rc, rc);
12687
12688 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
12689 uint32_t uAccessType = VMX_EXIT_QUALIFICATION_APIC_ACCESS_TYPE(pVmxTransient->uExitQualification);
12690 VBOXSTRICTRC rcStrict2;
12691 switch (uAccessType)
12692 {
12693 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
12694 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
12695 {
12696 AssertMsg( !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
12697 || VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification) != 0x80,
12698 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
12699
12700 RTGCPHYS GCPhys = pMixedCtx->msrApicBase; /* Always up-to-date, msrApicBase is not part of the VMCS. */
12701 GCPhys &= PAGE_BASE_GC_MASK;
12702 GCPhys += VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification);
12703 PVM pVM = pVCpu->CTX_SUFF(pVM);
12704 Log4(("ApicAccess uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
12705 VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification)));
12706
12707 rcStrict2 = IOMMMIOPhysHandler(pVM, pVCpu,
12708 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW,
12709 CPUMCTX2CORE(pMixedCtx), GCPhys);
12710 Log4(("ApicAccess rcStrict2=%d\n", VBOXSTRICTRC_VAL(rcStrict2)));
12711 if ( rcStrict2 == VINF_SUCCESS
12712 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
12713 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
12714 {
12715 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
12716 | HM_CHANGED_GUEST_RSP
12717 | HM_CHANGED_GUEST_RFLAGS
12718 | HM_CHANGED_VMX_GUEST_APIC_STATE);
12719 rcStrict2 = VINF_SUCCESS;
12720 }
12721 break;
12722 }
12723
12724 default:
12725 Log4(("ApicAccess uAccessType=%#x\n", uAccessType));
12726 rcStrict2 = VINF_EM_RAW_EMULATE_INSTR;
12727 break;
12728 }
12729
12730 if (rcStrict2 != VINF_SUCCESS)
12731 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
12732 return rcStrict2;
12733}
12734
12735
12736/**
12737 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
12738 * VM-exit.
12739 */
12740HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12741{
12742 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12743
12744 /* We should -not- get this VM-exit if the guest's debug registers were active. */
12745 if (pVmxTransient->fWasGuestDebugStateActive)
12746 {
12747 AssertMsgFailed(("Unexpected MOV DRx exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12748 HMVMX_RETURN_UNEXPECTED_EXIT();
12749 }
12750
12751 if ( !pVCpu->hm.s.fSingleInstruction
12752 && !pVmxTransient->fWasHyperDebugStateActive)
12753 {
12754 Assert(!DBGFIsStepping(pVCpu));
12755 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
12756
12757 /* Don't intercept MOV DRx any more. */
12758 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
12759 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
12760 AssertRCReturn(rc, rc);
12761
12762 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
12763 VMMRZCallRing3Disable(pVCpu);
12764 HM_DISABLE_PREEMPT();
12765
12766 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
12767 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
12768 Assert(CPUMIsGuestDebugStateActive(pVCpu) || HC_ARCH_BITS == 32);
12769
12770 HM_RESTORE_PREEMPT();
12771 VMMRZCallRing3Enable(pVCpu);
12772
12773#ifdef VBOX_WITH_STATISTICS
12774 rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12775 AssertRCReturn(rc, rc);
12776 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
12777 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
12778 else
12779 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
12780#endif
12781 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
12782 return VINF_SUCCESS;
12783 }
12784
12785 /*
12786 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER, CS. EFER is always up-to-date.
12787 * Update the segment registers and DR7 from the CPU.
12788 */
12789 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12790 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12791 rc |= hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
12792 AssertRCReturn(rc, rc);
12793 Log4(("CS:RIP=%04x:%08RX64\n", pMixedCtx->cs.Sel, pMixedCtx->rip));
12794
12795 PVM pVM = pVCpu->CTX_SUFF(pVM);
12796 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
12797 {
12798 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
12799 VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification),
12800 VMX_EXIT_QUALIFICATION_DRX_GENREG(pVmxTransient->uExitQualification));
12801 if (RT_SUCCESS(rc))
12802 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
12803 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
12804 }
12805 else
12806 {
12807 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
12808 VMX_EXIT_QUALIFICATION_DRX_GENREG(pVmxTransient->uExitQualification),
12809 VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification));
12810 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
12811 }
12812
12813 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
12814 if (RT_SUCCESS(rc))
12815 {
12816 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12817 AssertRCReturn(rc2, rc2);
12818 return VINF_SUCCESS;
12819 }
12820 return rc;
12821}
12822
12823
12824/**
12825 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
12826 * Conditional VM-exit.
12827 */
12828HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12829{
12830 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12831 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
12832
12833 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
12834 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
12835 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
12836 {
12837 /* If event delivery causes an EPT misconfig (MMIO), go back to instruction emulation as otherwise
12838 injecting the original pending event would most likely cause the same EPT misconfig VM-exit. */
12839 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
12840 {
12841 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
12842 return VERR_EM_INTERPRETER;
12843 }
12844 }
12845 else
12846 {
12847 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
12848 rcStrict1 = VINF_SUCCESS;
12849 return rcStrict1;
12850 }
12851
12852 RTGCPHYS GCPhys = 0;
12853 int rc = VMXReadVmcs64(VMX_VMCS64_EXIT_GUEST_PHYS_ADDR_FULL, &GCPhys);
12854
12855#if 0
12856 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx); /** @todo Can we do better? */
12857#else
12858 /* Aggressive state sync. for now. */
12859 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
12860 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12861 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12862#endif
12863 AssertRCReturn(rc, rc);
12864
12865 /*
12866 * If we succeed, resume guest execution.
12867 * If we fail in interpreting the instruction because we couldn't get the guest physical address
12868 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
12869 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
12870 * weird case. See @bugref{6043}.
12871 */
12872 PVM pVM = pVCpu->CTX_SUFF(pVM);
12873 VBOXSTRICTRC rcStrict2 = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pMixedCtx), GCPhys, UINT32_MAX);
12874 Log4(("EPT misconfig at %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pMixedCtx->rip, VBOXSTRICTRC_VAL(rcStrict2)));
12875 if ( rcStrict2 == VINF_SUCCESS
12876 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
12877 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
12878 {
12879 /* Successfully handled MMIO operation. */
12880 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
12881 | HM_CHANGED_GUEST_RSP
12882 | HM_CHANGED_GUEST_RFLAGS
12883 | HM_CHANGED_VMX_GUEST_APIC_STATE);
12884 return VINF_SUCCESS;
12885 }
12886 return rcStrict2;
12887}
12888
12889
12890/**
12891 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
12892 * VM-exit.
12893 */
12894HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12895{
12896 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12897 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
12898
12899 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
12900 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
12901 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
12902 {
12903 /* In the unlikely case that the EPT violation happened as a result of delivering an event, log it. */
12904 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
12905 Log4(("EPT violation with an event pending u64IntInfo=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo));
12906 }
12907 else
12908 {
12909 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
12910 rcStrict1 = VINF_SUCCESS;
12911 return rcStrict1;
12912 }
12913
12914 RTGCPHYS GCPhys = 0;
12915 int rc = VMXReadVmcs64(VMX_VMCS64_EXIT_GUEST_PHYS_ADDR_FULL, &GCPhys);
12916 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12917#if 0
12918 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx); /** @todo Can we do better? */
12919#else
12920 /* Aggressive state sync. for now. */
12921 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
12922 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12923 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12924#endif
12925 AssertRCReturn(rc, rc);
12926
12927 /* Intel spec. Table 27-7 "Exit Qualifications for EPT violations". */
12928 AssertMsg(((pVmxTransient->uExitQualification >> 7) & 3) != 2, ("%#RX64", pVmxTransient->uExitQualification));
12929
12930 RTGCUINT uErrorCode = 0;
12931 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_INSTR_FETCH)
12932 uErrorCode |= X86_TRAP_PF_ID;
12933 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_DATA_WRITE)
12934 uErrorCode |= X86_TRAP_PF_RW;
12935 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_ENTRY_PRESENT)
12936 uErrorCode |= X86_TRAP_PF_P;
12937
12938 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
12939
12940 Log4(("EPT violation %#x at %#RX64 ErrorCode %#x CS:RIP=%04x:%08RX64\n", pVmxTransient->uExitQualification, GCPhys,
12941 uErrorCode, pMixedCtx->cs.Sel, pMixedCtx->rip));
12942
12943 /* Handle the pagefault trap for the nested shadow table. */
12944 PVM pVM = pVCpu->CTX_SUFF(pVM);
12945 VBOXSTRICTRC rcStrict2 = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pMixedCtx), GCPhys);
12946 TRPMResetTrap(pVCpu);
12947
12948 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
12949 if ( rcStrict2 == VINF_SUCCESS
12950 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
12951 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
12952 {
12953 /* Successfully synced our nested page tables. */
12954 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
12955 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
12956 | HM_CHANGED_GUEST_RSP
12957 | HM_CHANGED_GUEST_RFLAGS);
12958 return VINF_SUCCESS;
12959 }
12960
12961 Log4(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)));
12962 return rcStrict2;
12963}
12964
12965/** @} */
12966
12967/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12968/* -=-=-=-=-=-=-=-=-=- VM-exit Exception Handlers -=-=-=-=-=-=-=-=-=-=- */
12969/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12970
12971/** @name VM-exit exception handlers.
12972 * @{
12973 */
12974
12975/**
12976 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
12977 */
12978static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12979{
12980 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
12981 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
12982
12983 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
12984 AssertRCReturn(rc, rc);
12985
12986 if (!(pMixedCtx->cr0 & X86_CR0_NE))
12987 {
12988 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
12989 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
12990
12991 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
12992 * provides VM-exit instruction length. If this causes problem later,
12993 * disassemble the instruction like it's done on AMD-V. */
12994 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12995 AssertRCReturn(rc2, rc2);
12996 return rc;
12997 }
12998
12999 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13000 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13001 return rc;
13002}
13003
13004
13005/**
13006 * VM-exit exception handler for \#BP (Breakpoint exception).
13007 */
13008static int hmR0VmxExitXcptBP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13009{
13010 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13011 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
13012
13013 /** @todo Try optimize this by not saving the entire guest state unless
13014 * really needed. */
13015 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13016 AssertRCReturn(rc, rc);
13017
13018 PVM pVM = pVCpu->CTX_SUFF(pVM);
13019 rc = DBGFRZTrap03Handler(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
13020 if (rc == VINF_EM_RAW_GUEST_TRAP)
13021 {
13022 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13023 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13024 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13025 AssertRCReturn(rc, rc);
13026
13027 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13028 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13029 }
13030
13031 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_EM_DBG_BREAKPOINT);
13032 return rc;
13033}
13034
13035
13036/**
13037 * VM-exit exception handler for \#AC (alignment check exception).
13038 */
13039static int hmR0VmxExitXcptAC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13040{
13041 RT_NOREF_PV(pMixedCtx);
13042 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13043
13044 /*
13045 * Re-inject it. We'll detect any nesting before getting here.
13046 */
13047 int rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13048 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13049 AssertRCReturn(rc, rc);
13050 Assert(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO);
13051
13052 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13053 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13054 return VINF_SUCCESS;
13055}
13056
13057
13058/**
13059 * VM-exit exception handler for \#DB (Debug exception).
13060 */
13061static int hmR0VmxExitXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13062{
13063 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13064 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
13065 Log6(("XcptDB\n"));
13066
13067 /*
13068 * Get the DR6-like values from the VM-exit qualification and pass it to DBGF
13069 * for processing.
13070 */
13071 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
13072 AssertRCReturn(rc, rc);
13073
13074 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
13075 uint64_t uDR6 = X86_DR6_INIT_VAL;
13076 uDR6 |= ( pVmxTransient->uExitQualification
13077 & (X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3 | X86_DR6_BD | X86_DR6_BS));
13078
13079 rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pMixedCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
13080 if (rc == VINF_EM_RAW_GUEST_TRAP)
13081 {
13082 /*
13083 * The exception was for the guest. Update DR6, DR7.GD and
13084 * IA32_DEBUGCTL.LBR before forwarding it.
13085 * (See Intel spec. 27.1 "Architectural State before a VM-Exit".)
13086 */
13087 VMMRZCallRing3Disable(pVCpu);
13088 HM_DISABLE_PREEMPT();
13089
13090 pMixedCtx->dr[6] &= ~X86_DR6_B_MASK;
13091 pMixedCtx->dr[6] |= uDR6;
13092 if (CPUMIsGuestDebugStateActive(pVCpu))
13093 ASMSetDR6(pMixedCtx->dr[6]);
13094
13095 HM_RESTORE_PREEMPT();
13096 VMMRZCallRing3Enable(pVCpu);
13097
13098 rc = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
13099 AssertRCReturn(rc, rc);
13100
13101 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
13102 pMixedCtx->dr[7] &= ~X86_DR7_GD;
13103
13104 /* Paranoia. */
13105 pMixedCtx->dr[7] &= ~X86_DR7_RAZ_MASK;
13106 pMixedCtx->dr[7] |= X86_DR7_RA1_MASK;
13107
13108 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, (uint32_t)pMixedCtx->dr[7]);
13109 AssertRCReturn(rc, rc);
13110
13111 /*
13112 * Raise #DB in the guest.
13113 *
13114 * It is important to reflect what the VM-exit gave us (preserving the interruption-type) rather than use
13115 * hmR0VmxSetPendingXcptDB() as the #DB could've been raised while executing ICEBP and not the 'normal' #DB.
13116 * Thus it -may- trigger different handling in the CPU (like skipped DPL checks). See @bugref{6398}.
13117 *
13118 * Since ICEBP isn't documented on Intel, see AMD spec. 15.20 "Event Injection".
13119 */
13120 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13121 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13122 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13123 AssertRCReturn(rc, rc);
13124 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13125 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13126 return VINF_SUCCESS;
13127 }
13128
13129 /*
13130 * Not a guest trap, must be a hypervisor related debug event then.
13131 * Update DR6 in case someone is interested in it.
13132 */
13133 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
13134 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
13135 CPUMSetHyperDR6(pVCpu, uDR6);
13136
13137 return rc;
13138}
13139
13140
13141/**
13142 * VM-exit exception handler for \#NM (Device-not-available exception: floating
13143 * point exception).
13144 */
13145static int hmR0VmxExitXcptNM(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13146{
13147 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13148
13149 /* We require CR0 and EFER. EFER is always up-to-date. */
13150 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
13151 AssertRCReturn(rc, rc);
13152
13153 /* We're playing with the host CPU state here, have to disable preemption or longjmp. */
13154 VMMRZCallRing3Disable(pVCpu);
13155 HM_DISABLE_PREEMPT();
13156
13157 /* If the guest FPU was active at the time of the #NM exit, then it's a guest fault. */
13158 if (pVmxTransient->fWasGuestFPUStateActive)
13159 {
13160 rc = VINF_EM_RAW_GUEST_TRAP;
13161 Assert(CPUMIsGuestFPUStateActive(pVCpu) || HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0));
13162 }
13163 else
13164 {
13165#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13166 Assert(!pVmxTransient->fWasGuestFPUStateActive || pVCpu->hm.s.fUsingDebugLoop);
13167#endif
13168 rc = CPUMR0Trap07Handler(pVCpu->CTX_SUFF(pVM), pVCpu);
13169 Assert( rc == VINF_EM_RAW_GUEST_TRAP
13170 || ((rc == VINF_SUCCESS || rc == VINF_CPUM_HOST_CR0_MODIFIED) && CPUMIsGuestFPUStateActive(pVCpu)));
13171 if (rc == VINF_CPUM_HOST_CR0_MODIFIED)
13172 HMCPU_CF_SET(pVCpu, HM_CHANGED_HOST_CONTEXT);
13173 }
13174
13175 HM_RESTORE_PREEMPT();
13176 VMMRZCallRing3Enable(pVCpu);
13177
13178 if (rc == VINF_SUCCESS || rc == VINF_CPUM_HOST_CR0_MODIFIED)
13179 {
13180 /* Guest FPU state was activated, we'll want to change CR0 FPU intercepts before the next VM-reentry. */
13181 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
13182 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowNM);
13183 pVCpu->hm.s.fPreloadGuestFpu = true;
13184 }
13185 else
13186 {
13187 /* Forward #NM to the guest. */
13188 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
13189 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13190 AssertRCReturn(rc, rc);
13191 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13192 pVmxTransient->cbInstr, 0 /* error code */, 0 /* GCPtrFaultAddress */);
13193 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNM);
13194 }
13195
13196 return VINF_SUCCESS;
13197}
13198
13199
13200/**
13201 * VM-exit exception handler for \#GP (General-protection exception).
13202 *
13203 * @remarks Requires pVmxTransient->uExitIntInfo to be up-to-date.
13204 */
13205static int hmR0VmxExitXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13206{
13207 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13208 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
13209
13210 int rc;
13211 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
13212 { /* likely */ }
13213 else
13214 {
13215#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13216 Assert(pVCpu->hm.s.fUsingDebugLoop);
13217#endif
13218 /* If the guest is not in real-mode or we have unrestricted execution support, reflect #GP to the guest. */
13219 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13220 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13221 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13222 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13223 AssertRCReturn(rc, rc);
13224 Log4(("#GP Gst: CS:RIP %04x:%08RX64 ErrorCode=%#x CR0=%#RX64 CPL=%u TR=%#04x\n", pMixedCtx->cs.Sel, pMixedCtx->rip,
13225 pVmxTransient->uExitIntErrorCode, pMixedCtx->cr0, CPUMGetGuestCPL(pVCpu), pMixedCtx->tr.Sel));
13226 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13227 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13228 return rc;
13229 }
13230
13231 Assert(CPUMIsGuestInRealModeEx(pMixedCtx));
13232 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
13233
13234 /* EMInterpretDisasCurrent() requires a lot of the state, save the entire state. */
13235 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13236 AssertRCReturn(rc, rc);
13237
13238 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
13239 uint32_t cbOp = 0;
13240 PVM pVM = pVCpu->CTX_SUFF(pVM);
13241 bool fDbgStepping = pVCpu->hm.s.fSingleInstruction;
13242 rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, &cbOp);
13243 if (RT_SUCCESS(rc))
13244 {
13245 rc = VINF_SUCCESS;
13246 Assert(cbOp == pDis->cbInstr);
13247 Log4(("#GP Disas OpCode=%u CS:EIP %04x:%04RX64\n", pDis->pCurInstr->uOpcode, pMixedCtx->cs.Sel, pMixedCtx->rip));
13248 switch (pDis->pCurInstr->uOpcode)
13249 {
13250 case OP_CLI:
13251 {
13252 pMixedCtx->eflags.Bits.u1IF = 0;
13253 pMixedCtx->eflags.Bits.u1RF = 0;
13254 pMixedCtx->rip += pDis->cbInstr;
13255 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13256 if ( !fDbgStepping
13257 && pMixedCtx->eflags.Bits.u1TF)
13258 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13259 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCli);
13260 break;
13261 }
13262
13263 case OP_STI:
13264 {
13265 bool fOldIF = pMixedCtx->eflags.Bits.u1IF;
13266 pMixedCtx->eflags.Bits.u1IF = 1;
13267 pMixedCtx->eflags.Bits.u1RF = 0;
13268 pMixedCtx->rip += pDis->cbInstr;
13269 if (!fOldIF)
13270 {
13271 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
13272 Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
13273 }
13274 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13275 if ( !fDbgStepping
13276 && pMixedCtx->eflags.Bits.u1TF)
13277 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13278 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitSti);
13279 break;
13280 }
13281
13282 case OP_HLT:
13283 {
13284 rc = VINF_EM_HALT;
13285 pMixedCtx->rip += pDis->cbInstr;
13286 pMixedCtx->eflags.Bits.u1RF = 0;
13287 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13288 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
13289 break;
13290 }
13291
13292 case OP_POPF:
13293 {
13294 Log4(("POPF CS:EIP %04x:%04RX64\n", pMixedCtx->cs.Sel, pMixedCtx->rip));
13295 uint32_t cbParm;
13296 uint32_t uMask;
13297 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
13298 if (pDis->fPrefix & DISPREFIX_OPSIZE)
13299 {
13300 cbParm = 4;
13301 uMask = 0xffffffff;
13302 }
13303 else
13304 {
13305 cbParm = 2;
13306 uMask = 0xffff;
13307 }
13308
13309 /* Get the stack pointer & pop the contents of the stack onto Eflags. */
13310 RTGCPTR GCPtrStack = 0;
13311 X86EFLAGS Eflags;
13312 Eflags.u32 = 0;
13313 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
13314 &GCPtrStack);
13315 if (RT_SUCCESS(rc))
13316 {
13317 Assert(sizeof(Eflags.u32) >= cbParm);
13318 rc = VBOXSTRICTRC_TODO(PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &Eflags.u32, cbParm, PGMACCESSORIGIN_HM));
13319 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc)); /** @todo allow strict return codes here */
13320 }
13321 if (RT_FAILURE(rc))
13322 {
13323 rc = VERR_EM_INTERPRETER;
13324 break;
13325 }
13326 Log4(("POPF %#x -> %#RX64 mask=%#x RIP=%#RX64\n", Eflags.u, pMixedCtx->rsp, uMask, pMixedCtx->rip));
13327 pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ~((X86_EFL_POPF_BITS & uMask) | X86_EFL_RF))
13328 | (Eflags.u32 & X86_EFL_POPF_BITS & uMask);
13329 pMixedCtx->esp += cbParm;
13330 pMixedCtx->esp &= uMask;
13331 pMixedCtx->rip += pDis->cbInstr;
13332 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13333 | HM_CHANGED_GUEST_RSP
13334 | HM_CHANGED_GUEST_RFLAGS);
13335 /* Generate a pending-debug exception when the guest stepping over POPF regardless of how
13336 POPF restores EFLAGS.TF. */
13337 if ( !fDbgStepping
13338 && fGstStepping)
13339 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13340 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPopf);
13341 break;
13342 }
13343
13344 case OP_PUSHF:
13345 {
13346 uint32_t cbParm;
13347 uint32_t uMask;
13348 if (pDis->fPrefix & DISPREFIX_OPSIZE)
13349 {
13350 cbParm = 4;
13351 uMask = 0xffffffff;
13352 }
13353 else
13354 {
13355 cbParm = 2;
13356 uMask = 0xffff;
13357 }
13358
13359 /* Get the stack pointer & push the contents of eflags onto the stack. */
13360 RTGCPTR GCPtrStack = 0;
13361 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), (pMixedCtx->esp - cbParm) & uMask,
13362 SELMTOFLAT_FLAGS_CPL0, &GCPtrStack);
13363 if (RT_FAILURE(rc))
13364 {
13365 rc = VERR_EM_INTERPRETER;
13366 break;
13367 }
13368 X86EFLAGS Eflags = pMixedCtx->eflags;
13369 /* The RF & VM bits are cleared on image stored on stack; see Intel Instruction reference for PUSHF. */
13370 Eflags.Bits.u1RF = 0;
13371 Eflags.Bits.u1VM = 0;
13372
13373 rc = VBOXSTRICTRC_TODO(PGMPhysWrite(pVM, (RTGCPHYS)GCPtrStack, &Eflags.u, cbParm, PGMACCESSORIGIN_HM));
13374 if (RT_UNLIKELY(rc != VINF_SUCCESS))
13375 {
13376 AssertMsgFailed(("%Rrc\n", rc)); /** @todo allow strict return codes here */
13377 rc = VERR_EM_INTERPRETER;
13378 break;
13379 }
13380 Log4(("PUSHF %#x -> %#RGv\n", Eflags.u, GCPtrStack));
13381 pMixedCtx->esp -= cbParm;
13382 pMixedCtx->esp &= uMask;
13383 pMixedCtx->rip += pDis->cbInstr;
13384 pMixedCtx->eflags.Bits.u1RF = 0;
13385 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13386 | HM_CHANGED_GUEST_RSP
13387 | HM_CHANGED_GUEST_RFLAGS);
13388 if ( !fDbgStepping
13389 && pMixedCtx->eflags.Bits.u1TF)
13390 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13391 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPushf);
13392 break;
13393 }
13394
13395 case OP_IRET:
13396 {
13397 /** @todo Handle 32-bit operand sizes and check stack limits. See Intel
13398 * instruction reference. */
13399 RTGCPTR GCPtrStack = 0;
13400 uint32_t uMask = 0xffff;
13401 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
13402 uint16_t aIretFrame[3];
13403 if (pDis->fPrefix & (DISPREFIX_OPSIZE | DISPREFIX_ADDRSIZE))
13404 {
13405 rc = VERR_EM_INTERPRETER;
13406 break;
13407 }
13408 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
13409 &GCPtrStack);
13410 if (RT_SUCCESS(rc))
13411 {
13412 rc = VBOXSTRICTRC_TODO(PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &aIretFrame[0], sizeof(aIretFrame),
13413 PGMACCESSORIGIN_HM));
13414 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc)); /** @todo allow strict return codes here */
13415 }
13416 if (RT_FAILURE(rc))
13417 {
13418 rc = VERR_EM_INTERPRETER;
13419 break;
13420 }
13421 pMixedCtx->eip = 0;
13422 pMixedCtx->ip = aIretFrame[0];
13423 pMixedCtx->cs.Sel = aIretFrame[1];
13424 pMixedCtx->cs.ValidSel = aIretFrame[1];
13425 pMixedCtx->cs.u64Base = (uint64_t)pMixedCtx->cs.Sel << 4;
13426 pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ((UINT32_C(0xffff0000) | X86_EFL_1) & ~X86_EFL_RF))
13427 | (aIretFrame[2] & X86_EFL_POPF_BITS & uMask);
13428 pMixedCtx->sp += sizeof(aIretFrame);
13429 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13430 | HM_CHANGED_GUEST_SEGMENT_REGS
13431 | HM_CHANGED_GUEST_RSP
13432 | HM_CHANGED_GUEST_RFLAGS);
13433 /* Generate a pending-debug exception when stepping over IRET regardless of how IRET modifies EFLAGS.TF. */
13434 if ( !fDbgStepping
13435 && fGstStepping)
13436 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13437 Log4(("IRET %#RX32 to %04x:%04x\n", GCPtrStack, pMixedCtx->cs.Sel, pMixedCtx->ip));
13438 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIret);
13439 break;
13440 }
13441
13442 case OP_INT:
13443 {
13444 uint16_t uVector = pDis->Param1.uValue & 0xff;
13445 hmR0VmxSetPendingIntN(pVCpu, pMixedCtx, uVector, pDis->cbInstr);
13446 /* INT clears EFLAGS.TF, we must not set any pending debug exceptions here. */
13447 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
13448 break;
13449 }
13450
13451 case OP_INTO:
13452 {
13453 if (pMixedCtx->eflags.Bits.u1OF)
13454 {
13455 hmR0VmxSetPendingXcptOF(pVCpu, pMixedCtx, pDis->cbInstr);
13456 /* INTO clears EFLAGS.TF, we must not set any pending debug exceptions here. */
13457 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
13458 }
13459 else
13460 {
13461 pMixedCtx->eflags.Bits.u1RF = 0;
13462 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
13463 }
13464 break;
13465 }
13466
13467 default:
13468 {
13469 pMixedCtx->eflags.Bits.u1RF = 0; /* This is correct most of the time... */
13470 VBOXSTRICTRC rc2 = EMInterpretInstructionDisasState(pVCpu, pDis, CPUMCTX2CORE(pMixedCtx), 0 /* pvFault */,
13471 EMCODETYPE_SUPERVISOR);
13472 rc = VBOXSTRICTRC_VAL(rc2);
13473 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
13474 /** @todo We have to set pending-debug exceptions here when the guest is
13475 * single-stepping depending on the instruction that was interpreted. */
13476 Log4(("#GP rc=%Rrc\n", rc));
13477 break;
13478 }
13479 }
13480 }
13481 else
13482 rc = VERR_EM_INTERPRETER;
13483
13484 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_EM_HALT,
13485 ("#GP Unexpected rc=%Rrc\n", rc));
13486 return rc;
13487}
13488
13489
13490/**
13491 * VM-exit exception handler wrapper for generic exceptions. Simply re-injects
13492 * the exception reported in the VMX transient structure back into the VM.
13493 *
13494 * @remarks Requires uExitIntInfo in the VMX transient structure to be
13495 * up-to-date.
13496 */
13497static int hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13498{
13499 RT_NOREF_PV(pMixedCtx);
13500 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13501#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13502 Assert(pVCpu->hm.s.fUsingDebugLoop);
13503#endif
13504
13505 /* Re-inject the exception into the guest. This cannot be a double-fault condition which would have been handled in
13506 hmR0VmxCheckExitDueToEventDelivery(). */
13507 int rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13508 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13509 AssertRCReturn(rc, rc);
13510 Assert(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO);
13511
13512#ifdef DEBUG_ramshankar
13513 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
13514 uint8_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13515 Log(("hmR0VmxExitXcptGeneric: Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
13516#endif
13517
13518 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13519 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13520 return VINF_SUCCESS;
13521}
13522
13523
13524/**
13525 * VM-exit exception handler for \#PF (Page-fault exception).
13526 */
13527static int hmR0VmxExitXcptPF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13528{
13529 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13530 PVM pVM = pVCpu->CTX_SUFF(pVM);
13531 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
13532 rc |= hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13533 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13534 AssertRCReturn(rc, rc);
13535
13536 if (!pVM->hm.s.fNestedPaging)
13537 { /* likely */ }
13538 else
13539 {
13540#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13541 Assert(pVCpu->hm.s.fUsingDebugLoop);
13542#endif
13543 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13544 if (RT_LIKELY(!pVmxTransient->fVectoringDoublePF))
13545 {
13546 pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
13547 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13548 0 /* cbInstr */, pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQualification);
13549 }
13550 else
13551 {
13552 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13553 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
13554 Log4(("Pending #DF due to vectoring #PF. NP\n"));
13555 }
13556 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13557 return rc;
13558 }
13559
13560 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13561 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13562 if (pVmxTransient->fVectoringPF)
13563 {
13564 Assert(pVCpu->hm.s.Event.fPending);
13565 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13566 }
13567
13568 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13569 AssertRCReturn(rc, rc);
13570
13571 Log4(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQualification,
13572 pMixedCtx->cs.Sel, pMixedCtx->rip, pVmxTransient->uExitIntErrorCode, pMixedCtx->cr3));
13573
13574 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQualification, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13575 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pMixedCtx),
13576 (RTGCPTR)pVmxTransient->uExitQualification);
13577
13578 Log4(("#PF: rc=%Rrc\n", rc));
13579 if (rc == VINF_SUCCESS)
13580 {
13581#if 0
13582 /* Successfully synced shadow pages tables or emulated an MMIO instruction. */
13583 /** @todo this isn't quite right, what if guest does lgdt with some MMIO
13584 * memory? We don't update the whole state here... */
13585 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13586 | HM_CHANGED_GUEST_RSP
13587 | HM_CHANGED_GUEST_RFLAGS
13588 | HM_CHANGED_VMX_GUEST_APIC_STATE);
13589#else
13590 /*
13591 * This is typically a shadow page table sync or a MMIO instruction. But we may have
13592 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
13593 */
13594 /** @todo take advantage of CPUM changed flags instead of brute forcing. */
13595 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
13596#endif
13597 TRPMResetTrap(pVCpu);
13598 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
13599 return rc;
13600 }
13601
13602 if (rc == VINF_EM_RAW_GUEST_TRAP)
13603 {
13604 if (!pVmxTransient->fVectoringDoublePF)
13605 {
13606 /* It's a guest page fault and needs to be reflected to the guest. */
13607 uint32_t uGstErrorCode = TRPMGetErrorCode(pVCpu);
13608 TRPMResetTrap(pVCpu);
13609 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
13610 pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
13611 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13612 0 /* cbInstr */, uGstErrorCode, pVmxTransient->uExitQualification);
13613 }
13614 else
13615 {
13616 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13617 TRPMResetTrap(pVCpu);
13618 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
13619 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
13620 Log4(("#PF: Pending #DF due to vectoring #PF\n"));
13621 }
13622
13623 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13624 return VINF_SUCCESS;
13625 }
13626
13627 TRPMResetTrap(pVCpu);
13628 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
13629 return rc;
13630}
13631
13632/** @} */
13633
Note: See TracBrowser for help on using the repository browser.

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