VirtualBox

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

Last change on this file since 64880 was 64880, checked in by vboxsync, 8 years ago

VMM/HMVMXR0: "& 0xf" is redundant while right-shifting a uint8_t by 4 bits. Also comment clarification.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 585.0 KB
Line 
1/* $Id: HMVMXR0.cpp 64880 2016-12-15 14:53:09Z 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.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_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 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 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_ENCLS */ hmR0VmxExitErrUndefined,
512 /* 61 VMX_EXIT_RDSEED */ hmR0VmxExitErrUndefined, /* only spurious exits, so undefined */
513 /* 62 VMX_EXIT_PML_FULL */ 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 /** @todo r=ramshankar: Shouldn't setting up \#UD intercepts be handled by
2653 * hmR0VmxLoadGuestXcptIntercepts()? Why do we check it here? */
2654 uint32_t u32XcptBitmap = pVCpu->hm.s.fGIMTrapXcptUD ? RT_BIT(X86_XCPT_UD) : 0;
2655
2656 /* Must always intercept #AC to prevent the guest from hanging the CPU. */
2657 u32XcptBitmap |= RT_BIT_32(X86_XCPT_AC);
2658
2659 /* Because we need to maintain the DR6 state even when intercepting DRx reads
2660 and writes, and because recursive #DBs can cause the CPU hang, we must always
2661 intercept #DB. */
2662 u32XcptBitmap |= RT_BIT_32(X86_XCPT_DB);
2663
2664 /* Without Nested Paging, #PF must cause a VM-exit so we can sync our shadow page tables. */
2665 if (!pVM->hm.s.fNestedPaging)
2666 u32XcptBitmap |= RT_BIT(X86_XCPT_PF);
2667
2668 pVCpu->hm.s.vmx.u32XcptBitmap = u32XcptBitmap;
2669 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
2670 AssertRCReturn(rc, rc);
2671 return rc;
2672}
2673
2674
2675/**
2676 * Sets up the initial guest-state mask. The guest-state mask is consulted
2677 * before reading guest-state fields from the VMCS as VMREADs can be expensive
2678 * for the nested virtualization case (as it would cause a VM-exit).
2679 *
2680 * @param pVCpu The cross context virtual CPU structure.
2681 */
2682static int hmR0VmxInitUpdatedGuestStateMask(PVMCPU pVCpu)
2683{
2684 /* Initially the guest-state is up-to-date as there is nothing in the VMCS. */
2685 HMVMXCPU_GST_RESET_TO(pVCpu, HMVMX_UPDATED_GUEST_ALL);
2686 return VINF_SUCCESS;
2687}
2688
2689
2690/**
2691 * Does per-VM VT-x initialization.
2692 *
2693 * @returns VBox status code.
2694 * @param pVM The cross context VM structure.
2695 */
2696VMMR0DECL(int) VMXR0InitVM(PVM pVM)
2697{
2698 LogFlowFunc(("pVM=%p\n", pVM));
2699
2700 int rc = hmR0VmxStructsAlloc(pVM);
2701 if (RT_FAILURE(rc))
2702 {
2703 LogRel(("VMXR0InitVM: hmR0VmxStructsAlloc failed! rc=%Rrc\n", rc));
2704 return rc;
2705 }
2706
2707 return VINF_SUCCESS;
2708}
2709
2710
2711/**
2712 * Does per-VM VT-x termination.
2713 *
2714 * @returns VBox status code.
2715 * @param pVM The cross context VM structure.
2716 */
2717VMMR0DECL(int) VMXR0TermVM(PVM pVM)
2718{
2719 LogFlowFunc(("pVM=%p\n", pVM));
2720
2721#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2722 if (pVM->hm.s.vmx.hMemObjScratch != NIL_RTR0MEMOBJ)
2723 ASMMemZero32(pVM->hm.s.vmx.pvScratch, PAGE_SIZE);
2724#endif
2725 hmR0VmxStructsFree(pVM);
2726 return VINF_SUCCESS;
2727}
2728
2729
2730/**
2731 * Sets up the VM for execution under VT-x.
2732 * This function is only called once per-VM during initialization.
2733 *
2734 * @returns VBox status code.
2735 * @param pVM The cross context VM structure.
2736 */
2737VMMR0DECL(int) VMXR0SetupVM(PVM pVM)
2738{
2739 AssertPtrReturn(pVM, VERR_INVALID_PARAMETER);
2740 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2741
2742 LogFlowFunc(("pVM=%p\n", pVM));
2743
2744 /*
2745 * Without UnrestrictedGuest, pRealModeTSS and pNonPagingModeEPTPageTable *must* always be allocated.
2746 * We no longer support the highly unlikely case of UnrestrictedGuest without pRealModeTSS. See hmR3InitFinalizeR0Intel().
2747 */
2748 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
2749 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
2750 || !pVM->hm.s.vmx.pRealModeTSS))
2751 {
2752 LogRel(("VMXR0SetupVM: Invalid real-on-v86 state.\n"));
2753 return VERR_INTERNAL_ERROR;
2754 }
2755
2756 /* Initialize these always, see hmR3InitFinalizeR0().*/
2757 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NONE;
2758 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_NONE;
2759
2760 /* Setup the tagged-TLB flush handlers. */
2761 int rc = hmR0VmxSetupTaggedTlb(pVM);
2762 if (RT_FAILURE(rc))
2763 {
2764 LogRel(("VMXR0SetupVM: hmR0VmxSetupTaggedTlb failed! rc=%Rrc\n", rc));
2765 return rc;
2766 }
2767
2768 /* Check if we can use the VMCS controls for swapping the EFER MSR. */
2769 Assert(!pVM->hm.s.vmx.fSupportsVmcsEfer);
2770#if HC_ARCH_BITS == 64
2771 if ( (pVM->hm.s.vmx.Msrs.VmxEntry.n.allowed1 & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR)
2772 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR)
2773 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR))
2774 {
2775 pVM->hm.s.vmx.fSupportsVmcsEfer = true;
2776 }
2777#endif
2778
2779 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
2780 RTCCUINTREG uHostCR4 = ASMGetCR4();
2781 if (RT_UNLIKELY(!(uHostCR4 & X86_CR4_VMXE)))
2782 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
2783
2784 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2785 {
2786 PVMCPU pVCpu = &pVM->aCpus[i];
2787 AssertPtr(pVCpu);
2788 AssertPtr(pVCpu->hm.s.vmx.pvVmcs);
2789
2790 /* Log the VCPU pointers, useful for debugging SMP VMs. */
2791 Log4(("VMXR0SetupVM: pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
2792
2793 /* Initialize the VM-exit history array with end-of-array markers (UINT16_MAX). */
2794 Assert(!pVCpu->hm.s.idxExitHistoryFree);
2795 HMCPU_EXIT_HISTORY_RESET(pVCpu);
2796
2797 /* Set revision dword at the beginning of the VMCS structure. */
2798 *(uint32_t *)pVCpu->hm.s.vmx.pvVmcs = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.Msrs.u64BasicInfo);
2799
2800 /* Initialize our VMCS region in memory, set the VMCS launch state to "clear". */
2801 rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2802 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVmcs failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2803 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2804
2805 /* Load this VMCS as the current VMCS. */
2806 rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2807 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXActivateVmcs failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2808 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2809
2810 rc = hmR0VmxSetupPinCtls(pVM, pVCpu);
2811 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupPinCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2812 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2813
2814 rc = hmR0VmxSetupProcCtls(pVM, pVCpu);
2815 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupProcCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2816 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2817
2818 rc = hmR0VmxSetupMiscCtls(pVM, pVCpu);
2819 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupMiscCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2820 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2821
2822 rc = hmR0VmxInitXcptBitmap(pVM, pVCpu);
2823 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitXcptBitmap failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2824 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2825
2826 rc = hmR0VmxInitUpdatedGuestStateMask(pVCpu);
2827 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitUpdatedGuestStateMask failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2828 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2829
2830#if HC_ARCH_BITS == 32
2831 rc = hmR0VmxInitVmcsReadCache(pVM, pVCpu);
2832 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitVmcsReadCache failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2833 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2834#endif
2835
2836 /* Re-sync the CPU's internal data into our VMCS memory region & reset the launch state to "clear". */
2837 rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2838 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVmcs(2) failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2839 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2840
2841 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
2842
2843 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc);
2844 }
2845
2846 return VINF_SUCCESS;
2847}
2848
2849
2850/**
2851 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
2852 * the VMCS.
2853 *
2854 * @returns VBox status code.
2855 * @param pVM The cross context VM structure.
2856 * @param pVCpu The cross context virtual CPU structure.
2857 */
2858DECLINLINE(int) hmR0VmxSaveHostControlRegs(PVM pVM, PVMCPU pVCpu)
2859{
2860 NOREF(pVM); NOREF(pVCpu);
2861
2862 RTCCUINTREG uReg = ASMGetCR0();
2863 int rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR0, uReg);
2864 AssertRCReturn(rc, rc);
2865
2866 uReg = ASMGetCR3();
2867 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR3, uReg);
2868 AssertRCReturn(rc, rc);
2869
2870 uReg = ASMGetCR4();
2871 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR4, uReg);
2872 AssertRCReturn(rc, rc);
2873 return rc;
2874}
2875
2876
2877#if HC_ARCH_BITS == 64
2878/**
2879 * Macro for adjusting host segment selectors to satisfy VT-x's VM-entry
2880 * requirements. See hmR0VmxSaveHostSegmentRegs().
2881 */
2882# define VMXLOCAL_ADJUST_HOST_SEG(seg, selValue) \
2883 if ((selValue) & (X86_SEL_RPL | X86_SEL_LDT)) \
2884 { \
2885 bool fValidSelector = true; \
2886 if ((selValue) & X86_SEL_LDT) \
2887 { \
2888 uint32_t uAttr = ASMGetSegAttr((selValue)); \
2889 fValidSelector = RT_BOOL(uAttr != UINT32_MAX && (uAttr & X86_DESC_P)); \
2890 } \
2891 if (fValidSelector) \
2892 { \
2893 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##seg; \
2894 pVCpu->hm.s.vmx.RestoreHost.uHostSel##seg = (selValue); \
2895 } \
2896 (selValue) = 0; \
2897 }
2898#endif
2899
2900
2901/**
2902 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
2903 * the host-state area in the VMCS.
2904 *
2905 * @returns VBox status code.
2906 * @param pVM The cross context VM structure.
2907 * @param pVCpu The cross context virtual CPU structure.
2908 */
2909DECLINLINE(int) hmR0VmxSaveHostSegmentRegs(PVM pVM, PVMCPU pVCpu)
2910{
2911 int rc = VERR_INTERNAL_ERROR_5;
2912
2913#if HC_ARCH_BITS == 64
2914 /*
2915 * If we've executed guest code using VT-x, the host-state bits will be messed up. We
2916 * should -not- save the messed up state without restoring the original host-state. See @bugref{7240}.
2917 *
2918 * This apparently can happen (most likely the FPU changes), deal with it rather than asserting.
2919 * Was observed booting Solaris10u10 32-bit guest.
2920 */
2921 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
2922 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
2923 {
2924 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags,
2925 pVCpu->idCpu));
2926 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
2927 }
2928 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
2929#else
2930 RT_NOREF(pVCpu);
2931#endif
2932
2933 /*
2934 * Host DS, ES, FS and GS segment registers.
2935 */
2936#if HC_ARCH_BITS == 64
2937 RTSEL uSelDS = ASMGetDS();
2938 RTSEL uSelES = ASMGetES();
2939 RTSEL uSelFS = ASMGetFS();
2940 RTSEL uSelGS = ASMGetGS();
2941#else
2942 RTSEL uSelDS = 0;
2943 RTSEL uSelES = 0;
2944 RTSEL uSelFS = 0;
2945 RTSEL uSelGS = 0;
2946#endif
2947
2948 /*
2949 * Host CS and SS segment registers.
2950 */
2951 RTSEL uSelCS = ASMGetCS();
2952 RTSEL uSelSS = ASMGetSS();
2953
2954 /*
2955 * Host TR segment register.
2956 */
2957 RTSEL uSelTR = ASMGetTR();
2958
2959#if HC_ARCH_BITS == 64
2960 /*
2961 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to gain VM-entry and restore them
2962 * before we get preempted. See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
2963 */
2964 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
2965 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
2966 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
2967 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
2968# undef VMXLOCAL_ADJUST_HOST_SEG
2969#endif
2970
2971 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
2972 Assert(!(uSelCS & X86_SEL_RPL)); Assert(!(uSelCS & X86_SEL_LDT));
2973 Assert(!(uSelSS & X86_SEL_RPL)); Assert(!(uSelSS & X86_SEL_LDT));
2974 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
2975 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
2976 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
2977 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
2978 Assert(!(uSelTR & X86_SEL_RPL)); Assert(!(uSelTR & X86_SEL_LDT));
2979 Assert(uSelCS);
2980 Assert(uSelTR);
2981
2982 /* Assertion is right but we would not have updated u32ExitCtls yet. */
2983#if 0
2984 if (!(pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE))
2985 Assert(uSelSS != 0);
2986#endif
2987
2988 /* Write these host selector fields into the host-state area in the VMCS. */
2989 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_CS_SEL, uSelCS);
2990 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_SS_SEL, uSelSS);
2991#if HC_ARCH_BITS == 64
2992 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_DS_SEL, uSelDS);
2993 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_ES_SEL, uSelES);
2994 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_FS_SEL, uSelFS);
2995 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_GS_SEL, uSelGS);
2996#else
2997 NOREF(uSelDS);
2998 NOREF(uSelES);
2999 NOREF(uSelFS);
3000 NOREF(uSelGS);
3001#endif
3002 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_TR_SEL, uSelTR);
3003 AssertRCReturn(rc, rc);
3004
3005 /*
3006 * Host GDTR and IDTR.
3007 */
3008 RTGDTR Gdtr;
3009 RTIDTR Idtr;
3010 RT_ZERO(Gdtr);
3011 RT_ZERO(Idtr);
3012 ASMGetGDTR(&Gdtr);
3013 ASMGetIDTR(&Idtr);
3014 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_GDTR_BASE, Gdtr.pGdt);
3015 rc |= VMXWriteVmcsHstN(VMX_VMCS_HOST_IDTR_BASE, Idtr.pIdt);
3016 AssertRCReturn(rc, rc);
3017
3018#if HC_ARCH_BITS == 64
3019 /*
3020 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps them to the
3021 * maximum limit (0xffff) on every VM-exit.
3022 */
3023 if (Gdtr.cbGdt != 0xffff)
3024 {
3025 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
3026 AssertCompile(sizeof(Gdtr) == sizeof(X86XDTR64));
3027 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
3028 }
3029
3030 /*
3031 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT"
3032 * and Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit as 0xfff, VT-x
3033 * bloating the limit to 0xffff shouldn't cause any different CPU behavior. However, several hosts either insists
3034 * on 0xfff being the limit (Windows Patch Guard) or uses the limit for other purposes (darwin puts the CPU ID in there
3035 * but botches sidt alignment in at least one consumer). So, we're only allowing IDTR.LIMIT to be left at 0xffff on
3036 * hosts where we are pretty sure it won't cause trouble.
3037 */
3038# if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
3039 if (Idtr.cbIdt < 0x0fff)
3040# else
3041 if (Idtr.cbIdt != 0xffff)
3042# endif
3043 {
3044 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
3045 AssertCompile(sizeof(Idtr) == sizeof(X86XDTR64));
3046 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostIdtr, &Idtr, sizeof(X86XDTR64));
3047 }
3048#endif
3049
3050 /*
3051 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI and RPL bits
3052 * is effectively what the CPU does for "scaling by 8". TI is always 0 and RPL should be too in most cases.
3053 */
3054 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= Gdtr.cbGdt,
3055 ("hmR0VmxSaveHostSegmentRegs: TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, Gdtr.cbGdt),
3056 VERR_VMX_INVALID_HOST_STATE);
3057
3058 PCX86DESCHC pDesc = (PCX86DESCHC)(Gdtr.pGdt + (uSelTR & X86_SEL_MASK));
3059#if HC_ARCH_BITS == 64
3060 uintptr_t uTRBase = X86DESC64_BASE(pDesc);
3061
3062 /*
3063 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on all VM-exits.
3064 * The type is the same for 64-bit busy TSS[1]. The limit needs manual restoration if the host has something else.
3065 * Task switching is not supported in 64-bit mode[2], but the limit still matters as IOPM is supported in 64-bit mode.
3066 * Restoring the limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
3067 *
3068 * [1] See Intel spec. 3.5 "System Descriptor Types".
3069 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
3070 */
3071 Assert(pDesc->System.u4Type == 11);
3072 if ( pDesc->System.u16LimitLow != 0x67
3073 || pDesc->System.u4LimitHigh)
3074 {
3075 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
3076 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
3077 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
3078 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
3079 pVCpu->hm.s.vmx.RestoreHost.uHostSelTR = uSelTR;
3080
3081 /* Store the GDTR here as we need it while restoring TR. */
3082 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
3083 }
3084#else
3085 NOREF(pVM);
3086 uintptr_t uTRBase = X86DESC_BASE(pDesc);
3087#endif
3088 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_TR_BASE, uTRBase);
3089 AssertRCReturn(rc, rc);
3090
3091 /*
3092 * Host FS base and GS base.
3093 */
3094#if HC_ARCH_BITS == 64
3095 uint64_t u64FSBase = ASMRdMsr(MSR_K8_FS_BASE);
3096 uint64_t u64GSBase = ASMRdMsr(MSR_K8_GS_BASE);
3097 rc = VMXWriteVmcs64(VMX_VMCS_HOST_FS_BASE, u64FSBase);
3098 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_GS_BASE, u64GSBase);
3099 AssertRCReturn(rc, rc);
3100
3101 /* Store the base if we have to restore FS or GS manually as we need to restore the base as well. */
3102 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_FS)
3103 pVCpu->hm.s.vmx.RestoreHost.uHostFSBase = u64FSBase;
3104 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_GS)
3105 pVCpu->hm.s.vmx.RestoreHost.uHostGSBase = u64GSBase;
3106#endif
3107 return rc;
3108}
3109
3110
3111/**
3112 * Saves certain host MSRs in the VM-exit MSR-load area and some in the
3113 * host-state area of the VMCS. Theses MSRs will be automatically restored on
3114 * the host after every successful VM-exit.
3115 *
3116 * @returns VBox status code.
3117 * @param pVM The cross context VM structure.
3118 * @param pVCpu The cross context virtual CPU structure.
3119 *
3120 * @remarks No-long-jump zone!!!
3121 */
3122DECLINLINE(int) hmR0VmxSaveHostMsrs(PVM pVM, PVMCPU pVCpu)
3123{
3124 NOREF(pVM);
3125
3126 AssertPtr(pVCpu);
3127 AssertPtr(pVCpu->hm.s.vmx.pvHostMsr);
3128
3129 /*
3130 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
3131 * rather than swapping them on every VM-entry.
3132 */
3133 hmR0VmxLazySaveHostMsrs(pVCpu);
3134
3135 /*
3136 * Host Sysenter MSRs.
3137 */
3138 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS));
3139#if HC_ARCH_BITS == 32
3140 rc |= VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP));
3141 rc |= VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP));
3142#else
3143 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP));
3144 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP));
3145#endif
3146 AssertRCReturn(rc, rc);
3147
3148 /*
3149 * Host EFER MSR.
3150 * If the CPU supports the newer VMCS controls for managing EFER, use it.
3151 * Otherwise it's done as part of auto-load/store MSR area in the VMCS, see hmR0VmxLoadGuestMsrs().
3152 */
3153 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
3154 {
3155 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, pVM->hm.s.vmx.u64HostEfer);
3156 AssertRCReturn(rc, rc);
3157 }
3158
3159 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
3160 * hmR0VmxLoadGuestExitCtls() !! */
3161
3162 return rc;
3163}
3164
3165
3166/**
3167 * Figures out if we need to swap the EFER MSR which is particularly expensive.
3168 *
3169 * We check all relevant bits. For now, that's everything besides LMA/LME, as
3170 * these two bits are handled by VM-entry, see hmR0VmxLoadGuestExitCtls() and
3171 * hmR0VMxLoadGuestEntryCtls().
3172 *
3173 * @returns true if we need to load guest EFER, false otherwise.
3174 * @param pVCpu The cross context virtual CPU structure.
3175 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3176 * out-of-sync. Make sure to update the required fields
3177 * before using them.
3178 *
3179 * @remarks Requires EFER, CR4.
3180 * @remarks No-long-jump zone!!!
3181 */
3182static bool hmR0VmxShouldSwapEferMsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3183{
3184#ifdef HMVMX_ALWAYS_SWAP_EFER
3185 return true;
3186#endif
3187
3188#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
3189 /* For 32-bit hosts running 64-bit guests, we always swap EFER in the world-switcher. Nothing to do here. */
3190 if (CPUMIsGuestInLongMode(pVCpu))
3191 return false;
3192#endif
3193
3194 PVM pVM = pVCpu->CTX_SUFF(pVM);
3195 uint64_t u64HostEfer = pVM->hm.s.vmx.u64HostEfer;
3196 uint64_t u64GuestEfer = pMixedCtx->msrEFER;
3197
3198 /*
3199 * For 64-bit guests, if EFER.SCE bit differs, we need to swap to ensure that the
3200 * guest's SYSCALL behaviour isn't screwed. See @bugref{7386}.
3201 */
3202 if ( CPUMIsGuestInLongMode(pVCpu)
3203 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
3204 {
3205 return true;
3206 }
3207
3208 /*
3209 * If the guest uses PAE and EFER.NXE bit differs, we need to swap EFER as it
3210 * affects guest paging. 64-bit paging implies CR4.PAE as well.
3211 * See Intel spec. 4.5 "IA-32e Paging" and Intel spec. 4.1.1 "Three Paging Modes".
3212 */
3213 if ( (pMixedCtx->cr4 & X86_CR4_PAE)
3214 && (pMixedCtx->cr0 & X86_CR0_PG)
3215 && (u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
3216 {
3217 /* Assert that host is PAE capable. */
3218 Assert(pVM->hm.s.cpuid.u32AMDFeatureEDX & X86_CPUID_EXT_FEATURE_EDX_NX);
3219 return true;
3220 }
3221
3222 /** @todo Check the latest Intel spec. for any other bits,
3223 * like SMEP/SMAP? */
3224 return false;
3225}
3226
3227
3228/**
3229 * Sets up VM-entry controls in the VMCS. These controls can affect things done
3230 * on VM-exit; e.g. "load debug controls", see Intel spec. 24.8.1 "VM-entry
3231 * controls".
3232 *
3233 * @returns VBox status code.
3234 * @param pVCpu The cross context virtual CPU structure.
3235 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3236 * out-of-sync. Make sure to update the required fields
3237 * before using them.
3238 *
3239 * @remarks Requires EFER.
3240 * @remarks No-long-jump zone!!!
3241 */
3242DECLINLINE(int) hmR0VmxLoadGuestEntryCtls(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3243{
3244 int rc = VINF_SUCCESS;
3245 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_ENTRY_CTLS))
3246 {
3247 PVM pVM = pVCpu->CTX_SUFF(pVM);
3248 uint32_t val = pVM->hm.s.vmx.Msrs.VmxEntry.n.disallowed0; /* Bits set here must be set in the VMCS. */
3249 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxEntry.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3250
3251 /* Load debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x capable CPUs only supports the 1-setting of this bit. */
3252 val |= VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG;
3253
3254 /* Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry. */
3255 if (CPUMIsGuestInLongModeEx(pMixedCtx))
3256 {
3257 val |= VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST;
3258 Log4(("Load[%RU32]: VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST\n", pVCpu->idCpu));
3259 }
3260 else
3261 Assert(!(val & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST));
3262
3263 /* If the CPU supports the newer VMCS controls for managing guest/host EFER, use it. */
3264 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
3265 && hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
3266 {
3267 val |= VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR;
3268 Log4(("Load[%RU32]: VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR\n", pVCpu->idCpu));
3269 }
3270
3271 /*
3272 * The following should -not- be set (since we're not in SMM mode):
3273 * - VMX_VMCS_CTRL_ENTRY_ENTRY_SMM
3274 * - VMX_VMCS_CTRL_ENTRY_DEACTIVATE_DUALMON
3275 */
3276
3277 /** @todo VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PERF_MSR,
3278 * VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PAT_MSR. */
3279
3280 if ((val & zap) != val)
3281 {
3282 LogRel(("hmR0VmxLoadGuestEntryCtls: Invalid VM-entry controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
3283 pVM->hm.s.vmx.Msrs.VmxEntry.n.disallowed0, val, zap));
3284 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
3285 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3286 }
3287
3288 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, val);
3289 AssertRCReturn(rc, rc);
3290
3291 pVCpu->hm.s.vmx.u32EntryCtls = val;
3292 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_ENTRY_CTLS);
3293 }
3294 return rc;
3295}
3296
3297
3298/**
3299 * Sets up the VM-exit controls in the VMCS.
3300 *
3301 * @returns VBox status code.
3302 * @param pVCpu The cross context virtual CPU structure.
3303 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3304 * out-of-sync. Make sure to update the required fields
3305 * before using them.
3306 *
3307 * @remarks Requires EFER.
3308 */
3309DECLINLINE(int) hmR0VmxLoadGuestExitCtls(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3310{
3311 NOREF(pMixedCtx);
3312
3313 int rc = VINF_SUCCESS;
3314 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_EXIT_CTLS))
3315 {
3316 PVM pVM = pVCpu->CTX_SUFF(pVM);
3317 uint32_t val = pVM->hm.s.vmx.Msrs.VmxExit.n.disallowed0; /* Bits set here must be set in the VMCS. */
3318 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3319
3320 /* Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only supported the 1-setting of this bit. */
3321 val |= VMX_VMCS_CTRL_EXIT_SAVE_DEBUG;
3322
3323 /*
3324 * Set the host long mode active (EFER.LMA) bit (which Intel calls "Host address-space size") if necessary.
3325 * On VM-exit, VT-x sets both the host EFER.LMA and EFER.LME bit to this value. See assertion in hmR0VmxSaveHostMsrs().
3326 */
3327#if HC_ARCH_BITS == 64
3328 val |= VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE;
3329 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE\n", pVCpu->idCpu));
3330#else
3331 Assert( pVCpu->hm.s.vmx.pfnStartVM == VMXR0SwitcherStartVM64
3332 || pVCpu->hm.s.vmx.pfnStartVM == VMXR0StartVM32);
3333 /* Set the host address-space size based on the switcher, not guest state. See @bugref{8432}. */
3334 if (pVCpu->hm.s.vmx.pfnStartVM == VMXR0SwitcherStartVM64)
3335 {
3336 /* The switcher returns to long mode, EFER is managed by the switcher. */
3337 val |= VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE;
3338 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE\n", pVCpu->idCpu));
3339 }
3340 else
3341 Assert(!(val & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE));
3342#endif
3343
3344 /* If the newer VMCS fields for managing EFER exists, use it. */
3345 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
3346 && hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
3347 {
3348 val |= VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR
3349 | VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR;
3350 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR, VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR\n", pVCpu->idCpu));
3351 }
3352
3353 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
3354 Assert(!(val & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT));
3355
3356 /** @todo VMX_VMCS_CTRL_EXIT_LOAD_PERF_MSR,
3357 * VMX_VMCS_CTRL_EXIT_SAVE_GUEST_PAT_MSR,
3358 * VMX_VMCS_CTRL_EXIT_LOAD_HOST_PAT_MSR. */
3359
3360 if ( pVM->hm.s.vmx.fUsePreemptTimer
3361 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_SAVE_VMX_PREEMPT_TIMER))
3362 val |= VMX_VMCS_CTRL_EXIT_SAVE_VMX_PREEMPT_TIMER;
3363
3364 if ((val & zap) != val)
3365 {
3366 LogRel(("hmR0VmxSetupProcCtls: Invalid VM-exit controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
3367 pVM->hm.s.vmx.Msrs.VmxExit.n.disallowed0, val, zap));
3368 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
3369 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3370 }
3371
3372 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, val);
3373 AssertRCReturn(rc, rc);
3374
3375 pVCpu->hm.s.vmx.u32ExitCtls = val;
3376 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_EXIT_CTLS);
3377 }
3378 return rc;
3379}
3380
3381
3382/**
3383 * Sets the TPR threshold in the VMCS.
3384 *
3385 * @returns VBox status code.
3386 * @param pVCpu The cross context virtual CPU structure.
3387 * @param u32TprThreshold The TPR threshold (task-priority class only).
3388 */
3389DECLINLINE(int) hmR0VmxApicSetTprThreshold(PVMCPU pVCpu, uint32_t u32TprThreshold)
3390{
3391 Assert(!(u32TprThreshold & 0xfffffff0)); /* Bits 31:4 MBZ. */
3392 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW); RT_NOREF_PV(pVCpu);
3393 return VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
3394}
3395
3396
3397/**
3398 * Loads the guest APIC and related state.
3399 *
3400 * @returns VBox status code.
3401 * @param pVCpu The cross context virtual CPU structure.
3402 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3403 * out-of-sync. Make sure to update the required fields
3404 * before using them.
3405 */
3406DECLINLINE(int) hmR0VmxLoadGuestApicState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3407{
3408 NOREF(pMixedCtx);
3409
3410 int rc = VINF_SUCCESS;
3411 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE))
3412 {
3413 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
3414 && APICIsEnabled(pVCpu))
3415 {
3416 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
3417 {
3418 Assert(pVCpu->hm.s.vmx.HCPhysVirtApic);
3419
3420 bool fPendingIntr = false;
3421 uint8_t u8Tpr = 0;
3422 uint8_t u8PendingIntr = 0;
3423 rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
3424 AssertRCReturn(rc, rc);
3425
3426 /*
3427 * If there are interrupts pending but masked by the TPR, instruct VT-x to cause a TPR-below-threshold VM-exit
3428 * when the guest lowers its TPR below the priority of the pending interrupt so we can deliver the interrupt.
3429 * If there are no interrupts pending, set threshold to 0 to not cause any TPR-below-threshold VM-exits.
3430 */
3431 pVCpu->hm.s.vmx.pbVirtApic[XAPIC_OFF_TPR] = u8Tpr;
3432 uint32_t u32TprThreshold = 0;
3433 if (fPendingIntr)
3434 {
3435 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR (which is the Task-Priority Class). */
3436 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
3437 const uint8_t u8TprPriority = u8Tpr >> 4;
3438 if (u8PendingPriority <= u8TprPriority)
3439 u32TprThreshold = u8PendingPriority;
3440 else
3441 u32TprThreshold = u8TprPriority; /* Required for Vista 64-bit guest, see @bugref{6398}. */
3442 }
3443
3444 rc = hmR0VmxApicSetTprThreshold(pVCpu, u32TprThreshold);
3445 AssertRCReturn(rc, rc);
3446 }
3447
3448#ifndef IEM_VERIFICATION_MODE_FULL
3449 /* Setup the Virtualized APIC accesses. */
3450 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC)
3451 {
3452 uint64_t u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
3453 if (u64MsrApicBase != pVCpu->hm.s.vmx.u64MsrApicBase)
3454 {
3455 PVM pVM = pVCpu->CTX_SUFF(pVM);
3456 Assert(pVM->hm.s.vmx.HCPhysApicAccess);
3457 RTGCPHYS GCPhysApicBase;
3458 GCPhysApicBase = u64MsrApicBase;
3459 GCPhysApicBase &= PAGE_BASE_GC_MASK;
3460
3461 /* Unalias any existing mapping. */
3462 rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
3463 AssertRCReturn(rc, rc);
3464
3465 /* Map the HC APIC-access page into the GC space, this also updates the shadow page tables if necessary. */
3466 Log4(("Mapped HC APIC-access page into GC: GCPhysApicBase=%#RGp\n", GCPhysApicBase));
3467 rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
3468 AssertRCReturn(rc, rc);
3469
3470 /* Update VMX's cache of the APIC base. */
3471 pVCpu->hm.s.vmx.u64MsrApicBase = u64MsrApicBase;
3472 }
3473 }
3474#endif /* !IEM_VERIFICATION_MODE_FULL */
3475 }
3476 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
3477 }
3478
3479 return rc;
3480}
3481
3482
3483/**
3484 * Gets the guest's interruptibility-state ("interrupt shadow" as AMD calls it).
3485 *
3486 * @returns Guest's interruptibility-state.
3487 * @param pVCpu The cross context virtual CPU structure.
3488 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3489 * out-of-sync. Make sure to update the required fields
3490 * before using them.
3491 *
3492 * @remarks No-long-jump zone!!!
3493 */
3494DECLINLINE(uint32_t) hmR0VmxGetGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3495{
3496 /*
3497 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
3498 */
3499 uint32_t uIntrState = 0;
3500 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
3501 {
3502 /* If inhibition is active, RIP & RFLAGS should've been accessed (i.e. read previously from the VMCS or from ring-3). */
3503 AssertMsg(HMVMXCPU_GST_IS_SET(pVCpu, HMVMX_UPDATED_GUEST_RIP | HMVMX_UPDATED_GUEST_RFLAGS),
3504 ("%#x\n", HMVMXCPU_GST_VALUE(pVCpu)));
3505 if (pMixedCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
3506 {
3507 if (pMixedCtx->eflags.Bits.u1IF)
3508 uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
3509 else
3510 uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS;
3511 }
3512 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
3513 {
3514 /*
3515 * We can clear the inhibit force flag as even if we go back to the recompiler without executing guest code in
3516 * VT-x, the flag's condition to be cleared is met and thus the cleared state is correct.
3517 */
3518 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
3519 }
3520 }
3521
3522 /*
3523 * NMIs to the guest are blocked after an NMI is injected until the guest executes an IRET. We only
3524 * bother with virtual-NMI blocking when we have support for virtual NMIs in the CPU, otherwise
3525 * setting this would block host-NMIs and IRET will not clear the blocking.
3526 *
3527 * See Intel spec. 26.6.1 "Interruptibility state". See @bugref{7445}.
3528 */
3529 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS)
3530 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
3531 {
3532 uIntrState |= VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI;
3533 }
3534
3535 return uIntrState;
3536}
3537
3538
3539/**
3540 * Loads the guest's interruptibility-state into the guest-state area in the
3541 * VMCS.
3542 *
3543 * @returns VBox status code.
3544 * @param pVCpu The cross context virtual CPU structure.
3545 * @param uIntrState The interruptibility-state to set.
3546 */
3547static int hmR0VmxLoadGuestIntrState(PVMCPU pVCpu, uint32_t uIntrState)
3548{
3549 NOREF(pVCpu);
3550 AssertMsg(!(uIntrState & 0xfffffff0), ("%#x\n", uIntrState)); /* Bits 31:4 MBZ. */
3551 Assert((uIntrState & 0x3) != 0x3); /* Block-by-STI and MOV SS cannot be simultaneously set. */
3552 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, uIntrState);
3553 AssertRC(rc);
3554 return rc;
3555}
3556
3557
3558/**
3559 * Loads the exception intercepts required for guest execution in the VMCS.
3560 *
3561 * @returns VBox status code.
3562 * @param pVCpu The cross context virtual CPU structure.
3563 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3564 * out-of-sync. Make sure to update the required fields
3565 * before using them.
3566 */
3567static int hmR0VmxLoadGuestXcptIntercepts(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3568{
3569 NOREF(pMixedCtx);
3570 int rc = VINF_SUCCESS;
3571 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
3572 {
3573 /* The remaining exception intercepts are handled elsewhere, e.g. in hmR0VmxLoadSharedCR0(). */
3574 if (pVCpu->hm.s.fGIMTrapXcptUD)
3575 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_UD);
3576#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
3577 else
3578 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_UD);
3579#endif
3580
3581 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_AC));
3582 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
3583
3584 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
3585 AssertRCReturn(rc, rc);
3586
3587 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
3588 Log4(("Load[%RU32]: VMX_VMCS32_CTRL_EXCEPTION_BITMAP=%#RX64 fContextUseFlags=%#RX32\n", pVCpu->idCpu,
3589 pVCpu->hm.s.vmx.u32XcptBitmap, HMCPU_CF_VALUE(pVCpu)));
3590 }
3591 return rc;
3592}
3593
3594
3595/**
3596 * Loads the guest's RIP into the guest-state area in the VMCS.
3597 *
3598 * @returns VBox status code.
3599 * @param pVCpu The cross context virtual CPU structure.
3600 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3601 * out-of-sync. Make sure to update the required fields
3602 * before using them.
3603 *
3604 * @remarks No-long-jump zone!!!
3605 */
3606static int hmR0VmxLoadGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3607{
3608 int rc = VINF_SUCCESS;
3609 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RIP))
3610 {
3611 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_RIP, pMixedCtx->rip);
3612 AssertRCReturn(rc, rc);
3613
3614 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RIP);
3615 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RIP=%#RX64 fContextUseFlags=%#RX32\n", pVCpu->idCpu, pMixedCtx->rip,
3616 HMCPU_CF_VALUE(pVCpu)));
3617 }
3618 return rc;
3619}
3620
3621
3622/**
3623 * Loads the guest's RSP into the guest-state area in the VMCS.
3624 *
3625 * @returns VBox status code.
3626 * @param pVCpu The cross context virtual CPU structure.
3627 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3628 * out-of-sync. Make sure to update the required fields
3629 * before using them.
3630 *
3631 * @remarks No-long-jump zone!!!
3632 */
3633static int hmR0VmxLoadGuestRsp(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3634{
3635 int rc = VINF_SUCCESS;
3636 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RSP))
3637 {
3638 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_RSP, pMixedCtx->rsp);
3639 AssertRCReturn(rc, rc);
3640
3641 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RSP);
3642 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RSP=%#RX64\n", pVCpu->idCpu, pMixedCtx->rsp));
3643 }
3644 return rc;
3645}
3646
3647
3648/**
3649 * Loads the guest's RFLAGS into the guest-state area in the VMCS.
3650 *
3651 * @returns VBox status code.
3652 * @param pVCpu The cross context virtual CPU structure.
3653 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3654 * out-of-sync. Make sure to update the required fields
3655 * before using them.
3656 *
3657 * @remarks No-long-jump zone!!!
3658 */
3659static int hmR0VmxLoadGuestRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3660{
3661 int rc = VINF_SUCCESS;
3662 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RFLAGS))
3663 {
3664 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
3665 Let us assert it as such and use 32-bit VMWRITE. */
3666 Assert(!(pMixedCtx->rflags.u64 >> 32));
3667 X86EFLAGS Eflags = pMixedCtx->eflags;
3668 /** @todo r=bird: There shall be no need to OR in X86_EFL_1 here, nor
3669 * shall there be any reason for clearing bits 63:22, 15, 5 and 3.
3670 * These will never be cleared/set, unless some other part of the VMM
3671 * code is buggy - in which case we're better of finding and fixing
3672 * those bugs than hiding them. */
3673 Assert(Eflags.u32 & X86_EFL_RA1_MASK);
3674 Assert(!(Eflags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
3675 Eflags.u32 &= VMX_EFLAGS_RESERVED_0; /* Bits 22-31, 15, 5 & 3 MBZ. */
3676 Eflags.u32 |= VMX_EFLAGS_RESERVED_1; /* Bit 1 MB1. */
3677
3678 /*
3679 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so we can restore them on VM-exit.
3680 * Modify the real-mode guest's eflags so that VT-x can run the real-mode guest code under Virtual 8086 mode.
3681 */
3682 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3683 {
3684 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
3685 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
3686 pVCpu->hm.s.vmx.RealMode.Eflags.u32 = Eflags.u32; /* Save the original eflags of the real-mode guest. */
3687 Eflags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
3688 Eflags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
3689 }
3690
3691 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_RFLAGS, Eflags.u32);
3692 AssertRCReturn(rc, rc);
3693
3694 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RFLAGS);
3695 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RFLAGS=%#RX32\n", pVCpu->idCpu, Eflags.u32));
3696 }
3697 return rc;
3698}
3699
3700
3701/**
3702 * Loads the guest RIP, RSP and RFLAGS into the guest-state area in the VMCS.
3703 *
3704 * @returns VBox status code.
3705 * @param pVCpu The cross context virtual CPU structure.
3706 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3707 * out-of-sync. Make sure to update the required fields
3708 * before using them.
3709 *
3710 * @remarks No-long-jump zone!!!
3711 */
3712DECLINLINE(int) hmR0VmxLoadGuestRipRspRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3713{
3714 int rc = hmR0VmxLoadGuestRip(pVCpu, pMixedCtx);
3715 rc |= hmR0VmxLoadGuestRsp(pVCpu, pMixedCtx);
3716 rc |= hmR0VmxLoadGuestRflags(pVCpu, pMixedCtx);
3717 AssertRCReturn(rc, rc);
3718 return rc;
3719}
3720
3721
3722/**
3723 * Loads the guest CR0 control register into the guest-state area in the VMCS.
3724 * CR0 is partially shared with the host and we have to consider the FPU bits.
3725 *
3726 * @returns VBox status code.
3727 * @param pVCpu The cross context virtual CPU structure.
3728 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3729 * out-of-sync. Make sure to update the required fields
3730 * before using them.
3731 *
3732 * @remarks No-long-jump zone!!!
3733 */
3734static int hmR0VmxLoadSharedCR0(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3735{
3736 /*
3737 * Guest CR0.
3738 * Guest FPU.
3739 */
3740 int rc = VINF_SUCCESS;
3741 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
3742 {
3743 Assert(!(pMixedCtx->cr0 >> 32));
3744 uint32_t u32GuestCR0 = pMixedCtx->cr0;
3745 PVM pVM = pVCpu->CTX_SUFF(pVM);
3746
3747 /* The guest's view (read access) of its CR0 is unblemished. */
3748 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_READ_SHADOW, u32GuestCR0);
3749 AssertRCReturn(rc, rc);
3750 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR0_READ_SHADOW=%#RX32\n", pVCpu->idCpu, u32GuestCR0));
3751
3752 /* Setup VT-x's view of the guest CR0. */
3753 /* Minimize VM-exits due to CR3 changes when we have NestedPaging. */
3754 if (pVM->hm.s.fNestedPaging)
3755 {
3756 if (CPUMIsGuestPagingEnabledEx(pMixedCtx))
3757 {
3758 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
3759 pVCpu->hm.s.vmx.u32ProcCtls &= ~( VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
3760 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT);
3761 }
3762 else
3763 {
3764 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
3765 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
3766 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
3767 }
3768
3769 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
3770 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3771 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
3772
3773 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
3774 AssertRCReturn(rc, rc);
3775 }
3776 else
3777 u32GuestCR0 |= X86_CR0_WP; /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
3778
3779 /*
3780 * Guest FPU bits.
3781 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be set on the first
3782 * CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
3783 */
3784 u32GuestCR0 |= X86_CR0_NE;
3785 bool fInterceptNM = false;
3786 if (CPUMIsGuestFPUStateActive(pVCpu))
3787 {
3788 fInterceptNM = false; /* Guest FPU active, no need to VM-exit on #NM. */
3789 /* The guest should still get #NM exceptions when it expects it to, so we should not clear TS & MP bits here.
3790 We're only concerned about -us- not intercepting #NMs when the guest-FPU is active. Not the guest itself! */
3791 }
3792 else
3793 {
3794 fInterceptNM = true; /* Guest FPU inactive, VM-exit on #NM for lazy FPU loading. */
3795 u32GuestCR0 |= X86_CR0_TS /* Guest can task switch quickly and do lazy FPU syncing. */
3796 | X86_CR0_MP; /* FWAIT/WAIT should not ignore CR0.TS and should generate #NM. */
3797 }
3798
3799 /* Catch floating point exceptions if we need to report them to the guest in a different way. */
3800 bool fInterceptMF = false;
3801 if (!(pMixedCtx->cr0 & X86_CR0_NE))
3802 fInterceptMF = true;
3803
3804 /* Finally, intercept all exceptions as we cannot directly inject them in real-mode, see hmR0VmxInjectEventVmcs(). */
3805 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3806 {
3807 Assert(PDMVmmDevHeapIsEnabled(pVM));
3808 Assert(pVM->hm.s.vmx.pRealModeTSS);
3809 pVCpu->hm.s.vmx.u32XcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
3810 fInterceptNM = true;
3811 fInterceptMF = true;
3812 }
3813 else
3814 {
3815 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
3816 pVCpu->hm.s.vmx.u32XcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
3817 }
3818 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
3819
3820 if (fInterceptNM)
3821 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_NM);
3822 else
3823 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_NM);
3824
3825 if (fInterceptMF)
3826 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_MF);
3827 else
3828 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_MF);
3829
3830 /* Additional intercepts for debugging, define these yourself explicitly. */
3831#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
3832 pVCpu->hm.s.vmx.u32XcptBitmap |= 0
3833 | RT_BIT(X86_XCPT_BP)
3834 | RT_BIT(X86_XCPT_DE)
3835 | RT_BIT(X86_XCPT_NM)
3836 | RT_BIT(X86_XCPT_TS)
3837 | RT_BIT(X86_XCPT_UD)
3838 | RT_BIT(X86_XCPT_NP)
3839 | RT_BIT(X86_XCPT_SS)
3840 | RT_BIT(X86_XCPT_GP)
3841 | RT_BIT(X86_XCPT_PF)
3842 | RT_BIT(X86_XCPT_MF)
3843 ;
3844#elif defined(HMVMX_ALWAYS_TRAP_PF)
3845 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_PF);
3846#endif
3847
3848 Assert(pVM->hm.s.fNestedPaging || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_PF)));
3849
3850 /* Set/clear the CR0 specific bits along with their exceptions (PE, PG, CD, NW). */
3851 uint32_t uSetCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
3852 uint32_t uZapCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
3853 if (pVM->hm.s.vmx.fUnrestrictedGuest) /* Exceptions for unrestricted-guests for fixed CR0 bits (PE, PG). */
3854 uSetCR0 &= ~(X86_CR0_PE | X86_CR0_PG);
3855 else
3856 Assert((uSetCR0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
3857
3858 u32GuestCR0 |= uSetCR0;
3859 u32GuestCR0 &= uZapCR0;
3860 u32GuestCR0 &= ~(X86_CR0_CD | X86_CR0_NW); /* Always enable caching. */
3861
3862 /* Write VT-x's view of the guest CR0 into the VMCS. */
3863 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_CR0, u32GuestCR0);
3864 AssertRCReturn(rc, rc);
3865 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR0=%#RX32 (uSetCR0=%#RX32 uZapCR0=%#RX32)\n", pVCpu->idCpu, u32GuestCR0, uSetCR0,
3866 uZapCR0));
3867
3868 /*
3869 * CR0 is shared between host and guest along with a CR0 read shadow. Therefore, certain bits must not be changed
3870 * by the guest because VT-x ignores saving/restoring them (namely CD, ET, NW) and for certain other bits
3871 * we want to be notified immediately of guest CR0 changes (e.g. PG to update our shadow page tables).
3872 */
3873 uint32_t u32CR0Mask = 0;
3874 u32CR0Mask = X86_CR0_PE
3875 | X86_CR0_NE
3876 | X86_CR0_WP
3877 | X86_CR0_PG
3878 | X86_CR0_ET /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.ET */
3879 | X86_CR0_CD /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.CD */
3880 | X86_CR0_NW; /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.NW */
3881
3882 /** @todo Avoid intercepting CR0.PE with unrestricted guests. Fix PGM
3883 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
3884 * and @bugref{6944}. */
3885#if 0
3886 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3887 u32CR0Mask &= ~X86_CR0_PE;
3888#endif
3889 if (pVM->hm.s.fNestedPaging)
3890 u32CR0Mask &= ~X86_CR0_WP;
3891
3892 /* If the guest FPU state is active, don't need to VM-exit on writes to FPU related bits in CR0. */
3893 if (fInterceptNM)
3894 {
3895 u32CR0Mask |= X86_CR0_TS
3896 | X86_CR0_MP;
3897 }
3898
3899 /* Write the CR0 mask into the VMCS and update the VCPU's copy of the current CR0 mask. */
3900 pVCpu->hm.s.vmx.u32CR0Mask = u32CR0Mask;
3901 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_MASK, u32CR0Mask);
3902 AssertRCReturn(rc, rc);
3903 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR0_MASK=%#RX32\n", pVCpu->idCpu, u32CR0Mask));
3904
3905 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR0);
3906 }
3907 return rc;
3908}
3909
3910
3911/**
3912 * Loads the guest control registers (CR3, CR4) into the guest-state area
3913 * in the VMCS.
3914 *
3915 * @returns VBox strict status code.
3916 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
3917 * without unrestricted guest access and the VMMDev is not presently
3918 * mapped (e.g. EFI32).
3919 *
3920 * @param pVCpu The cross context virtual CPU structure.
3921 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3922 * out-of-sync. Make sure to update the required fields
3923 * before using them.
3924 *
3925 * @remarks No-long-jump zone!!!
3926 */
3927static VBOXSTRICTRC hmR0VmxLoadGuestCR3AndCR4(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3928{
3929 int rc = VINF_SUCCESS;
3930 PVM pVM = pVCpu->CTX_SUFF(pVM);
3931
3932 /*
3933 * Guest CR2.
3934 * It's always loaded in the assembler code. Nothing to do here.
3935 */
3936
3937 /*
3938 * Guest CR3.
3939 */
3940 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR3))
3941 {
3942 RTGCPHYS GCPhysGuestCR3 = NIL_RTGCPHYS;
3943 if (pVM->hm.s.fNestedPaging)
3944 {
3945 pVCpu->hm.s.vmx.HCPhysEPTP = PGMGetHyperCR3(pVCpu);
3946
3947 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
3948 Assert(pVCpu->hm.s.vmx.HCPhysEPTP);
3949 Assert(!(pVCpu->hm.s.vmx.HCPhysEPTP & UINT64_C(0xfff0000000000000)));
3950 Assert(!(pVCpu->hm.s.vmx.HCPhysEPTP & 0xfff));
3951
3952 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
3953 pVCpu->hm.s.vmx.HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
3954 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
3955
3956 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
3957 AssertMsg( ((pVCpu->hm.s.vmx.HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
3958 && ((pVCpu->hm.s.vmx.HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
3959 ("EPTP %#RX64\n", pVCpu->hm.s.vmx.HCPhysEPTP));
3960 AssertMsg( !((pVCpu->hm.s.vmx.HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
3961 || (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
3962 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVCpu->hm.s.vmx.HCPhysEPTP));
3963
3964 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVCpu->hm.s.vmx.HCPhysEPTP);
3965 AssertRCReturn(rc, rc);
3966 Log4(("Load[%RU32]: VMX_VMCS64_CTRL_EPTP_FULL=%#RX64\n", pVCpu->idCpu, pVCpu->hm.s.vmx.HCPhysEPTP));
3967
3968 if ( pVM->hm.s.vmx.fUnrestrictedGuest
3969 || CPUMIsGuestPagingEnabledEx(pMixedCtx))
3970 {
3971 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
3972 if (CPUMIsGuestInPAEModeEx(pMixedCtx))
3973 {
3974 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
3975 AssertRCReturn(rc, rc);
3976 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u);
3977 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u);
3978 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u);
3979 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u);
3980 AssertRCReturn(rc, rc);
3981 }
3982
3983 /* The guest's view of its CR3 is unblemished with Nested Paging when the guest is using paging or we
3984 have Unrestricted Execution to handle the guest when it's not using paging. */
3985 GCPhysGuestCR3 = pMixedCtx->cr3;
3986 }
3987 else
3988 {
3989 /*
3990 * The guest is not using paging, but the CPU (VT-x) has to. While the guest thinks it accesses physical memory
3991 * directly, we use our identity-mapped page table to map guest-linear to guest-physical addresses.
3992 * EPT takes care of translating it to host-physical addresses.
3993 */
3994 RTGCPHYS GCPhys;
3995 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
3996
3997 /* We obtain it here every time as the guest could have relocated this PCI region. */
3998 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
3999 if (RT_SUCCESS(rc))
4000 { /* likely */ }
4001 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
4002 {
4003 Log4(("Load[%RU32]: VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n", pVCpu->idCpu));
4004 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
4005 }
4006 else
4007 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
4008
4009 GCPhysGuestCR3 = GCPhys;
4010 }
4011
4012 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR3=%#RGp (GstN)\n", pVCpu->idCpu, GCPhysGuestCR3));
4013 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_CR3, GCPhysGuestCR3);
4014 }
4015 else
4016 {
4017 /* Non-nested paging case, just use the hypervisor's CR3. */
4018 RTHCPHYS HCPhysGuestCR3 = PGMGetHyperCR3(pVCpu);
4019
4020 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR3=%#RHv (HstN)\n", pVCpu->idCpu, HCPhysGuestCR3));
4021 rc = VMXWriteVmcsHstN(VMX_VMCS_GUEST_CR3, HCPhysGuestCR3);
4022 }
4023 AssertRCReturn(rc, rc);
4024
4025 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR3);
4026 }
4027
4028 /*
4029 * Guest CR4.
4030 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
4031 */
4032 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR4))
4033 {
4034 Assert(!(pMixedCtx->cr4 >> 32));
4035 uint32_t u32GuestCR4 = pMixedCtx->cr4;
4036
4037 /* The guest's view of its CR4 is unblemished. */
4038 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_READ_SHADOW, u32GuestCR4);
4039 AssertRCReturn(rc, rc);
4040 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR4_READ_SHADOW=%#RX32\n", pVCpu->idCpu, u32GuestCR4));
4041
4042 /* Setup VT-x's view of the guest CR4. */
4043 /*
4044 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software interrupts to the 8086 program
4045 * interrupt handler. Clear the VME bit (the interrupt redirection bitmap is already all 0, see hmR3InitFinalizeR0())
4046 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
4047 */
4048 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4049 {
4050 Assert(pVM->hm.s.vmx.pRealModeTSS);
4051 Assert(PDMVmmDevHeapIsEnabled(pVM));
4052 u32GuestCR4 &= ~X86_CR4_VME;
4053 }
4054
4055 if (pVM->hm.s.fNestedPaging)
4056 {
4057 if ( !CPUMIsGuestPagingEnabledEx(pMixedCtx)
4058 && !pVM->hm.s.vmx.fUnrestrictedGuest)
4059 {
4060 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
4061 u32GuestCR4 |= X86_CR4_PSE;
4062 /* Our identity mapping is a 32-bit page directory. */
4063 u32GuestCR4 &= ~X86_CR4_PAE;
4064 }
4065 /* else use guest CR4.*/
4066 }
4067 else
4068 {
4069 /*
4070 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
4071 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
4072 */
4073 switch (pVCpu->hm.s.enmShadowMode)
4074 {
4075 case PGMMODE_REAL: /* Real-mode. */
4076 case PGMMODE_PROTECTED: /* Protected mode without paging. */
4077 case PGMMODE_32_BIT: /* 32-bit paging. */
4078 {
4079 u32GuestCR4 &= ~X86_CR4_PAE;
4080 break;
4081 }
4082
4083 case PGMMODE_PAE: /* PAE paging. */
4084 case PGMMODE_PAE_NX: /* PAE paging with NX. */
4085 {
4086 u32GuestCR4 |= X86_CR4_PAE;
4087 break;
4088 }
4089
4090 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
4091 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
4092#ifdef VBOX_ENABLE_64_BITS_GUESTS
4093 break;
4094#endif
4095 default:
4096 AssertFailed();
4097 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
4098 }
4099 }
4100
4101 /* We need to set and clear the CR4 specific bits here (mainly the X86_CR4_VMXE bit). */
4102 uint64_t uSetCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
4103 uint64_t uZapCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
4104 u32GuestCR4 |= uSetCR4;
4105 u32GuestCR4 &= uZapCR4;
4106
4107 /* Write VT-x's view of the guest CR4 into the VMCS. */
4108 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR4=%#RX32 (Set=%#RX32 Zap=%#RX32)\n", pVCpu->idCpu, u32GuestCR4, uSetCR4, uZapCR4));
4109 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_CR4, u32GuestCR4);
4110 AssertRCReturn(rc, rc);
4111
4112 /* Setup CR4 mask. CR4 flags owned by the host, if the guest attempts to change them, that would cause a VM-exit. */
4113 uint32_t u32CR4Mask = X86_CR4_VME
4114 | X86_CR4_PAE
4115 | X86_CR4_PGE
4116 | X86_CR4_PSE
4117 | X86_CR4_VMXE;
4118 if (pVM->cpum.ro.HostFeatures.fXSaveRstor)
4119 u32CR4Mask |= X86_CR4_OSXSAVE;
4120 pVCpu->hm.s.vmx.u32CR4Mask = u32CR4Mask;
4121 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_MASK, u32CR4Mask);
4122 AssertRCReturn(rc, rc);
4123
4124 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
4125 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pMixedCtx->cr4 & X86_CR4_OSXSAVE) && pMixedCtx->aXcr[0] != ASMGetXcr0();
4126
4127 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR4);
4128 }
4129 return rc;
4130}
4131
4132
4133/**
4134 * Loads the guest debug registers into the guest-state area in the VMCS.
4135 *
4136 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
4137 *
4138 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
4139 *
4140 * @returns VBox status code.
4141 * @param pVCpu The cross context virtual CPU structure.
4142 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4143 * out-of-sync. Make sure to update the required fields
4144 * before using them.
4145 *
4146 * @remarks No-long-jump zone!!!
4147 */
4148static int hmR0VmxLoadSharedDebugState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4149{
4150 if (!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_DEBUG))
4151 return VINF_SUCCESS;
4152
4153#ifdef VBOX_STRICT
4154 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
4155 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
4156 {
4157 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
4158 Assert((pMixedCtx->dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0); /* Bits 63:32, 15, 14, 12, 11 are reserved. */
4159 Assert((pMixedCtx->dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK); /* Bit 10 is reserved (RA1). */
4160 }
4161#endif
4162
4163 int rc;
4164 PVM pVM = pVCpu->CTX_SUFF(pVM);
4165 bool fSteppingDB = false;
4166 bool fInterceptMovDRx = false;
4167 if (pVCpu->hm.s.fSingleInstruction)
4168 {
4169 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
4170 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG)
4171 {
4172 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG;
4173 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
4174 AssertRCReturn(rc, rc);
4175 Assert(fSteppingDB == false);
4176 }
4177 else
4178 {
4179 pMixedCtx->eflags.u32 |= X86_EFL_TF;
4180 pVCpu->hm.s.fClearTrapFlag = true;
4181 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
4182 fSteppingDB = true;
4183 }
4184 }
4185
4186 if ( fSteppingDB
4187 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
4188 {
4189 /*
4190 * Use the combined guest and host DRx values found in the hypervisor
4191 * register set because the debugger has breakpoints active or someone
4192 * is single stepping on the host side without a monitor trap flag.
4193 *
4194 * Note! DBGF expects a clean DR6 state before executing guest code.
4195 */
4196#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4197 if ( CPUMIsGuestInLongModeEx(pMixedCtx)
4198 && !CPUMIsHyperDebugStateActivePending(pVCpu))
4199 {
4200 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
4201 Assert(CPUMIsHyperDebugStateActivePending(pVCpu));
4202 Assert(!CPUMIsGuestDebugStateActivePending(pVCpu));
4203 }
4204 else
4205#endif
4206 if (!CPUMIsHyperDebugStateActive(pVCpu))
4207 {
4208 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
4209 Assert(CPUMIsHyperDebugStateActive(pVCpu));
4210 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
4211 }
4212
4213 /* Update DR7. (The other DRx values are handled by CPUM one way or the other.) */
4214 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, (uint32_t)CPUMGetHyperDR7(pVCpu));
4215 AssertRCReturn(rc, rc);
4216
4217 pVCpu->hm.s.fUsingHyperDR7 = true;
4218 fInterceptMovDRx = true;
4219 }
4220 else
4221 {
4222 /*
4223 * If the guest has enabled debug registers, we need to load them prior to
4224 * executing guest code so they'll trigger at the right time.
4225 */
4226 if (pMixedCtx->dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD)) /** @todo Why GD? */
4227 {
4228#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4229 if ( CPUMIsGuestInLongModeEx(pMixedCtx)
4230 && !CPUMIsGuestDebugStateActivePending(pVCpu))
4231 {
4232 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
4233 Assert(CPUMIsGuestDebugStateActivePending(pVCpu));
4234 Assert(!CPUMIsHyperDebugStateActivePending(pVCpu));
4235 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
4236 }
4237 else
4238#endif
4239 if (!CPUMIsGuestDebugStateActive(pVCpu))
4240 {
4241 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
4242 Assert(CPUMIsGuestDebugStateActive(pVCpu));
4243 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
4244 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
4245 }
4246 Assert(!fInterceptMovDRx);
4247 }
4248 /*
4249 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
4250 * must intercept #DB in order to maintain a correct DR6 guest value, and
4251 * because we need to intercept it to prevent nested #DBs from hanging the
4252 * CPU, we end up always having to intercept it. See hmR0VmxInitXcptBitmap.
4253 */
4254#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4255 else if ( !CPUMIsGuestDebugStateActivePending(pVCpu)
4256 && !CPUMIsGuestDebugStateActive(pVCpu))
4257#else
4258 else if (!CPUMIsGuestDebugStateActive(pVCpu))
4259#endif
4260 {
4261 fInterceptMovDRx = true;
4262 }
4263
4264 /* Update guest DR7. */
4265 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, pMixedCtx->dr[7]);
4266 AssertRCReturn(rc, rc);
4267
4268 pVCpu->hm.s.fUsingHyperDR7 = false;
4269 }
4270
4271 /*
4272 * Update the processor-based VM-execution controls regarding intercepting MOV DRx instructions.
4273 */
4274 if (fInterceptMovDRx)
4275 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
4276 else
4277 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
4278 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
4279 AssertRCReturn(rc, rc);
4280
4281 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_DEBUG);
4282 return VINF_SUCCESS;
4283}
4284
4285
4286#ifdef VBOX_STRICT
4287/**
4288 * Strict function to validate segment registers.
4289 *
4290 * @remarks ASSUMES CR0 is up to date.
4291 */
4292static void hmR0VmxValidateSegmentRegs(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
4293{
4294 /* Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers". */
4295 /* NOTE: The reason we check for attribute value 0 and not just the unusable bit here is because hmR0VmxWriteSegmentReg()
4296 * only updates the VMCS' copy of the value with the unusable bit and doesn't change the guest-context value. */
4297 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
4298 && ( !CPUMIsGuestInRealModeEx(pCtx)
4299 && !CPUMIsGuestInV86ModeEx(pCtx)))
4300 {
4301 /* Protected mode checks */
4302 /* CS */
4303 Assert(pCtx->cs.Attr.n.u1Present);
4304 Assert(!(pCtx->cs.Attr.u & 0xf00));
4305 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
4306 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
4307 || !(pCtx->cs.Attr.n.u1Granularity));
4308 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
4309 || (pCtx->cs.Attr.n.u1Granularity));
4310 /* CS cannot be loaded with NULL in protected mode. */
4311 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
4312 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
4313 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
4314 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
4315 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
4316 else
4317 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
4318 /* SS */
4319 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
4320 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
4321 if ( !(pCtx->cr0 & X86_CR0_PE)
4322 || pCtx->cs.Attr.n.u4Type == 3)
4323 {
4324 Assert(!pCtx->ss.Attr.n.u2Dpl);
4325 }
4326 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
4327 {
4328 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
4329 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
4330 Assert(pCtx->ss.Attr.n.u1Present);
4331 Assert(!(pCtx->ss.Attr.u & 0xf00));
4332 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
4333 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
4334 || !(pCtx->ss.Attr.n.u1Granularity));
4335 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
4336 || (pCtx->ss.Attr.n.u1Granularity));
4337 }
4338 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxWriteSegmentReg(). */
4339 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
4340 {
4341 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4342 Assert(pCtx->ds.Attr.n.u1Present);
4343 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
4344 Assert(!(pCtx->ds.Attr.u & 0xf00));
4345 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
4346 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
4347 || !(pCtx->ds.Attr.n.u1Granularity));
4348 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
4349 || (pCtx->ds.Attr.n.u1Granularity));
4350 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4351 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
4352 }
4353 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
4354 {
4355 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4356 Assert(pCtx->es.Attr.n.u1Present);
4357 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
4358 Assert(!(pCtx->es.Attr.u & 0xf00));
4359 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
4360 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
4361 || !(pCtx->es.Attr.n.u1Granularity));
4362 Assert( !(pCtx->es.u32Limit & 0xfff00000)
4363 || (pCtx->es.Attr.n.u1Granularity));
4364 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4365 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
4366 }
4367 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
4368 {
4369 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4370 Assert(pCtx->fs.Attr.n.u1Present);
4371 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
4372 Assert(!(pCtx->fs.Attr.u & 0xf00));
4373 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
4374 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
4375 || !(pCtx->fs.Attr.n.u1Granularity));
4376 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
4377 || (pCtx->fs.Attr.n.u1Granularity));
4378 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4379 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
4380 }
4381 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
4382 {
4383 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4384 Assert(pCtx->gs.Attr.n.u1Present);
4385 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
4386 Assert(!(pCtx->gs.Attr.u & 0xf00));
4387 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
4388 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
4389 || !(pCtx->gs.Attr.n.u1Granularity));
4390 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
4391 || (pCtx->gs.Attr.n.u1Granularity));
4392 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4393 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
4394 }
4395 /* 64-bit capable CPUs. */
4396# if HC_ARCH_BITS == 64
4397 Assert(!(pCtx->cs.u64Base >> 32));
4398 Assert(!pCtx->ss.Attr.u || !(pCtx->ss.u64Base >> 32));
4399 Assert(!pCtx->ds.Attr.u || !(pCtx->ds.u64Base >> 32));
4400 Assert(!pCtx->es.Attr.u || !(pCtx->es.u64Base >> 32));
4401# endif
4402 }
4403 else if ( CPUMIsGuestInV86ModeEx(pCtx)
4404 || ( CPUMIsGuestInRealModeEx(pCtx)
4405 && !pVM->hm.s.vmx.fUnrestrictedGuest))
4406 {
4407 /* Real and v86 mode checks. */
4408 /* hmR0VmxWriteSegmentReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
4409 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
4410 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4411 {
4412 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3; u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
4413 }
4414 else
4415 {
4416 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
4417 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
4418 }
4419
4420 /* CS */
4421 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
4422 Assert(pCtx->cs.u32Limit == 0xffff);
4423 Assert(u32CSAttr == 0xf3);
4424 /* SS */
4425 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
4426 Assert(pCtx->ss.u32Limit == 0xffff);
4427 Assert(u32SSAttr == 0xf3);
4428 /* DS */
4429 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
4430 Assert(pCtx->ds.u32Limit == 0xffff);
4431 Assert(u32DSAttr == 0xf3);
4432 /* ES */
4433 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
4434 Assert(pCtx->es.u32Limit == 0xffff);
4435 Assert(u32ESAttr == 0xf3);
4436 /* FS */
4437 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
4438 Assert(pCtx->fs.u32Limit == 0xffff);
4439 Assert(u32FSAttr == 0xf3);
4440 /* GS */
4441 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
4442 Assert(pCtx->gs.u32Limit == 0xffff);
4443 Assert(u32GSAttr == 0xf3);
4444 /* 64-bit capable CPUs. */
4445# if HC_ARCH_BITS == 64
4446 Assert(!(pCtx->cs.u64Base >> 32));
4447 Assert(!u32SSAttr || !(pCtx->ss.u64Base >> 32));
4448 Assert(!u32DSAttr || !(pCtx->ds.u64Base >> 32));
4449 Assert(!u32ESAttr || !(pCtx->es.u64Base >> 32));
4450# endif
4451 }
4452}
4453#endif /* VBOX_STRICT */
4454
4455
4456/**
4457 * Writes a guest segment register into the guest-state area in the VMCS.
4458 *
4459 * @returns VBox status code.
4460 * @param pVCpu The cross context virtual CPU structure.
4461 * @param idxSel Index of the selector in the VMCS.
4462 * @param idxLimit Index of the segment limit in the VMCS.
4463 * @param idxBase Index of the segment base in the VMCS.
4464 * @param idxAccess Index of the access rights of the segment in the VMCS.
4465 * @param pSelReg Pointer to the segment selector.
4466 *
4467 * @remarks No-long-jump zone!!!
4468 */
4469static int hmR0VmxWriteSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase,
4470 uint32_t idxAccess, PCPUMSELREG pSelReg)
4471{
4472 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); /* 16-bit guest selector field. */
4473 rc |= VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); /* 32-bit guest segment limit field. */
4474 rc |= VMXWriteVmcsGstN(idxBase, pSelReg->u64Base); /* Natural width guest segment base field.*/
4475 AssertRCReturn(rc, rc);
4476
4477 uint32_t u32Access = pSelReg->Attr.u;
4478 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4479 {
4480 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
4481 u32Access = 0xf3;
4482 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
4483 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
4484 }
4485 else
4486 {
4487 /*
4488 * The way to differentiate between whether this is really a null selector or was just a selector loaded with 0 in
4489 * real-mode is using the segment attributes. A selector loaded in real-mode with the value 0 is valid and usable in
4490 * protected-mode and we should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures NULL selectors
4491 * loaded in protected-mode have their attribute as 0.
4492 */
4493 if (!u32Access)
4494 u32Access = X86DESCATTR_UNUSABLE;
4495 }
4496
4497 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
4498 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
4499 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
4500
4501 rc = VMXWriteVmcs32(idxAccess, u32Access); /* 32-bit guest segment access-rights field. */
4502 AssertRCReturn(rc, rc);
4503 return rc;
4504}
4505
4506
4507/**
4508 * Loads the guest segment registers, GDTR, IDTR, LDTR, (TR, FS and GS bases)
4509 * into the guest-state area in the VMCS.
4510 *
4511 * @returns VBox status code.
4512 * @param pVCpu The cross context virtual CPU structure.
4513 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4514 * out-of-sync. Make sure to update the required fields
4515 * before using them.
4516 *
4517 * @remarks ASSUMES pMixedCtx->cr0 is up to date (strict builds validation).
4518 * @remarks No-long-jump zone!!!
4519 */
4520static int hmR0VmxLoadGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4521{
4522 int rc = VERR_INTERNAL_ERROR_5;
4523 PVM pVM = pVCpu->CTX_SUFF(pVM);
4524
4525 /*
4526 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
4527 */
4528 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS))
4529 {
4530 /* Save the segment attributes for real-on-v86 mode hack, so we can restore them on VM-exit. */
4531 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4532 {
4533 pVCpu->hm.s.vmx.RealMode.AttrCS.u = pMixedCtx->cs.Attr.u;
4534 pVCpu->hm.s.vmx.RealMode.AttrSS.u = pMixedCtx->ss.Attr.u;
4535 pVCpu->hm.s.vmx.RealMode.AttrDS.u = pMixedCtx->ds.Attr.u;
4536 pVCpu->hm.s.vmx.RealMode.AttrES.u = pMixedCtx->es.Attr.u;
4537 pVCpu->hm.s.vmx.RealMode.AttrFS.u = pMixedCtx->fs.Attr.u;
4538 pVCpu->hm.s.vmx.RealMode.AttrGS.u = pMixedCtx->gs.Attr.u;
4539 }
4540
4541#ifdef VBOX_WITH_REM
4542 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
4543 {
4544 Assert(pVM->hm.s.vmx.pRealModeTSS);
4545 AssertCompile(PGMMODE_REAL < PGMMODE_PROTECTED);
4546 if ( pVCpu->hm.s.vmx.fWasInRealMode
4547 && PGMGetGuestMode(pVCpu) >= PGMMODE_PROTECTED)
4548 {
4549 /* Signal that the recompiler must flush its code-cache as the guest -may- rewrite code it will later execute
4550 in real-mode (e.g. OpenBSD 4.0) */
4551 REMFlushTBs(pVM);
4552 Log4(("Load[%RU32]: Switch to protected mode detected!\n", pVCpu->idCpu));
4553 pVCpu->hm.s.vmx.fWasInRealMode = false;
4554 }
4555 }
4556#endif
4557 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_CS_SEL, VMX_VMCS32_GUEST_CS_LIMIT, VMX_VMCS_GUEST_CS_BASE,
4558 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS, &pMixedCtx->cs);
4559 AssertRCReturn(rc, rc);
4560 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_SS_SEL, VMX_VMCS32_GUEST_SS_LIMIT, VMX_VMCS_GUEST_SS_BASE,
4561 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS, &pMixedCtx->ss);
4562 AssertRCReturn(rc, rc);
4563 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_DS_SEL, VMX_VMCS32_GUEST_DS_LIMIT, VMX_VMCS_GUEST_DS_BASE,
4564 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS, &pMixedCtx->ds);
4565 AssertRCReturn(rc, rc);
4566 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_ES_SEL, VMX_VMCS32_GUEST_ES_LIMIT, VMX_VMCS_GUEST_ES_BASE,
4567 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS, &pMixedCtx->es);
4568 AssertRCReturn(rc, rc);
4569 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FS_SEL, VMX_VMCS32_GUEST_FS_LIMIT, VMX_VMCS_GUEST_FS_BASE,
4570 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS, &pMixedCtx->fs);
4571 AssertRCReturn(rc, rc);
4572 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_GS_SEL, VMX_VMCS32_GUEST_GS_LIMIT, VMX_VMCS_GUEST_GS_BASE,
4573 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS, &pMixedCtx->gs);
4574 AssertRCReturn(rc, rc);
4575
4576#ifdef VBOX_STRICT
4577 /* Validate. */
4578 hmR0VmxValidateSegmentRegs(pVM, pVCpu, pMixedCtx);
4579#endif
4580
4581 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS);
4582 Log4(("Load[%RU32]: CS=%#RX16 Base=%#RX64 Limit=%#RX32 Attr=%#RX32\n", pVCpu->idCpu, pMixedCtx->cs.Sel,
4583 pMixedCtx->cs.u64Base, pMixedCtx->cs.u32Limit, pMixedCtx->cs.Attr.u));
4584 }
4585
4586 /*
4587 * Guest TR.
4588 */
4589 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_TR))
4590 {
4591 /*
4592 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is achieved
4593 * using the interrupt redirection bitmap (all bits cleared to let the guest handle INT-n's) in the TSS.
4594 * See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
4595 */
4596 uint16_t u16Sel = 0;
4597 uint32_t u32Limit = 0;
4598 uint64_t u64Base = 0;
4599 uint32_t u32AccessRights = 0;
4600
4601 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4602 {
4603 u16Sel = pMixedCtx->tr.Sel;
4604 u32Limit = pMixedCtx->tr.u32Limit;
4605 u64Base = pMixedCtx->tr.u64Base;
4606 u32AccessRights = pMixedCtx->tr.Attr.u;
4607 }
4608 else
4609 {
4610 Assert(pVM->hm.s.vmx.pRealModeTSS);
4611 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMR3CanExecuteGuest() -XXX- what about inner loop changes? */
4612
4613 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
4614 RTGCPHYS GCPhys;
4615 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
4616 AssertRCReturn(rc, rc);
4617
4618 X86DESCATTR DescAttr;
4619 DescAttr.u = 0;
4620 DescAttr.n.u1Present = 1;
4621 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
4622
4623 u16Sel = 0;
4624 u32Limit = HM_VTX_TSS_SIZE;
4625 u64Base = GCPhys; /* in real-mode phys = virt. */
4626 u32AccessRights = DescAttr.u;
4627 }
4628
4629 /* Validate. */
4630 Assert(!(u16Sel & RT_BIT(2)));
4631 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
4632 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
4633 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
4634 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
4635 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
4636 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
4637 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
4638 Assert( (u32Limit & 0xfff) == 0xfff
4639 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
4640 Assert( !(pMixedCtx->tr.u32Limit & 0xfff00000)
4641 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
4642
4643 rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_TR_SEL, u16Sel);
4644 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit);
4645 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_TR_BASE, u64Base);
4646 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights);
4647 AssertRCReturn(rc, rc);
4648
4649 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_TR);
4650 Log4(("Load[%RU32]: VMX_VMCS_GUEST_TR_BASE=%#RX64\n", pVCpu->idCpu, u64Base));
4651 }
4652
4653 /*
4654 * Guest GDTR.
4655 */
4656 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_GDTR))
4657 {
4658 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pMixedCtx->gdtr.cbGdt);
4659 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_GDTR_BASE, pMixedCtx->gdtr.pGdt);
4660 AssertRCReturn(rc, rc);
4661
4662 /* Validate. */
4663 Assert(!(pMixedCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
4664
4665 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_GDTR);
4666 Log4(("Load[%RU32]: VMX_VMCS_GUEST_GDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->gdtr.pGdt));
4667 }
4668
4669 /*
4670 * Guest LDTR.
4671 */
4672 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LDTR))
4673 {
4674 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
4675 uint32_t u32Access = 0;
4676 if (!pMixedCtx->ldtr.Attr.u)
4677 u32Access = X86DESCATTR_UNUSABLE;
4678 else
4679 u32Access = pMixedCtx->ldtr.Attr.u;
4680
4681 rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_LDTR_SEL, pMixedCtx->ldtr.Sel);
4682 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pMixedCtx->ldtr.u32Limit);
4683 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_LDTR_BASE, pMixedCtx->ldtr.u64Base);
4684 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access);
4685 AssertRCReturn(rc, rc);
4686
4687 /* Validate. */
4688 if (!(u32Access & X86DESCATTR_UNUSABLE))
4689 {
4690 Assert(!(pMixedCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
4691 Assert(pMixedCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
4692 Assert(!pMixedCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
4693 Assert(pMixedCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
4694 Assert(!pMixedCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
4695 Assert(!(pMixedCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
4696 Assert( (pMixedCtx->ldtr.u32Limit & 0xfff) == 0xfff
4697 || !pMixedCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
4698 Assert( !(pMixedCtx->ldtr.u32Limit & 0xfff00000)
4699 || pMixedCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
4700 }
4701
4702 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_LDTR);
4703 Log4(("Load[%RU32]: VMX_VMCS_GUEST_LDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->ldtr.u64Base));
4704 }
4705
4706 /*
4707 * Guest IDTR.
4708 */
4709 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_IDTR))
4710 {
4711 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pMixedCtx->idtr.cbIdt);
4712 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_IDTR_BASE, pMixedCtx->idtr.pIdt);
4713 AssertRCReturn(rc, rc);
4714
4715 /* Validate. */
4716 Assert(!(pMixedCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
4717
4718 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_IDTR);
4719 Log4(("Load[%RU32]: VMX_VMCS_GUEST_IDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->idtr.pIdt));
4720 }
4721
4722 return VINF_SUCCESS;
4723}
4724
4725
4726/**
4727 * Loads certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
4728 * areas.
4729 *
4730 * These MSRs will automatically be loaded to the host CPU on every successful
4731 * VM-entry and stored from the host CPU on every successful VM-exit. This also
4732 * creates/updates MSR slots for the host MSRs. The actual host MSR values are
4733 * -not- updated here for performance reasons. See hmR0VmxSaveHostMsrs().
4734 *
4735 * Also loads the sysenter MSRs into the guest-state area in the VMCS.
4736 *
4737 * @returns VBox status code.
4738 * @param pVCpu The cross context virtual CPU structure.
4739 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4740 * out-of-sync. Make sure to update the required fields
4741 * before using them.
4742 *
4743 * @remarks No-long-jump zone!!!
4744 */
4745static int hmR0VmxLoadGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4746{
4747 AssertPtr(pVCpu);
4748 AssertPtr(pVCpu->hm.s.vmx.pvGuestMsr);
4749
4750 /*
4751 * MSRs that we use the auto-load/store MSR area in the VMCS.
4752 */
4753 PVM pVM = pVCpu->CTX_SUFF(pVM);
4754 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS))
4755 {
4756 /* For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(). */
4757#if HC_ARCH_BITS == 32
4758 if (pVM->hm.s.fAllow64BitGuests)
4759 {
4760 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_LSTAR, pMixedCtx->msrLSTAR, false, NULL);
4761 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K6_STAR, pMixedCtx->msrSTAR, false, NULL);
4762 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_SF_MASK, pMixedCtx->msrSFMASK, false, NULL);
4763 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_KERNEL_GS_BASE, pMixedCtx->msrKERNELGSBASE, false, NULL);
4764 AssertRCReturn(rc, rc);
4765# ifdef LOG_ENABLED
4766 PVMXAUTOMSR pMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
4767 for (uint32_t i = 0; i < pVCpu->hm.s.vmx.cMsrs; i++, pMsr++)
4768 {
4769 Log4(("Load[%RU32]: MSR[%RU32]: u32Msr=%#RX32 u64Value=%#RX64\n", pVCpu->idCpu, i, pMsr->u32Msr,
4770 pMsr->u64Value));
4771 }
4772# endif
4773 }
4774#endif
4775 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
4776 }
4777
4778 /*
4779 * Guest Sysenter MSRs.
4780 * These flags are only set when MSR-bitmaps are not supported by the CPU and we cause
4781 * VM-exits on WRMSRs for these MSRs.
4782 */
4783 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR))
4784 {
4785 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pMixedCtx->SysEnter.cs); AssertRCReturn(rc, rc);
4786 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR);
4787 }
4788
4789 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR))
4790 {
4791 int rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, pMixedCtx->SysEnter.eip); AssertRCReturn(rc, rc);
4792 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
4793 }
4794
4795 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR))
4796 {
4797 int rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, pMixedCtx->SysEnter.esp); AssertRCReturn(rc, rc);
4798 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
4799 }
4800
4801 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_EFER_MSR))
4802 {
4803 if (hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
4804 {
4805 /*
4806 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
4807 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
4808 */
4809 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
4810 {
4811 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pMixedCtx->msrEFER);
4812 AssertRCReturn(rc,rc);
4813 Log4(("Load[%RU32]: VMX_VMCS64_GUEST_EFER_FULL=%#RX64\n", pVCpu->idCpu, pMixedCtx->msrEFER));
4814 }
4815 else
4816 {
4817 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K6_EFER, pMixedCtx->msrEFER, false /* fUpdateHostMsr */,
4818 NULL /* pfAddedAndUpdated */);
4819 AssertRCReturn(rc, rc);
4820
4821 /* We need to intercept reads too, see @bugref{7386#c16}. */
4822 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
4823 hmR0VmxSetMsrPermission(pVCpu, MSR_K6_EFER, VMXMSREXIT_INTERCEPT_READ, VMXMSREXIT_INTERCEPT_WRITE);
4824 Log4(("Load[%RU32]: MSR[--]: u32Msr=%#RX32 u64Value=%#RX64 cMsrs=%u\n", pVCpu->idCpu, MSR_K6_EFER,
4825 pMixedCtx->msrEFER, pVCpu->hm.s.vmx.cMsrs));
4826 }
4827 }
4828 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
4829 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, MSR_K6_EFER);
4830 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_EFER_MSR);
4831 }
4832
4833 return VINF_SUCCESS;
4834}
4835
4836
4837/**
4838 * Loads the guest activity state into the guest-state area in the VMCS.
4839 *
4840 * @returns VBox status code.
4841 * @param pVCpu The cross context virtual CPU structure.
4842 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4843 * out-of-sync. Make sure to update the required fields
4844 * before using them.
4845 *
4846 * @remarks No-long-jump zone!!!
4847 */
4848static int hmR0VmxLoadGuestActivityState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4849{
4850 NOREF(pMixedCtx);
4851 /** @todo See if we can make use of other states, e.g.
4852 * VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN or HLT. */
4853 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_ACTIVITY_STATE))
4854 {
4855 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, VMX_VMCS_GUEST_ACTIVITY_ACTIVE);
4856 AssertRCReturn(rc, rc);
4857
4858 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_ACTIVITY_STATE);
4859 }
4860 return VINF_SUCCESS;
4861}
4862
4863
4864#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
4865/**
4866 * Check if guest state allows safe use of 32-bit switcher again.
4867 *
4868 * Segment bases and protected mode structures must be 32-bit addressable
4869 * because the 32-bit switcher will ignore high dword when writing these VMCS
4870 * fields. See @bugref{8432} for details.
4871 *
4872 * @returns true if safe, false if must continue to use the 64-bit switcher.
4873 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4874 * out-of-sync. Make sure to update the required fields
4875 * before using them.
4876 *
4877 * @remarks No-long-jump zone!!!
4878 */
4879static bool hmR0VmxIs32BitSwitcherSafe(PCPUMCTX pMixedCtx)
4880{
4881 if (pMixedCtx->gdtr.pGdt & UINT64_C(0xffffffff00000000))
4882 return false;
4883 if (pMixedCtx->idtr.pIdt & UINT64_C(0xffffffff00000000))
4884 return false;
4885 if (pMixedCtx->ldtr.u64Base & UINT64_C(0xffffffff00000000))
4886 return false;
4887 if (pMixedCtx->tr.u64Base & UINT64_C(0xffffffff00000000))
4888 return false;
4889 if (pMixedCtx->es.u64Base & UINT64_C(0xffffffff00000000))
4890 return false;
4891 if (pMixedCtx->cs.u64Base & UINT64_C(0xffffffff00000000))
4892 return false;
4893 if (pMixedCtx->ss.u64Base & UINT64_C(0xffffffff00000000))
4894 return false;
4895 if (pMixedCtx->ds.u64Base & UINT64_C(0xffffffff00000000))
4896 return false;
4897 if (pMixedCtx->fs.u64Base & UINT64_C(0xffffffff00000000))
4898 return false;
4899 if (pMixedCtx->gs.u64Base & UINT64_C(0xffffffff00000000))
4900 return false;
4901 /* All good, bases are 32-bit. */
4902 return true;
4903}
4904#endif
4905
4906
4907/**
4908 * Sets up the appropriate function to run guest code.
4909 *
4910 * @returns VBox status code.
4911 * @param pVCpu The cross context virtual CPU structure.
4912 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4913 * out-of-sync. Make sure to update the required fields
4914 * before using them.
4915 *
4916 * @remarks No-long-jump zone!!!
4917 */
4918static int hmR0VmxSetupVMRunHandler(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4919{
4920 if (CPUMIsGuestInLongModeEx(pMixedCtx))
4921 {
4922#ifndef VBOX_ENABLE_64_BITS_GUESTS
4923 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
4924#endif
4925 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
4926#if HC_ARCH_BITS == 32
4927 /* 32-bit host. We need to switch to 64-bit before running the 64-bit guest. */
4928 if (pVCpu->hm.s.vmx.pfnStartVM != VMXR0SwitcherStartVM64)
4929 {
4930 if (pVCpu->hm.s.vmx.pfnStartVM != NULL) /* Very first entry would have saved host-state already, ignore it. */
4931 {
4932 /* Currently, all mode changes sends us back to ring-3, so these should be set. See @bugref{6944}. */
4933 AssertMsg(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_VMX_EXIT_CTLS
4934 | HM_CHANGED_VMX_ENTRY_CTLS
4935 | HM_CHANGED_GUEST_EFER_MSR), ("flags=%#x\n", HMCPU_CF_VALUE(pVCpu)));
4936 }
4937 pVCpu->hm.s.vmx.pfnStartVM = VMXR0SwitcherStartVM64;
4938
4939 /* Mark that we've switched to 64-bit handler, we can't safely switch back to 32-bit for
4940 the rest of the VM run (until VM reset). See @bugref{8432#c7}. */
4941 pVCpu->hm.s.vmx.fSwitchedTo64on32 = true;
4942 Log4(("Load[%RU32]: hmR0VmxSetupVMRunHandler: selected 64-bit switcher\n", pVCpu->idCpu));
4943 }
4944#else
4945 /* 64-bit host. */
4946 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM64;
4947#endif
4948 }
4949 else
4950 {
4951 /* Guest is not in long mode, use the 32-bit handler. */
4952#if HC_ARCH_BITS == 32
4953 if ( pVCpu->hm.s.vmx.pfnStartVM != VMXR0StartVM32
4954 && !pVCpu->hm.s.vmx.fSwitchedTo64on32 /* If set, guest mode change does not imply switcher change. */
4955 && pVCpu->hm.s.vmx.pfnStartVM != NULL) /* Very first entry would have saved host-state already, ignore it. */
4956 {
4957 /* Currently, all mode changes sends us back to ring-3, so these should be set. See @bugref{6944}. */
4958 AssertMsg(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_VMX_EXIT_CTLS
4959 | HM_CHANGED_VMX_ENTRY_CTLS
4960 | HM_CHANGED_GUEST_EFER_MSR), ("flags=%#x\n", HMCPU_CF_VALUE(pVCpu)));
4961 }
4962# ifdef VBOX_ENABLE_64_BITS_GUESTS
4963 /*
4964 * Keep using the 64-bit switcher even though we're in 32-bit because of bad Intel design, see @bugref{8432#c7}.
4965 * If real-on-v86 mode is active, clear the 64-bit switcher flag because now we know the guest is in a sane
4966 * state where it's safe to use the 32-bit switcher. Otherwise check the guest state if it's safe to use
4967 * the much faster 32-bit switcher again.
4968 */
4969 if (!pVCpu->hm.s.vmx.fSwitchedTo64on32)
4970 {
4971 if (pVCpu->hm.s.vmx.pfnStartVM != VMXR0StartVM32)
4972 Log4(("Load[%RU32]: hmR0VmxSetupVMRunHandler: selected 32-bit switcher\n", pVCpu->idCpu));
4973 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4974 }
4975 else
4976 {
4977 Assert(pVCpu->hm.s.vmx.pfnStartVM == VMXR0SwitcherStartVM64);
4978 if ( pVCpu->hm.s.vmx.RealMode.fRealOnV86Active
4979 || hmR0VmxIs32BitSwitcherSafe(pMixedCtx))
4980 {
4981 pVCpu->hm.s.vmx.fSwitchedTo64on32 = false;
4982 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4983 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_EFER_MSR
4984 | HM_CHANGED_VMX_ENTRY_CTLS
4985 | HM_CHANGED_VMX_EXIT_CTLS
4986 | HM_CHANGED_HOST_CONTEXT);
4987 Log4(("Load[%RU32]: hmR0VmxSetupVMRunHandler: selected 32-bit switcher (safe)\n", pVCpu->idCpu));
4988 }
4989 }
4990# else
4991 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4992# endif
4993#else
4994 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4995#endif
4996 }
4997 Assert(pVCpu->hm.s.vmx.pfnStartVM);
4998 return VINF_SUCCESS;
4999}
5000
5001
5002/**
5003 * Wrapper for running the guest code in VT-x.
5004 *
5005 * @returns VBox status code, no informational status codes.
5006 * @param pVM The cross context VM structure.
5007 * @param pVCpu The cross context virtual CPU structure.
5008 * @param pCtx Pointer to the guest-CPU context.
5009 *
5010 * @remarks No-long-jump zone!!!
5011 */
5012DECLINLINE(int) hmR0VmxRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
5013{
5014 /*
5015 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses floating-point operations
5016 * using SSE instructions. Some XMM registers (XMM6-XMM15) are callee-saved and thus the need for this XMM wrapper.
5017 * Refer MSDN docs. "Configuring Programs for 64-bit / x64 Software Conventions / Register Usage" for details.
5018 */
5019 bool const fResumeVM = RT_BOOL(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_LAUNCHED);
5020 /** @todo Add stats for resume vs launch. */
5021#ifdef VBOX_WITH_KERNEL_USING_XMM
5022 int rc = HMR0VMXStartVMWrapXMM(fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu, pVCpu->hm.s.vmx.pfnStartVM);
5023#else
5024 int rc = pVCpu->hm.s.vmx.pfnStartVM(fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu);
5025#endif
5026 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
5027 return rc;
5028}
5029
5030
5031/**
5032 * Reports world-switch error and dumps some useful debug info.
5033 *
5034 * @param pVM The cross context VM structure.
5035 * @param pVCpu The cross context virtual CPU structure.
5036 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
5037 * @param pCtx Pointer to the guest-CPU context.
5038 * @param pVmxTransient Pointer to the VMX transient structure (only
5039 * exitReason updated).
5040 */
5041static void hmR0VmxReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, int rcVMRun, PCPUMCTX pCtx, PVMXTRANSIENT pVmxTransient)
5042{
5043 Assert(pVM);
5044 Assert(pVCpu);
5045 Assert(pCtx);
5046 Assert(pVmxTransient);
5047 HMVMX_ASSERT_PREEMPT_SAFE();
5048
5049 Log4(("VM-entry failure: %Rrc\n", rcVMRun));
5050 switch (rcVMRun)
5051 {
5052 case VERR_VMX_INVALID_VMXON_PTR:
5053 AssertFailed();
5054 break;
5055 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
5056 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
5057 {
5058 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
5059 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
5060 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
5061 AssertRC(rc);
5062
5063 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
5064 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
5065 Cannot do it here as we may have been long preempted. */
5066
5067#ifdef VBOX_STRICT
5068 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
5069 pVmxTransient->uExitReason));
5070 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQualification));
5071 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
5072 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
5073 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
5074 else
5075 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
5076 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
5077 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
5078
5079 /* VMX control bits. */
5080 uint32_t u32Val;
5081 uint64_t u64Val;
5082 RTHCUINTREG uHCReg;
5083 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val); AssertRC(rc);
5084 Log4(("VMX_VMCS32_CTRL_PIN_EXEC %#RX32\n", u32Val));
5085 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val); AssertRC(rc);
5086 Log4(("VMX_VMCS32_CTRL_PROC_EXEC %#RX32\n", u32Val));
5087 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
5088 {
5089 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val); AssertRC(rc);
5090 Log4(("VMX_VMCS32_CTRL_PROC_EXEC2 %#RX32\n", u32Val));
5091 }
5092 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val); AssertRC(rc);
5093 Log4(("VMX_VMCS32_CTRL_ENTRY %#RX32\n", u32Val));
5094 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val); AssertRC(rc);
5095 Log4(("VMX_VMCS32_CTRL_EXIT %#RX32\n", u32Val));
5096 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_CR3_TARGET_COUNT, &u32Val); AssertRC(rc);
5097 Log4(("VMX_VMCS32_CTRL_CR3_TARGET_COUNT %#RX32\n", u32Val));
5098 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32Val); AssertRC(rc);
5099 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", u32Val));
5100 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &u32Val); AssertRC(rc);
5101 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", u32Val));
5102 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &u32Val); AssertRC(rc);
5103 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %u\n", u32Val));
5104 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, &u32Val); AssertRC(rc);
5105 Log4(("VMX_VMCS32_CTRL_TPR_THRESHOLD %u\n", u32Val));
5106 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &u32Val); AssertRC(rc);
5107 Log4(("VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT %u (guest MSRs)\n", u32Val));
5108 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &u32Val); AssertRC(rc);
5109 Log4(("VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT %u (host MSRs)\n", u32Val));
5110 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &u32Val); AssertRC(rc);
5111 Log4(("VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT %u (guest MSRs)\n", u32Val));
5112 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val); AssertRC(rc);
5113 Log4(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP %#RX32\n", u32Val));
5114 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, &u32Val); AssertRC(rc);
5115 Log4(("VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK %#RX32\n", u32Val));
5116 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, &u32Val); AssertRC(rc);
5117 Log4(("VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH %#RX32\n", u32Val));
5118 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
5119 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
5120 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
5121 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
5122 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
5123 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
5124 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
5125 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
5126 if (pVM->hm.s.fNestedPaging)
5127 {
5128 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
5129 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
5130 }
5131
5132 /* Guest bits. */
5133 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RIP, &u64Val); AssertRC(rc);
5134 Log4(("Old Guest Rip %#RX64 New %#RX64\n", pCtx->rip, u64Val));
5135 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RSP, &u64Val); AssertRC(rc);
5136 Log4(("Old Guest Rsp %#RX64 New %#RX64\n", pCtx->rsp, u64Val));
5137 rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &u32Val); AssertRC(rc);
5138 Log4(("Old Guest Rflags %#RX32 New %#RX32\n", pCtx->eflags.u32, u32Val));
5139 if (pVM->hm.s.vmx.fVpid)
5140 {
5141 rc = VMXReadVmcs32(VMX_VMCS16_VPID, &u32Val); AssertRC(rc);
5142 Log4(("VMX_VMCS16_VPID %u\n", u32Val));
5143 }
5144
5145 /* Host bits. */
5146 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR0, &uHCReg); AssertRC(rc);
5147 Log4(("Host CR0 %#RHr\n", uHCReg));
5148 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR3, &uHCReg); AssertRC(rc);
5149 Log4(("Host CR3 %#RHr\n", uHCReg));
5150 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR4, &uHCReg); AssertRC(rc);
5151 Log4(("Host CR4 %#RHr\n", uHCReg));
5152
5153 RTGDTR HostGdtr;
5154 PCX86DESCHC pDesc;
5155 ASMGetGDTR(&HostGdtr);
5156 rc = VMXReadVmcs32(VMX_VMCS16_HOST_CS_SEL, &u32Val); AssertRC(rc);
5157 Log4(("Host CS %#08x\n", u32Val));
5158 if (u32Val < HostGdtr.cbGdt)
5159 {
5160 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5161 HMR0DumpDescriptor(pDesc, u32Val, "CS: ");
5162 }
5163
5164 rc = VMXReadVmcs32(VMX_VMCS16_HOST_DS_SEL, &u32Val); AssertRC(rc);
5165 Log4(("Host DS %#08x\n", u32Val));
5166 if (u32Val < HostGdtr.cbGdt)
5167 {
5168 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5169 HMR0DumpDescriptor(pDesc, u32Val, "DS: ");
5170 }
5171
5172 rc = VMXReadVmcs32(VMX_VMCS16_HOST_ES_SEL, &u32Val); AssertRC(rc);
5173 Log4(("Host ES %#08x\n", u32Val));
5174 if (u32Val < HostGdtr.cbGdt)
5175 {
5176 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5177 HMR0DumpDescriptor(pDesc, u32Val, "ES: ");
5178 }
5179
5180 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FS_SEL, &u32Val); AssertRC(rc);
5181 Log4(("Host FS %#08x\n", u32Val));
5182 if (u32Val < HostGdtr.cbGdt)
5183 {
5184 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5185 HMR0DumpDescriptor(pDesc, u32Val, "FS: ");
5186 }
5187
5188 rc = VMXReadVmcs32(VMX_VMCS16_HOST_GS_SEL, &u32Val); AssertRC(rc);
5189 Log4(("Host GS %#08x\n", u32Val));
5190 if (u32Val < HostGdtr.cbGdt)
5191 {
5192 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5193 HMR0DumpDescriptor(pDesc, u32Val, "GS: ");
5194 }
5195
5196 rc = VMXReadVmcs32(VMX_VMCS16_HOST_SS_SEL, &u32Val); AssertRC(rc);
5197 Log4(("Host SS %#08x\n", u32Val));
5198 if (u32Val < HostGdtr.cbGdt)
5199 {
5200 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5201 HMR0DumpDescriptor(pDesc, u32Val, "SS: ");
5202 }
5203
5204 rc = VMXReadVmcs32(VMX_VMCS16_HOST_TR_SEL, &u32Val); AssertRC(rc);
5205 Log4(("Host TR %#08x\n", u32Val));
5206 if (u32Val < HostGdtr.cbGdt)
5207 {
5208 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5209 HMR0DumpDescriptor(pDesc, u32Val, "TR: ");
5210 }
5211
5212 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_TR_BASE, &uHCReg); AssertRC(rc);
5213 Log4(("Host TR Base %#RHv\n", uHCReg));
5214 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_GDTR_BASE, &uHCReg); AssertRC(rc);
5215 Log4(("Host GDTR Base %#RHv\n", uHCReg));
5216 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_IDTR_BASE, &uHCReg); AssertRC(rc);
5217 Log4(("Host IDTR Base %#RHv\n", uHCReg));
5218 rc = VMXReadVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, &u32Val); AssertRC(rc);
5219 Log4(("Host SYSENTER CS %#08x\n", u32Val));
5220 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_SYSENTER_EIP, &uHCReg); AssertRC(rc);
5221 Log4(("Host SYSENTER EIP %#RHv\n", uHCReg));
5222 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_SYSENTER_ESP, &uHCReg); AssertRC(rc);
5223 Log4(("Host SYSENTER ESP %#RHv\n", uHCReg));
5224 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_RSP, &uHCReg); AssertRC(rc);
5225 Log4(("Host RSP %#RHv\n", uHCReg));
5226 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_RIP, &uHCReg); AssertRC(rc);
5227 Log4(("Host RIP %#RHv\n", uHCReg));
5228# if HC_ARCH_BITS == 64
5229 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
5230 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
5231 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
5232 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
5233 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
5234 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
5235# endif
5236#endif /* VBOX_STRICT */
5237 break;
5238 }
5239
5240 default:
5241 /* Impossible */
5242 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
5243 break;
5244 }
5245 NOREF(pVM); NOREF(pCtx);
5246}
5247
5248
5249#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
5250#ifndef VMX_USE_CACHED_VMCS_ACCESSES
5251# error "VMX_USE_CACHED_VMCS_ACCESSES not defined when it should be!"
5252#endif
5253#ifdef VBOX_STRICT
5254static bool hmR0VmxIsValidWriteField(uint32_t idxField)
5255{
5256 switch (idxField)
5257 {
5258 case VMX_VMCS_GUEST_RIP:
5259 case VMX_VMCS_GUEST_RSP:
5260 case VMX_VMCS_GUEST_SYSENTER_EIP:
5261 case VMX_VMCS_GUEST_SYSENTER_ESP:
5262 case VMX_VMCS_GUEST_GDTR_BASE:
5263 case VMX_VMCS_GUEST_IDTR_BASE:
5264 case VMX_VMCS_GUEST_CS_BASE:
5265 case VMX_VMCS_GUEST_DS_BASE:
5266 case VMX_VMCS_GUEST_ES_BASE:
5267 case VMX_VMCS_GUEST_FS_BASE:
5268 case VMX_VMCS_GUEST_GS_BASE:
5269 case VMX_VMCS_GUEST_SS_BASE:
5270 case VMX_VMCS_GUEST_LDTR_BASE:
5271 case VMX_VMCS_GUEST_TR_BASE:
5272 case VMX_VMCS_GUEST_CR3:
5273 return true;
5274 }
5275 return false;
5276}
5277
5278static bool hmR0VmxIsValidReadField(uint32_t idxField)
5279{
5280 switch (idxField)
5281 {
5282 /* Read-only fields. */
5283 case VMX_VMCS_RO_EXIT_QUALIFICATION:
5284 return true;
5285 }
5286 /* Remaining readable fields should also be writable. */
5287 return hmR0VmxIsValidWriteField(idxField);
5288}
5289#endif /* VBOX_STRICT */
5290
5291
5292/**
5293 * Executes the specified handler in 64-bit mode.
5294 *
5295 * @returns VBox status code (no informational status codes).
5296 * @param pVM The cross context VM structure.
5297 * @param pVCpu The cross context virtual CPU structure.
5298 * @param pCtx Pointer to the guest CPU context.
5299 * @param enmOp The operation to perform.
5300 * @param cParams Number of parameters.
5301 * @param paParam Array of 32-bit parameters.
5302 */
5303VMMR0DECL(int) VMXR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, HM64ON32OP enmOp,
5304 uint32_t cParams, uint32_t *paParam)
5305{
5306 NOREF(pCtx);
5307
5308 AssertReturn(pVM->hm.s.pfnHost32ToGuest64R0, VERR_HM_NO_32_TO_64_SWITCHER);
5309 Assert(enmOp > HM64ON32OP_INVALID && enmOp < HM64ON32OP_END);
5310 Assert(pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Write.aField));
5311 Assert(pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Read.aField));
5312
5313#ifdef VBOX_STRICT
5314 for (uint32_t i = 0; i < pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries; i++)
5315 Assert(hmR0VmxIsValidWriteField(pVCpu->hm.s.vmx.VMCSCache.Write.aField[i]));
5316
5317 for (uint32_t i = 0; i <pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries; i++)
5318 Assert(hmR0VmxIsValidReadField(pVCpu->hm.s.vmx.VMCSCache.Read.aField[i]));
5319#endif
5320
5321 /* Disable interrupts. */
5322 RTCCUINTREG fOldEFlags = ASMIntDisableFlags();
5323
5324#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
5325 RTCPUID idHostCpu = RTMpCpuId();
5326 CPUMR0SetLApic(pVCpu, idHostCpu);
5327#endif
5328
5329 PHMGLOBALCPUINFO pCpu = HMR0GetCurrentCpu();
5330 RTHCPHYS HCPhysCpuPage = pCpu->HCPhysMemObj;
5331
5332 /* Clear VMCS. Marking it inactive, clearing implementation-specific data and writing VMCS data back to memory. */
5333 VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
5334 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
5335
5336 /* Leave VMX Root Mode. */
5337 VMXDisable();
5338
5339 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
5340
5341 CPUMSetHyperESP(pVCpu, VMMGetStackRC(pVCpu));
5342 CPUMSetHyperEIP(pVCpu, enmOp);
5343 for (int i = (int)cParams - 1; i >= 0; i--)
5344 CPUMPushHyper(pVCpu, paParam[i]);
5345
5346 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatWorldSwitch3264, z);
5347
5348 /* Call the switcher. */
5349 int rc = pVM->hm.s.pfnHost32ToGuest64R0(pVM, RT_OFFSETOF(VM, aCpus[pVCpu->idCpu].cpum) - RT_OFFSETOF(VM, cpum));
5350 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatWorldSwitch3264, z);
5351
5352 /** @todo replace with hmR0VmxEnterRootMode() and hmR0VmxLeaveRootMode(). */
5353 /* Make sure the VMX instructions don't cause #UD faults. */
5354 SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
5355
5356 /* Re-enter VMX Root Mode */
5357 int rc2 = VMXEnable(HCPhysCpuPage);
5358 if (RT_FAILURE(rc2))
5359 {
5360 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
5361 ASMSetFlags(fOldEFlags);
5362 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
5363 return rc2;
5364 }
5365
5366 rc2 = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
5367 AssertRC(rc2);
5368 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
5369 Assert(!(ASMGetFlags() & X86_EFL_IF));
5370 ASMSetFlags(fOldEFlags);
5371 return rc;
5372}
5373
5374
5375/**
5376 * Prepares for and executes VMLAUNCH (64-bit guests) for 32-bit hosts
5377 * supporting 64-bit guests.
5378 *
5379 * @returns VBox status code.
5380 * @param fResume Whether to VMLAUNCH or VMRESUME.
5381 * @param pCtx Pointer to the guest-CPU context.
5382 * @param pCache Pointer to the VMCS cache.
5383 * @param pVM The cross context VM structure.
5384 * @param pVCpu The cross context virtual CPU structure.
5385 */
5386DECLASM(int) VMXR0SwitcherStartVM64(RTHCUINT fResume, PCPUMCTX pCtx, PVMCSCACHE pCache, PVM pVM, PVMCPU pVCpu)
5387{
5388 NOREF(fResume);
5389
5390 PHMGLOBALCPUINFO pCpu = HMR0GetCurrentCpu();
5391 RTHCPHYS HCPhysCpuPage = pCpu->HCPhysMemObj;
5392
5393#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5394 pCache->uPos = 1;
5395 pCache->interPD = PGMGetInterPaeCR3(pVM);
5396 pCache->pSwitcher = (uint64_t)pVM->hm.s.pfnHost32ToGuest64R0;
5397#endif
5398
5399#if defined(DEBUG) && defined(VMX_USE_CACHED_VMCS_ACCESSES)
5400 pCache->TestIn.HCPhysCpuPage = 0;
5401 pCache->TestIn.HCPhysVmcs = 0;
5402 pCache->TestIn.pCache = 0;
5403 pCache->TestOut.HCPhysVmcs = 0;
5404 pCache->TestOut.pCache = 0;
5405 pCache->TestOut.pCtx = 0;
5406 pCache->TestOut.eflags = 0;
5407#else
5408 NOREF(pCache);
5409#endif
5410
5411 uint32_t aParam[10];
5412 aParam[0] = (uint32_t)(HCPhysCpuPage); /* Param 1: VMXON physical address - Lo. */
5413 aParam[1] = (uint32_t)(HCPhysCpuPage >> 32); /* Param 1: VMXON physical address - Hi. */
5414 aParam[2] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs); /* Param 2: VMCS physical address - Lo. */
5415 aParam[3] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs >> 32); /* Param 2: VMCS physical address - Hi. */
5416 aParam[4] = VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache);
5417 aParam[5] = 0;
5418 aParam[6] = VM_RC_ADDR(pVM, pVM);
5419 aParam[7] = 0;
5420 aParam[8] = VM_RC_ADDR(pVM, pVCpu);
5421 aParam[9] = 0;
5422
5423#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5424 pCtx->dr[4] = pVM->hm.s.vmx.pScratchPhys + 16 + 8;
5425 *(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) = 1;
5426#endif
5427 int rc = VMXR0Execute64BitsHandler(pVM, pVCpu, pCtx, HM64ON32OP_VMXRCStartVM64, RT_ELEMENTS(aParam), &aParam[0]);
5428
5429#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5430 Assert(*(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) == 5);
5431 Assert(pCtx->dr[4] == 10);
5432 *(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) = 0xff;
5433#endif
5434
5435#if defined(DEBUG) && defined(VMX_USE_CACHED_VMCS_ACCESSES)
5436 AssertMsg(pCache->TestIn.HCPhysCpuPage == HCPhysCpuPage, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysCpuPage, HCPhysCpuPage));
5437 AssertMsg(pCache->TestIn.HCPhysVmcs == pVCpu->hm.s.vmx.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
5438 pVCpu->hm.s.vmx.HCPhysVmcs));
5439 AssertMsg(pCache->TestIn.HCPhysVmcs == pCache->TestOut.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
5440 pCache->TestOut.HCPhysVmcs));
5441 AssertMsg(pCache->TestIn.pCache == pCache->TestOut.pCache, ("%RGv vs %RGv\n", pCache->TestIn.pCache,
5442 pCache->TestOut.pCache));
5443 AssertMsg(pCache->TestIn.pCache == VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache),
5444 ("%RGv vs %RGv\n", pCache->TestIn.pCache, VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache)));
5445 AssertMsg(pCache->TestIn.pCtx == pCache->TestOut.pCtx, ("%RGv vs %RGv\n", pCache->TestIn.pCtx,
5446 pCache->TestOut.pCtx));
5447 Assert(!(pCache->TestOut.eflags & X86_EFL_IF));
5448#endif
5449 return rc;
5450}
5451
5452
5453/**
5454 * Initialize the VMCS-Read cache.
5455 *
5456 * The VMCS cache is used for 32-bit hosts running 64-bit guests (except 32-bit
5457 * Darwin which runs with 64-bit paging in 32-bit mode) for 64-bit fields that
5458 * cannot be accessed in 32-bit mode. Some 64-bit fields -can- be accessed
5459 * (those that have a 32-bit FULL & HIGH part).
5460 *
5461 * @returns VBox status code.
5462 * @param pVM The cross context VM structure.
5463 * @param pVCpu The cross context virtual CPU structure.
5464 */
5465static int hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu)
5466{
5467#define VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, idxField) \
5468{ \
5469 Assert(pCache->Read.aField[idxField##_CACHE_IDX] == 0); \
5470 pCache->Read.aField[idxField##_CACHE_IDX] = idxField; \
5471 pCache->Read.aFieldVal[idxField##_CACHE_IDX] = 0; \
5472 ++cReadFields; \
5473}
5474
5475 AssertPtr(pVM);
5476 AssertPtr(pVCpu);
5477 PVMCSCACHE pCache = &pVCpu->hm.s.vmx.VMCSCache;
5478 uint32_t cReadFields = 0;
5479
5480 /*
5481 * Don't remove the #if 0'd fields in this code. They're listed here for consistency
5482 * and serve to indicate exceptions to the rules.
5483 */
5484
5485 /* Guest-natural selector base fields. */
5486#if 0
5487 /* These are 32-bit in practice. See Intel spec. 2.5 "Control Registers". */
5488 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR0);
5489 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR4);
5490#endif
5491 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_ES_BASE);
5492 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CS_BASE);
5493 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SS_BASE);
5494 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_DS_BASE);
5495 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_FS_BASE);
5496 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_GS_BASE);
5497 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_LDTR_BASE);
5498 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_TR_BASE);
5499 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_GDTR_BASE);
5500 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_IDTR_BASE);
5501 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_RSP);
5502 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_RIP);
5503#if 0
5504 /* Unused natural width guest-state fields. */
5505 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS);
5506 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR3); /* Handled in Nested Paging case */
5507#endif
5508 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SYSENTER_ESP);
5509 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SYSENTER_EIP);
5510
5511 /* 64-bit guest-state fields; unused as we use two 32-bit VMREADs for these 64-bit fields (using "FULL" and "HIGH" fields). */
5512#if 0
5513 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL);
5514 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_DEBUGCTL_FULL);
5515 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PAT_FULL);
5516 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_EFER_FULL);
5517 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL);
5518 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE0_FULL);
5519 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE1_FULL);
5520 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE2_FULL);
5521 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE3_FULL);
5522#endif
5523
5524 /* Natural width guest-state fields. */
5525 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_RO_EXIT_QUALIFICATION);
5526#if 0
5527 /* Currently unused field. */
5528 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_RO_EXIT_GUEST_LINEAR_ADDR);
5529#endif
5530
5531 if (pVM->hm.s.fNestedPaging)
5532 {
5533 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR3);
5534 AssertMsg(cReadFields == VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields,
5535 VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX));
5536 pCache->Read.cValidEntries = VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX;
5537 }
5538 else
5539 {
5540 AssertMsg(cReadFields == VMX_VMCS_MAX_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields, VMX_VMCS_MAX_CACHE_IDX));
5541 pCache->Read.cValidEntries = VMX_VMCS_MAX_CACHE_IDX;
5542 }
5543
5544#undef VMXLOCAL_INIT_READ_CACHE_FIELD
5545 return VINF_SUCCESS;
5546}
5547
5548
5549/**
5550 * Writes a field into the VMCS. This can either directly invoke a VMWRITE or
5551 * queue up the VMWRITE by using the VMCS write cache (on 32-bit hosts, except
5552 * darwin, running 64-bit guests).
5553 *
5554 * @returns VBox status code.
5555 * @param pVCpu The cross context virtual CPU structure.
5556 * @param idxField The VMCS field encoding.
5557 * @param u64Val 16, 32 or 64-bit value.
5558 */
5559VMMR0DECL(int) VMXWriteVmcs64Ex(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
5560{
5561 int rc;
5562 switch (idxField)
5563 {
5564 /*
5565 * These fields consists of a "FULL" and a "HIGH" part which can be written to individually.
5566 */
5567 /* 64-bit Control fields. */
5568 case VMX_VMCS64_CTRL_IO_BITMAP_A_FULL:
5569 case VMX_VMCS64_CTRL_IO_BITMAP_B_FULL:
5570 case VMX_VMCS64_CTRL_MSR_BITMAP_FULL:
5571 case VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL:
5572 case VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL:
5573 case VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL:
5574 case VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL:
5575 case VMX_VMCS64_CTRL_TSC_OFFSET_FULL:
5576 case VMX_VMCS64_CTRL_VAPIC_PAGEADDR_FULL:
5577 case VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL:
5578 case VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL:
5579 case VMX_VMCS64_CTRL_EPTP_FULL:
5580 case VMX_VMCS64_CTRL_EPTP_LIST_FULL:
5581 /* 64-bit Guest-state fields. */
5582 case VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL:
5583 case VMX_VMCS64_GUEST_DEBUGCTL_FULL:
5584 case VMX_VMCS64_GUEST_PAT_FULL:
5585 case VMX_VMCS64_GUEST_EFER_FULL:
5586 case VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL:
5587 case VMX_VMCS64_GUEST_PDPTE0_FULL:
5588 case VMX_VMCS64_GUEST_PDPTE1_FULL:
5589 case VMX_VMCS64_GUEST_PDPTE2_FULL:
5590 case VMX_VMCS64_GUEST_PDPTE3_FULL:
5591 /* 64-bit Host-state fields. */
5592 case VMX_VMCS64_HOST_PAT_FULL:
5593 case VMX_VMCS64_HOST_EFER_FULL:
5594 case VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL:
5595 {
5596 rc = VMXWriteVmcs32(idxField, u64Val);
5597 rc |= VMXWriteVmcs32(idxField + 1, (uint32_t)(u64Val >> 32));
5598 break;
5599 }
5600
5601 /*
5602 * These fields do not have high and low parts. Queue up the VMWRITE by using the VMCS write-cache (for 64-bit
5603 * values). When we switch the host to 64-bit mode for running 64-bit guests, these VMWRITEs get executed then.
5604 */
5605 /* Natural-width Guest-state fields. */
5606 case VMX_VMCS_GUEST_CR3:
5607 case VMX_VMCS_GUEST_ES_BASE:
5608 case VMX_VMCS_GUEST_CS_BASE:
5609 case VMX_VMCS_GUEST_SS_BASE:
5610 case VMX_VMCS_GUEST_DS_BASE:
5611 case VMX_VMCS_GUEST_FS_BASE:
5612 case VMX_VMCS_GUEST_GS_BASE:
5613 case VMX_VMCS_GUEST_LDTR_BASE:
5614 case VMX_VMCS_GUEST_TR_BASE:
5615 case VMX_VMCS_GUEST_GDTR_BASE:
5616 case VMX_VMCS_GUEST_IDTR_BASE:
5617 case VMX_VMCS_GUEST_RSP:
5618 case VMX_VMCS_GUEST_RIP:
5619 case VMX_VMCS_GUEST_SYSENTER_ESP:
5620 case VMX_VMCS_GUEST_SYSENTER_EIP:
5621 {
5622 if (!(u64Val >> 32))
5623 {
5624 /* If this field is 64-bit, VT-x will zero out the top bits. */
5625 rc = VMXWriteVmcs32(idxField, (uint32_t)u64Val);
5626 }
5627 else
5628 {
5629 /* Assert that only the 32->64 switcher case should ever come here. */
5630 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests);
5631 rc = VMXWriteCachedVmcsEx(pVCpu, idxField, u64Val);
5632 }
5633 break;
5634 }
5635
5636 default:
5637 {
5638 AssertMsgFailed(("VMXWriteVmcs64Ex: Invalid field %#RX32 (pVCpu=%p u64Val=%#RX64)\n", idxField, pVCpu, u64Val));
5639 rc = VERR_INVALID_PARAMETER;
5640 break;
5641 }
5642 }
5643 AssertRCReturn(rc, rc);
5644 return rc;
5645}
5646
5647
5648/**
5649 * Queue up a VMWRITE by using the VMCS write cache.
5650 * This is only used on 32-bit hosts (except darwin) for 64-bit guests.
5651 *
5652 * @param pVCpu The cross context virtual CPU structure.
5653 * @param idxField The VMCS field encoding.
5654 * @param u64Val 16, 32 or 64-bit value.
5655 */
5656VMMR0DECL(int) VMXWriteCachedVmcsEx(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
5657{
5658 AssertPtr(pVCpu);
5659 PVMCSCACHE pCache = &pVCpu->hm.s.vmx.VMCSCache;
5660
5661 AssertMsgReturn(pCache->Write.cValidEntries < VMCSCACHE_MAX_ENTRY - 1,
5662 ("entries=%u\n", pCache->Write.cValidEntries), VERR_ACCESS_DENIED);
5663
5664 /* Make sure there are no duplicates. */
5665 for (uint32_t i = 0; i < pCache->Write.cValidEntries; i++)
5666 {
5667 if (pCache->Write.aField[i] == idxField)
5668 {
5669 pCache->Write.aFieldVal[i] = u64Val;
5670 return VINF_SUCCESS;
5671 }
5672 }
5673
5674 pCache->Write.aField[pCache->Write.cValidEntries] = idxField;
5675 pCache->Write.aFieldVal[pCache->Write.cValidEntries] = u64Val;
5676 pCache->Write.cValidEntries++;
5677 return VINF_SUCCESS;
5678}
5679#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) */
5680
5681
5682/**
5683 * Sets up the usage of TSC-offsetting and updates the VMCS.
5684 *
5685 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
5686 * VMX preemption timer.
5687 *
5688 * @returns VBox status code.
5689 * @param pVM The cross context VM structure.
5690 * @param pVCpu The cross context virtual CPU structure.
5691 *
5692 * @remarks No-long-jump zone!!!
5693 */
5694static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVM pVM, PVMCPU pVCpu)
5695{
5696 int rc;
5697 bool fOffsettedTsc;
5698 bool fParavirtTsc;
5699 if (pVM->hm.s.vmx.fUsePreemptTimer)
5700 {
5701 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset,
5702 &fOffsettedTsc, &fParavirtTsc);
5703
5704 /* Make sure the returned values have sane upper and lower boundaries. */
5705 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
5706 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
5707 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
5708 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
5709
5710 uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
5711 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_PREEMPT_TIMER_VALUE, cPreemptionTickCount); AssertRC(rc);
5712 }
5713 else
5714 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset, &fParavirtTsc);
5715
5716 /** @todo later optimize this to be done elsewhere and not before every
5717 * VM-entry. */
5718 if (fParavirtTsc)
5719 {
5720 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
5721 information before every VM-entry, hence disable it for performance sake. */
5722#if 0
5723 rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
5724 AssertRC(rc);
5725#endif
5726 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
5727 }
5728
5729 if (fOffsettedTsc && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
5730 {
5731 /* Note: VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT takes precedence over TSC_OFFSET, applies to RDTSCP too. */
5732 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, pVCpu->hm.s.vmx.u64TSCOffset); AssertRC(rc);
5733
5734 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
5735 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
5736 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
5737 }
5738 else
5739 {
5740 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
5741 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
5742 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
5743 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
5744 }
5745}
5746
5747
5748/**
5749 * Determines if an exception is a contributory exception.
5750 *
5751 * Contributory exceptions are ones which can cause double-faults unless the
5752 * original exception was a benign exception. Page-fault is intentionally not
5753 * included here as it's a conditional contributory exception.
5754 *
5755 * @returns true if the exception is contributory, false otherwise.
5756 * @param uVector The exception vector.
5757 */
5758DECLINLINE(bool) hmR0VmxIsContributoryXcpt(const uint32_t uVector)
5759{
5760 switch (uVector)
5761 {
5762 case X86_XCPT_GP:
5763 case X86_XCPT_SS:
5764 case X86_XCPT_NP:
5765 case X86_XCPT_TS:
5766 case X86_XCPT_DE:
5767 return true;
5768 default:
5769 break;
5770 }
5771 return false;
5772}
5773
5774
5775/**
5776 * Sets an event as a pending event to be injected into the guest.
5777 *
5778 * @param pVCpu The cross context virtual CPU structure.
5779 * @param u32IntInfo The VM-entry interruption-information field.
5780 * @param cbInstr The VM-entry instruction length in bytes (for software
5781 * interrupts, exceptions and privileged software
5782 * exceptions).
5783 * @param u32ErrCode The VM-entry exception error code.
5784 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
5785 * page-fault.
5786 *
5787 * @remarks Statistics counter assumes this is a guest event being injected or
5788 * re-injected into the guest, i.e. 'StatInjectPendingReflect' is
5789 * always incremented.
5790 */
5791DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
5792 RTGCUINTPTR GCPtrFaultAddress)
5793{
5794 Assert(!pVCpu->hm.s.Event.fPending);
5795 pVCpu->hm.s.Event.fPending = true;
5796 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
5797 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
5798 pVCpu->hm.s.Event.cbInstr = cbInstr;
5799 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
5800}
5801
5802
5803/**
5804 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
5805 *
5806 * @param pVCpu The cross context virtual CPU structure.
5807 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5808 * out-of-sync. Make sure to update the required fields
5809 * before using them.
5810 */
5811DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5812{
5813 NOREF(pMixedCtx);
5814 uint32_t u32IntInfo = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
5815 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
5816 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
5817 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
5818}
5819
5820
5821/**
5822 * Handle a condition that occurred while delivering an event through the guest
5823 * IDT.
5824 *
5825 * @returns Strict VBox status code (i.e. informational status codes too).
5826 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
5827 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
5828 * to continue execution of the guest which will delivery the \#DF.
5829 * @retval VINF_EM_RESET if we detected a triple-fault condition.
5830 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
5831 *
5832 * @param pVCpu The cross context virtual CPU structure.
5833 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5834 * out-of-sync. Make sure to update the required fields
5835 * before using them.
5836 * @param pVmxTransient Pointer to the VMX transient structure.
5837 *
5838 * @remarks No-long-jump zone!!!
5839 */
5840static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
5841{
5842 uint32_t uExitVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
5843
5844 int rc2 = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient); AssertRCReturn(rc2, rc2);
5845 rc2 = hmR0VmxReadExitIntInfoVmcs(pVmxTransient); AssertRCReturn(rc2, rc2);
5846
5847 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
5848 if (VMX_IDT_VECTORING_INFO_VALID(pVmxTransient->uIdtVectoringInfo))
5849 {
5850 uint32_t uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
5851 uint32_t uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
5852
5853 typedef enum
5854 {
5855 VMXREFLECTXCPT_XCPT, /* Reflect the exception to the guest or for further evaluation by VMM. */
5856 VMXREFLECTXCPT_DF, /* Reflect the exception as a double-fault to the guest. */
5857 VMXREFLECTXCPT_TF, /* Indicate a triple faulted state to the VMM. */
5858 VMXREFLECTXCPT_HANG, /* Indicate bad VM trying to deadlock the CPU. */
5859 VMXREFLECTXCPT_NONE /* Nothing to reflect. */
5860 } VMXREFLECTXCPT;
5861
5862 /* See Intel spec. 30.7.1.1 "Reflecting Exceptions to Guest Software". */
5863 VMXREFLECTXCPT enmReflect = VMXREFLECTXCPT_NONE;
5864 if (VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo))
5865 {
5866 if (uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT)
5867 {
5868 enmReflect = VMXREFLECTXCPT_XCPT;
5869#ifdef VBOX_STRICT
5870 if ( hmR0VmxIsContributoryXcpt(uIdtVector)
5871 && uExitVector == X86_XCPT_PF)
5872 {
5873 Log4(("IDT: vcpu[%RU32] Contributory #PF uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
5874 }
5875#endif
5876 if ( uExitVector == X86_XCPT_PF
5877 && uIdtVector == X86_XCPT_PF)
5878 {
5879 pVmxTransient->fVectoringDoublePF = true;
5880 Log4(("IDT: vcpu[%RU32] Vectoring Double #PF uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
5881 }
5882 else if ( uExitVector == X86_XCPT_AC
5883 && uIdtVector == X86_XCPT_AC)
5884 {
5885 enmReflect = VMXREFLECTXCPT_HANG;
5886 Log4(("IDT: Nested #AC - Bad guest\n"));
5887 }
5888 else if ( (pVCpu->hm.s.vmx.u32XcptBitmap & HMVMX_CONTRIBUTORY_XCPT_MASK)
5889 && hmR0VmxIsContributoryXcpt(uExitVector)
5890 && ( hmR0VmxIsContributoryXcpt(uIdtVector)
5891 || uIdtVector == X86_XCPT_PF))
5892 {
5893 enmReflect = VMXREFLECTXCPT_DF;
5894 }
5895 else if (uIdtVector == X86_XCPT_DF)
5896 enmReflect = VMXREFLECTXCPT_TF;
5897 }
5898 else if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT
5899 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI)
5900 {
5901 /*
5902 * Ignore software interrupts (INT n), software exceptions (#BP, #OF) and
5903 * privileged software exception (#DB from ICEBP) as they reoccur when restarting the instruction.
5904 */
5905 enmReflect = VMXREFLECTXCPT_XCPT;
5906
5907 if (uExitVector == X86_XCPT_PF)
5908 {
5909 pVmxTransient->fVectoringPF = true;
5910 Log4(("IDT: vcpu[%RU32] Vectoring #PF due to Ext-Int/NMI. uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
5911 }
5912 }
5913 }
5914 else if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
5915 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT
5916 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI)
5917 {
5918 /*
5919 * If event delivery caused an EPT violation/misconfig or APIC access VM-exit, then the VM-exit
5920 * interruption-information will not be valid as it's not an exception and we end up here. In such cases,
5921 * it is sufficient to reflect the original exception to the guest after handling the VM-exit.
5922 */
5923 enmReflect = VMXREFLECTXCPT_XCPT;
5924 }
5925
5926 /*
5927 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig etc.) occurred
5928 * while delivering the NMI, we need to clear the block-by-NMI field in the guest interruptibility-state before
5929 * re-delivering the NMI after handling the VM-exit. Otherwise the subsequent VM-entry would fail.
5930 *
5931 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception". See @bugref{7445}.
5932 */
5933 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
5934 && enmReflect == VMXREFLECTXCPT_XCPT
5935 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
5936 && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
5937 {
5938 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
5939 }
5940
5941 switch (enmReflect)
5942 {
5943 case VMXREFLECTXCPT_XCPT:
5944 {
5945 Assert( uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT
5946 && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
5947 && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT);
5948
5949 uint32_t u32ErrCode = 0;
5950 if (VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo))
5951 {
5952 rc2 = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
5953 AssertRCReturn(rc2, rc2);
5954 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
5955 }
5956
5957 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF. See hmR0VmxExitXcptPF(). */
5958 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
5959 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
5960 0 /* cbInstr */, u32ErrCode, pMixedCtx->cr2);
5961 rcStrict = VINF_SUCCESS;
5962 Log4(("IDT: vcpu[%RU32] Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->idCpu,
5963 pVCpu->hm.s.Event.u64IntInfo, pVCpu->hm.s.Event.u32ErrCode));
5964
5965 break;
5966 }
5967
5968 case VMXREFLECTXCPT_DF:
5969 {
5970 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
5971 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
5972 rcStrict = VINF_HM_DOUBLE_FAULT;
5973 Log4(("IDT: vcpu[%RU32] Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->idCpu,
5974 pVCpu->hm.s.Event.u64IntInfo, uIdtVector, uExitVector));
5975
5976 break;
5977 }
5978
5979 case VMXREFLECTXCPT_TF:
5980 {
5981 rcStrict = VINF_EM_RESET;
5982 Log4(("IDT: vcpu[%RU32] Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", pVCpu->idCpu, uIdtVector,
5983 uExitVector));
5984 break;
5985 }
5986
5987 case VMXREFLECTXCPT_HANG:
5988 {
5989 rcStrict = VERR_EM_GUEST_CPU_HANG;
5990 break;
5991 }
5992
5993 default:
5994 Assert(rcStrict == VINF_SUCCESS);
5995 break;
5996 }
5997 }
5998 else if ( VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo)
5999 && VMX_EXIT_INTERRUPTION_INFO_NMI_UNBLOCK_IRET(pVmxTransient->uExitIntInfo)
6000 && uExitVector != X86_XCPT_DF
6001 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
6002 {
6003 /*
6004 * Execution of IRET caused this fault when NMI blocking was in effect (i.e we're in the guest NMI handler).
6005 * We need to set the block-by-NMI field so that NMIs remain blocked until the IRET execution is restarted.
6006 * See Intel spec. 30.7.1.2 "Resuming guest software after handling an exception".
6007 */
6008 if (!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6009 {
6010 Log4(("hmR0VmxCheckExitDueToEventDelivery: vcpu[%RU32] Setting VMCPU_FF_BLOCK_NMIS. Valid=%RTbool uExitReason=%u\n",
6011 pVCpu->idCpu, VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo), pVmxTransient->uExitReason));
6012 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
6013 }
6014 }
6015
6016 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
6017 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
6018 return rcStrict;
6019}
6020
6021
6022/**
6023 * Saves the guest's CR0 register from the VMCS into the guest-CPU context.
6024 *
6025 * @returns VBox status code.
6026 * @param pVCpu The cross context virtual CPU structure.
6027 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6028 * out-of-sync. Make sure to update the required fields
6029 * before using them.
6030 *
6031 * @remarks No-long-jump zone!!!
6032 */
6033static int hmR0VmxSaveGuestCR0(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6034{
6035 NOREF(pMixedCtx);
6036
6037 /*
6038 * While in the middle of saving guest-CR0, we could get preempted and re-invoked from the preemption hook,
6039 * see hmR0VmxLeave(). Safer to just make this code non-preemptible.
6040 */
6041 VMMRZCallRing3Disable(pVCpu);
6042 HM_DISABLE_PREEMPT();
6043
6044 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0))
6045 {
6046 uint32_t uVal = 0;
6047 uint32_t uShadow = 0;
6048 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &uVal);
6049 rc |= VMXReadVmcs32(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uShadow);
6050 AssertRCReturn(rc, rc);
6051
6052 uVal = (uShadow & pVCpu->hm.s.vmx.u32CR0Mask) | (uVal & ~pVCpu->hm.s.vmx.u32CR0Mask);
6053 CPUMSetGuestCR0(pVCpu, uVal);
6054 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0);
6055 }
6056
6057 HM_RESTORE_PREEMPT();
6058 VMMRZCallRing3Enable(pVCpu);
6059 return VINF_SUCCESS;
6060}
6061
6062
6063/**
6064 * Saves the guest's CR4 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 hmR0VmxSaveGuestCR4(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6075{
6076 NOREF(pMixedCtx);
6077
6078 int rc = VINF_SUCCESS;
6079 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4))
6080 {
6081 uint32_t uVal = 0;
6082 uint32_t uShadow = 0;
6083 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &uVal);
6084 rc |= VMXReadVmcs32(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uShadow);
6085 AssertRCReturn(rc, rc);
6086
6087 uVal = (uShadow & pVCpu->hm.s.vmx.u32CR4Mask) | (uVal & ~pVCpu->hm.s.vmx.u32CR4Mask);
6088 CPUMSetGuestCR4(pVCpu, uVal);
6089 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4);
6090 }
6091 return rc;
6092}
6093
6094
6095/**
6096 * Saves the guest's RIP register from the VMCS into the guest-CPU context.
6097 *
6098 * @returns VBox status code.
6099 * @param pVCpu The cross context virtual CPU structure.
6100 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6101 * out-of-sync. Make sure to update the required fields
6102 * before using them.
6103 *
6104 * @remarks No-long-jump zone!!!
6105 */
6106static int hmR0VmxSaveGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6107{
6108 int rc = VINF_SUCCESS;
6109 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP))
6110 {
6111 uint64_t u64Val = 0;
6112 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RIP, &u64Val);
6113 AssertRCReturn(rc, rc);
6114
6115 pMixedCtx->rip = u64Val;
6116 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP);
6117 }
6118 return rc;
6119}
6120
6121
6122/**
6123 * Saves the guest's RSP register from the VMCS into the guest-CPU context.
6124 *
6125 * @returns VBox status code.
6126 * @param pVCpu The cross context virtual CPU structure.
6127 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6128 * out-of-sync. Make sure to update the required fields
6129 * before using them.
6130 *
6131 * @remarks No-long-jump zone!!!
6132 */
6133static int hmR0VmxSaveGuestRsp(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6134{
6135 int rc = VINF_SUCCESS;
6136 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RSP))
6137 {
6138 uint64_t u64Val = 0;
6139 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RSP, &u64Val);
6140 AssertRCReturn(rc, rc);
6141
6142 pMixedCtx->rsp = u64Val;
6143 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RSP);
6144 }
6145 return rc;
6146}
6147
6148
6149/**
6150 * Saves the guest's RFLAGS from the VMCS into the guest-CPU context.
6151 *
6152 * @returns VBox status code.
6153 * @param pVCpu The cross context virtual CPU structure.
6154 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6155 * out-of-sync. Make sure to update the required fields
6156 * before using them.
6157 *
6158 * @remarks No-long-jump zone!!!
6159 */
6160static int hmR0VmxSaveGuestRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6161{
6162 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS))
6163 {
6164 uint32_t uVal = 0;
6165 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &uVal);
6166 AssertRCReturn(rc, rc);
6167
6168 pMixedCtx->eflags.u32 = uVal;
6169 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active) /* Undo our real-on-v86-mode changes to eflags if necessary. */
6170 {
6171 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6172 Log4(("Saving real-mode EFLAGS VT-x view=%#RX32\n", pMixedCtx->eflags.u32));
6173
6174 pMixedCtx->eflags.Bits.u1VM = 0;
6175 pMixedCtx->eflags.Bits.u2IOPL = pVCpu->hm.s.vmx.RealMode.Eflags.Bits.u2IOPL;
6176 }
6177
6178 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS);
6179 }
6180 return VINF_SUCCESS;
6181}
6182
6183
6184/**
6185 * Wrapper for saving the guest's RIP, RSP and RFLAGS from the VMCS into the
6186 * guest-CPU context.
6187 */
6188DECLINLINE(int) hmR0VmxSaveGuestRipRspRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6189{
6190 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6191 rc |= hmR0VmxSaveGuestRsp(pVCpu, pMixedCtx);
6192 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
6193 return rc;
6194}
6195
6196
6197/**
6198 * Saves the guest's interruptibility-state ("interrupt shadow" as AMD calls it)
6199 * from the guest-state area in the VMCS.
6200 *
6201 * @param pVCpu The cross context virtual CPU structure.
6202 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6203 * out-of-sync. Make sure to update the required fields
6204 * before using them.
6205 *
6206 * @remarks No-long-jump zone!!!
6207 */
6208static void hmR0VmxSaveGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6209{
6210 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_INTR_STATE))
6211 {
6212 uint32_t uIntrState = 0;
6213 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
6214 AssertRC(rc);
6215
6216 if (!uIntrState)
6217 {
6218 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
6219 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
6220
6221 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6222 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
6223 }
6224 else
6225 {
6226 if (uIntrState & ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS
6227 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI))
6228 {
6229 rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6230 AssertRC(rc);
6231 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx); /* for hmR0VmxGetGuestIntrState(). */
6232 AssertRC(rc);
6233
6234 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
6235 Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
6236 }
6237 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
6238 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
6239
6240 if (uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI)
6241 {
6242 if (!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6243 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
6244 }
6245 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6246 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
6247 }
6248
6249 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_INTR_STATE);
6250 }
6251}
6252
6253
6254/**
6255 * Saves the guest's activity state.
6256 *
6257 * @returns VBox status code.
6258 * @param pVCpu The cross context virtual CPU structure.
6259 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6260 * out-of-sync. Make sure to update the required fields
6261 * before using them.
6262 *
6263 * @remarks No-long-jump zone!!!
6264 */
6265static int hmR0VmxSaveGuestActivityState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6266{
6267 NOREF(pMixedCtx);
6268 /* Nothing to do for now until we make use of different guest-CPU activity state. Just update the flag. */
6269 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_ACTIVITY_STATE);
6270 return VINF_SUCCESS;
6271}
6272
6273
6274/**
6275 * Saves the guest SYSENTER MSRs (SYSENTER_CS, SYSENTER_EIP, SYSENTER_ESP) from
6276 * the current VMCS into the guest-CPU context.
6277 *
6278 * @returns VBox status code.
6279 * @param pVCpu The cross context virtual CPU structure.
6280 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6281 * out-of-sync. Make sure to update the required fields
6282 * before using them.
6283 *
6284 * @remarks No-long-jump zone!!!
6285 */
6286static int hmR0VmxSaveGuestSysenterMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6287{
6288 int rc = VINF_SUCCESS;
6289 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR))
6290 {
6291 uint32_t u32Val = 0;
6292 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRCReturn(rc, rc);
6293 pMixedCtx->SysEnter.cs = u32Val;
6294 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR);
6295 }
6296
6297 uint64_t u64Val = 0;
6298 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR))
6299 {
6300 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, &u64Val); AssertRCReturn(rc, rc);
6301 pMixedCtx->SysEnter.eip = u64Val;
6302 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR);
6303 }
6304 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR))
6305 {
6306 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, &u64Val); AssertRCReturn(rc, rc);
6307 pMixedCtx->SysEnter.esp = u64Val;
6308 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR);
6309 }
6310 return rc;
6311}
6312
6313
6314/**
6315 * Saves the set of guest MSRs (that we restore lazily while leaving VT-x) from
6316 * the CPU back into 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 hmR0VmxSaveGuestLazyMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6327{
6328 /* Since this can be called from our preemption hook it's safer to make the guest-MSRs update non-preemptible. */
6329 VMMRZCallRing3Disable(pVCpu);
6330 HM_DISABLE_PREEMPT();
6331
6332 /* Doing the check here ensures we don't overwrite already-saved guest MSRs from a preemption hook. */
6333 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS))
6334 {
6335 hmR0VmxLazySaveGuestMsrs(pVCpu, pMixedCtx);
6336 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS);
6337 }
6338
6339 HM_RESTORE_PREEMPT();
6340 VMMRZCallRing3Enable(pVCpu);
6341
6342 return VINF_SUCCESS;
6343}
6344
6345
6346/**
6347 * Saves the auto load/store'd guest MSRs from the current VMCS into
6348 * the guest-CPU context.
6349 *
6350 * @returns VBox status code.
6351 * @param pVCpu The cross context virtual CPU structure.
6352 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6353 * out-of-sync. Make sure to update the required fields
6354 * before using them.
6355 *
6356 * @remarks No-long-jump zone!!!
6357 */
6358static int hmR0VmxSaveGuestAutoLoadStoreMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6359{
6360 if (HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS))
6361 return VINF_SUCCESS;
6362
6363 PVMXAUTOMSR pMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
6364 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
6365 Log4(("hmR0VmxSaveGuestAutoLoadStoreMsrs: cMsrs=%u\n", cMsrs));
6366 for (uint32_t i = 0; i < cMsrs; i++, pMsr++)
6367 {
6368 switch (pMsr->u32Msr)
6369 {
6370 case MSR_K8_TSC_AUX: CPUMR0SetGuestTscAux(pVCpu, pMsr->u64Value); break;
6371 case MSR_K8_LSTAR: pMixedCtx->msrLSTAR = pMsr->u64Value; break;
6372 case MSR_K6_STAR: pMixedCtx->msrSTAR = pMsr->u64Value; break;
6373 case MSR_K8_SF_MASK: pMixedCtx->msrSFMASK = pMsr->u64Value; break;
6374 case MSR_K8_KERNEL_GS_BASE: pMixedCtx->msrKERNELGSBASE = pMsr->u64Value; break;
6375 case MSR_K6_EFER: /* Nothing to do here since we intercept writes, see hmR0VmxLoadGuestMsrs(). */
6376 break;
6377
6378 default:
6379 {
6380 AssertMsgFailed(("Unexpected MSR in auto-load/store area. uMsr=%#RX32 cMsrs=%u\n", pMsr->u32Msr, cMsrs));
6381 pVCpu->hm.s.u32HMError = pMsr->u32Msr;
6382 return VERR_HM_UNEXPECTED_LD_ST_MSR;
6383 }
6384 }
6385 }
6386
6387 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS);
6388 return VINF_SUCCESS;
6389}
6390
6391
6392/**
6393 * Saves the guest control registers from the current VMCS into the guest-CPU
6394 * context.
6395 *
6396 * @returns VBox status code.
6397 * @param pVCpu The cross context virtual CPU structure.
6398 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6399 * out-of-sync. Make sure to update the required fields
6400 * before using them.
6401 *
6402 * @remarks No-long-jump zone!!!
6403 */
6404static int hmR0VmxSaveGuestControlRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6405{
6406 /* Guest CR0. Guest FPU. */
6407 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6408 AssertRCReturn(rc, rc);
6409
6410 /* Guest CR4. */
6411 rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
6412 AssertRCReturn(rc, rc);
6413
6414 /* Guest CR2 - updated always during the world-switch or in #PF. */
6415 /* Guest CR3. Only changes with Nested Paging. This must be done -after- saving CR0 and CR4 from the guest! */
6416 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR3))
6417 {
6418 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
6419 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4));
6420
6421 PVM pVM = pVCpu->CTX_SUFF(pVM);
6422 if ( pVM->hm.s.vmx.fUnrestrictedGuest
6423 || ( pVM->hm.s.fNestedPaging
6424 && CPUMIsGuestPagingEnabledEx(pMixedCtx)))
6425 {
6426 uint64_t u64Val = 0;
6427 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_CR3, &u64Val);
6428 if (pMixedCtx->cr3 != u64Val)
6429 {
6430 CPUMSetGuestCR3(pVCpu, u64Val);
6431 if (VMMRZCallRing3IsEnabled(pVCpu))
6432 {
6433 PGMUpdateCR3(pVCpu, u64Val);
6434 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6435 }
6436 else
6437 {
6438 /* Set the force flag to inform PGM about it when necessary. It is cleared by PGMUpdateCR3().*/
6439 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
6440 }
6441 }
6442
6443 /* If the guest is in PAE mode, sync back the PDPE's into the guest state. */
6444 if (CPUMIsGuestInPAEModeEx(pMixedCtx)) /* Reads CR0, CR4 and EFER MSR (EFER is always up-to-date). */
6445 {
6446 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u);
6447 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u);
6448 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u);
6449 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u);
6450 AssertRCReturn(rc, rc);
6451
6452 if (VMMRZCallRing3IsEnabled(pVCpu))
6453 {
6454 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6455 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6456 }
6457 else
6458 {
6459 /* Set the force flag to inform PGM about it when necessary. It is cleared by PGMGstUpdatePaePdpes(). */
6460 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
6461 }
6462 }
6463 }
6464
6465 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR3);
6466 }
6467
6468 /*
6469 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
6470 * -> VMMRZCallRing3Disable() -> hmR0VmxSaveGuestState() -> Set VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
6471 * -> continue with VM-exit handling -> hmR0VmxSaveGuestControlRegs() and here we are.
6472 *
6473 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
6474 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
6475 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
6476 * -NOT- check if HMVMX_UPDATED_GUEST_CR3 is already set or not!
6477 *
6478 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
6479 */
6480 if (VMMRZCallRing3IsEnabled(pVCpu))
6481 {
6482 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
6483 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
6484
6485 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
6486 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6487
6488 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6489 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6490 }
6491
6492 return rc;
6493}
6494
6495
6496/**
6497 * Reads a guest segment register from the current VMCS into the guest-CPU
6498 * context.
6499 *
6500 * @returns VBox status code.
6501 * @param pVCpu The cross context virtual CPU structure.
6502 * @param idxSel Index of the selector in the VMCS.
6503 * @param idxLimit Index of the segment limit in the VMCS.
6504 * @param idxBase Index of the segment base in the VMCS.
6505 * @param idxAccess Index of the access rights of the segment in the VMCS.
6506 * @param pSelReg Pointer to the segment selector.
6507 *
6508 * @remarks No-long-jump zone!!!
6509 * @remarks Never call this function directly!!! Use the VMXLOCAL_READ_SEG()
6510 * macro as that takes care of whether to read from the VMCS cache or
6511 * not.
6512 */
6513DECLINLINE(int) hmR0VmxReadSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase, uint32_t idxAccess,
6514 PCPUMSELREG pSelReg)
6515{
6516 NOREF(pVCpu);
6517
6518 uint32_t u32Val = 0;
6519 int rc = VMXReadVmcs32(idxSel, &u32Val);
6520 AssertRCReturn(rc, rc);
6521 pSelReg->Sel = (uint16_t)u32Val;
6522 pSelReg->ValidSel = (uint16_t)u32Val;
6523 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
6524
6525 rc = VMXReadVmcs32(idxLimit, &u32Val);
6526 AssertRCReturn(rc, rc);
6527 pSelReg->u32Limit = u32Val;
6528
6529 uint64_t u64Val = 0;
6530 rc = VMXReadVmcsGstNByIdxVal(idxBase, &u64Val);
6531 AssertRCReturn(rc, rc);
6532 pSelReg->u64Base = u64Val;
6533
6534 rc = VMXReadVmcs32(idxAccess, &u32Val);
6535 AssertRCReturn(rc, rc);
6536 pSelReg->Attr.u = u32Val;
6537
6538 /*
6539 * If VT-x marks the segment as unusable, most other bits remain undefined:
6540 * - For CS the L, D and G bits have meaning.
6541 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
6542 * - For the remaining data segments no bits are defined.
6543 *
6544 * The present bit and the unusable bit has been observed to be set at the
6545 * same time (the selector was supposed to be invalid as we started executing
6546 * a V8086 interrupt in ring-0).
6547 *
6548 * What should be important for the rest of the VBox code, is that the P bit is
6549 * cleared. Some of the other VBox code recognizes the unusable bit, but
6550 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
6551 * safe side here, we'll strip off P and other bits we don't care about. If
6552 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
6553 *
6554 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
6555 */
6556 if (pSelReg->Attr.u & X86DESCATTR_UNUSABLE)
6557 {
6558 Assert(idxSel != VMX_VMCS16_GUEST_TR_SEL); /* TR is the only selector that can never be unusable. */
6559
6560 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
6561 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
6562 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
6563
6564 Log4(("hmR0VmxReadSegmentReg: Unusable idxSel=%#x attr=%#x -> %#x\n", idxSel, u32Val, pSelReg->Attr.u));
6565#ifdef DEBUG_bird
6566 AssertMsg((u32Val & ~X86DESCATTR_P) == pSelReg->Attr.u,
6567 ("%#x: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
6568 idxSel, u32Val, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
6569#endif
6570 }
6571 return VINF_SUCCESS;
6572}
6573
6574
6575#ifdef VMX_USE_CACHED_VMCS_ACCESSES
6576# define VMXLOCAL_READ_SEG(Sel, CtxSel) \
6577 hmR0VmxReadSegmentReg(pVCpu, VMX_VMCS16_GUEST_##Sel##_SEL, VMX_VMCS32_GUEST_##Sel##_LIMIT, \
6578 VMX_VMCS_GUEST_##Sel##_BASE_CACHE_IDX, VMX_VMCS32_GUEST_##Sel##_ACCESS_RIGHTS, &pMixedCtx->CtxSel)
6579#else
6580# define VMXLOCAL_READ_SEG(Sel, CtxSel) \
6581 hmR0VmxReadSegmentReg(pVCpu, VMX_VMCS16_GUEST_##Sel##_SEL, VMX_VMCS32_GUEST_##Sel##_LIMIT, \
6582 VMX_VMCS_GUEST_##Sel##_BASE, VMX_VMCS32_GUEST_##Sel##_ACCESS_RIGHTS, &pMixedCtx->CtxSel)
6583#endif
6584
6585
6586/**
6587 * Saves the guest segment registers from the current VMCS into the guest-CPU
6588 * context.
6589 *
6590 * @returns VBox status code.
6591 * @param pVCpu The cross context virtual CPU structure.
6592 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6593 * out-of-sync. Make sure to update the required fields
6594 * before using them.
6595 *
6596 * @remarks No-long-jump zone!!!
6597 */
6598static int hmR0VmxSaveGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6599{
6600 /* Guest segment registers. */
6601 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SEGMENT_REGS))
6602 {
6603 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6604 AssertRCReturn(rc, rc);
6605
6606 rc = VMXLOCAL_READ_SEG(CS, cs);
6607 rc |= VMXLOCAL_READ_SEG(SS, ss);
6608 rc |= VMXLOCAL_READ_SEG(DS, ds);
6609 rc |= VMXLOCAL_READ_SEG(ES, es);
6610 rc |= VMXLOCAL_READ_SEG(FS, fs);
6611 rc |= VMXLOCAL_READ_SEG(GS, gs);
6612 AssertRCReturn(rc, rc);
6613
6614 /* Restore segment attributes for real-on-v86 mode hack. */
6615 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
6616 {
6617 pMixedCtx->cs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrCS.u;
6618 pMixedCtx->ss.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrSS.u;
6619 pMixedCtx->ds.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrDS.u;
6620 pMixedCtx->es.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrES.u;
6621 pMixedCtx->fs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrFS.u;
6622 pMixedCtx->gs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrGS.u;
6623 }
6624 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SEGMENT_REGS);
6625 }
6626
6627 return VINF_SUCCESS;
6628}
6629
6630
6631/**
6632 * Saves the guest descriptor table registers and task register from the current
6633 * VMCS into the guest-CPU context.
6634 *
6635 * @returns VBox status code.
6636 * @param pVCpu The cross context virtual CPU structure.
6637 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6638 * out-of-sync. Make sure to update the required fields
6639 * before using them.
6640 *
6641 * @remarks No-long-jump zone!!!
6642 */
6643static int hmR0VmxSaveGuestTableRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6644{
6645 int rc = VINF_SUCCESS;
6646
6647 /* Guest LDTR. */
6648 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LDTR))
6649 {
6650 rc = VMXLOCAL_READ_SEG(LDTR, ldtr);
6651 AssertRCReturn(rc, rc);
6652 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LDTR);
6653 }
6654
6655 /* Guest GDTR. */
6656 uint64_t u64Val = 0;
6657 uint32_t u32Val = 0;
6658 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_GDTR))
6659 {
6660 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
6661 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRCReturn(rc, rc);
6662 pMixedCtx->gdtr.pGdt = u64Val;
6663 pMixedCtx->gdtr.cbGdt = u32Val;
6664 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_GDTR);
6665 }
6666
6667 /* Guest IDTR. */
6668 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_IDTR))
6669 {
6670 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
6671 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRCReturn(rc, rc);
6672 pMixedCtx->idtr.pIdt = u64Val;
6673 pMixedCtx->idtr.cbIdt = u32Val;
6674 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_IDTR);
6675 }
6676
6677 /* Guest TR. */
6678 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_TR))
6679 {
6680 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6681 AssertRCReturn(rc, rc);
6682
6683 /* For real-mode emulation using virtual-8086 mode we have the fake TSS (pRealModeTSS) in TR, don't save the fake one. */
6684 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
6685 {
6686 rc = VMXLOCAL_READ_SEG(TR, tr);
6687 AssertRCReturn(rc, rc);
6688 }
6689 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_TR);
6690 }
6691 return rc;
6692}
6693
6694#undef VMXLOCAL_READ_SEG
6695
6696
6697/**
6698 * Saves the guest debug-register DR7 from the current VMCS into the guest-CPU
6699 * context.
6700 *
6701 * @returns VBox status code.
6702 * @param pVCpu The cross context virtual CPU structure.
6703 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6704 * out-of-sync. Make sure to update the required fields
6705 * before using them.
6706 *
6707 * @remarks No-long-jump zone!!!
6708 */
6709static int hmR0VmxSaveGuestDR7(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6710{
6711 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_DEBUG))
6712 {
6713 if (!pVCpu->hm.s.fUsingHyperDR7)
6714 {
6715 /* Upper 32-bits are always zero. See Intel spec. 2.7.3 "Loading and Storing Debug Registers". */
6716 uint32_t u32Val;
6717 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_DR7, &u32Val); AssertRCReturn(rc, rc);
6718 pMixedCtx->dr[7] = u32Val;
6719 }
6720
6721 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_DEBUG);
6722 }
6723 return VINF_SUCCESS;
6724}
6725
6726
6727/**
6728 * Saves the guest APIC state from the current VMCS into the guest-CPU context.
6729 *
6730 * @returns VBox status code.
6731 * @param pVCpu The cross context virtual CPU structure.
6732 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6733 * out-of-sync. Make sure to update the required fields
6734 * before using them.
6735 *
6736 * @remarks No-long-jump zone!!!
6737 */
6738static int hmR0VmxSaveGuestApicState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6739{
6740 NOREF(pMixedCtx);
6741
6742 /* Updating TPR is already done in hmR0VmxPostRunGuest(). Just update the flag. */
6743 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_APIC_STATE);
6744 return VINF_SUCCESS;
6745}
6746
6747
6748/**
6749 * Saves the entire guest state from the currently active VMCS into the
6750 * guest-CPU context.
6751 *
6752 * This essentially VMREADs all guest-data.
6753 *
6754 * @returns VBox status code.
6755 * @param pVCpu The cross context virtual CPU structure.
6756 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6757 * out-of-sync. Make sure to update the required fields
6758 * before using them.
6759 */
6760static int hmR0VmxSaveGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6761{
6762 Assert(pVCpu);
6763 Assert(pMixedCtx);
6764
6765 if (HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL)
6766 return VINF_SUCCESS;
6767
6768 /* Though we can longjmp to ring-3 due to log-flushes here and get recalled
6769 again on the ring-3 callback path, there is no real need to. */
6770 if (VMMRZCallRing3IsEnabled(pVCpu))
6771 VMMR0LogFlushDisable(pVCpu);
6772 else
6773 Assert(VMMR0IsLogFlushDisabled(pVCpu));
6774 Log4Func(("vcpu[%RU32]\n", pVCpu->idCpu));
6775
6776 int rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
6777 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestRipRspRflags failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6778
6779 rc = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
6780 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestControlRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6781
6782 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
6783 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSegmentRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6784
6785 rc = hmR0VmxSaveGuestTableRegs(pVCpu, pMixedCtx);
6786 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestTableRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6787
6788 rc = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
6789 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestDR7 failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6790
6791 rc = hmR0VmxSaveGuestSysenterMsrs(pVCpu, pMixedCtx);
6792 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSysenterMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6793
6794 rc = hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
6795 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestLazyMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6796
6797 rc = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
6798 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestAutoLoadStoreMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6799
6800 rc = hmR0VmxSaveGuestActivityState(pVCpu, pMixedCtx);
6801 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestActivityState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6802
6803 rc = hmR0VmxSaveGuestApicState(pVCpu, pMixedCtx);
6804 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestApicState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6805
6806 AssertMsg(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL,
6807 ("Missed guest state bits while saving state; missing %RX32 (got %RX32, want %RX32) - check log for any previous errors!\n",
6808 HMVMX_UPDATED_GUEST_ALL ^ HMVMXCPU_GST_VALUE(pVCpu), HMVMXCPU_GST_VALUE(pVCpu), HMVMX_UPDATED_GUEST_ALL));
6809
6810 if (VMMRZCallRing3IsEnabled(pVCpu))
6811 VMMR0LogFlushEnable(pVCpu);
6812
6813 return VINF_SUCCESS;
6814}
6815
6816
6817/**
6818 * Saves basic guest registers needed for IEM instruction execution.
6819 *
6820 * @returns VBox status code (OR-able).
6821 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
6822 * @param pMixedCtx Pointer to the CPU context of the guest.
6823 * @param fMemory Whether the instruction being executed operates on
6824 * memory or not. Only CR0 is synced up if clear.
6825 * @param fNeedRsp Need RSP (any instruction working on GPRs or stack).
6826 */
6827static int hmR0VmxSaveGuestRegsForIemExec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fMemory, bool fNeedRsp)
6828{
6829 /*
6830 * We assume all general purpose registers other than RSP are available.
6831 *
6832 * RIP is a must, as it will be incremented or otherwise changed.
6833 *
6834 * RFLAGS are always required to figure the CPL.
6835 *
6836 * RSP isn't always required, however it's a GPR, so frequently required.
6837 *
6838 * SS and CS are the only segment register needed if IEM doesn't do memory
6839 * access (CPL + 16/32/64-bit mode), but we can only get all segment registers.
6840 *
6841 * CR0 is always required by IEM for the CPL, while CR3 and CR4 will only
6842 * be required for memory accesses.
6843 *
6844 * Note! Before IEM dispatches an exception, it will call us to sync in everything.
6845 */
6846 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6847 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
6848 if (fNeedRsp)
6849 rc |= hmR0VmxSaveGuestRsp(pVCpu, pMixedCtx);
6850 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
6851 if (!fMemory)
6852 rc |= hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6853 else
6854 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
6855 AssertRCReturn(rc, rc);
6856 return rc;
6857}
6858
6859
6860/**
6861 * Ensures that we've got a complete basic guest-context.
6862 *
6863 * This excludes the FPU, SSE, AVX, and similar extended state. The interface
6864 * is for the interpreter.
6865 *
6866 * @returns VBox status code.
6867 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
6868 * @param pMixedCtx Pointer to the guest-CPU context which may have data
6869 * needing to be synced in.
6870 * @thread EMT(pVCpu)
6871 */
6872VMMR0_INT_DECL(int) HMR0EnsureCompleteBasicContext(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6873{
6874 /* Note! Since this is only applicable to VT-x, the implementation is placed
6875 in the VT-x part of the sources instead of the generic stuff. */
6876 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported)
6877 {
6878 /* For now, imply that the caller might change everything too. */
6879 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
6880 return hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
6881 }
6882 return VINF_SUCCESS;
6883}
6884
6885
6886/**
6887 * Check per-VM and per-VCPU force flag actions that require us to go back to
6888 * ring-3 for one reason or another.
6889 *
6890 * @returns Strict VBox status code (i.e. informational status codes too)
6891 * @retval VINF_SUCCESS if we don't have any actions that require going back to
6892 * ring-3.
6893 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
6894 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
6895 * interrupts)
6896 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
6897 * all EMTs to be in ring-3.
6898 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
6899 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
6900 * to the EM loop.
6901 *
6902 * @param pVM The cross context VM structure.
6903 * @param pVCpu The cross context virtual CPU structure.
6904 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6905 * out-of-sync. Make sure to update the required fields
6906 * before using them.
6907 * @param fStepping Running in hmR0VmxRunGuestCodeStep().
6908 */
6909static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fStepping)
6910{
6911 Assert(VMMRZCallRing3IsEnabled(pVCpu));
6912
6913 /*
6914 * Anything pending? Should be more likely than not if we're doing a good job.
6915 */
6916 if ( !fStepping
6917 ? !VM_FF_IS_PENDING(pVM, VM_FF_HP_R0_PRE_HM_MASK)
6918 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
6919 : !VM_FF_IS_PENDING(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
6920 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
6921 return VINF_SUCCESS;
6922
6923 /* We need the control registers now, make sure the guest-CPU context is updated. */
6924 int rc3 = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
6925 AssertRCReturn(rc3, rc3);
6926
6927 /* Pending HM CR3 sync. */
6928 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
6929 {
6930 int rc2 = PGMUpdateCR3(pVCpu, pMixedCtx->cr3);
6931 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
6932 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
6933 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6934 }
6935
6936 /* Pending HM PAE PDPEs. */
6937 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
6938 {
6939 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6940 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6941 }
6942
6943 /* Pending PGM C3 sync. */
6944 if (VMCPU_FF_IS_PENDING(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
6945 {
6946 VBOXSTRICTRC rcStrict2 = PGMSyncCR3(pVCpu, pMixedCtx->cr0, pMixedCtx->cr3, pMixedCtx->cr4,
6947 VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
6948 if (rcStrict2 != VINF_SUCCESS)
6949 {
6950 AssertRC(VBOXSTRICTRC_VAL(rcStrict2));
6951 Log4(("hmR0VmxCheckForceFlags: PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict2)));
6952 return rcStrict2;
6953 }
6954 }
6955
6956 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
6957 if ( VM_FF_IS_PENDING(pVM, VM_FF_HM_TO_R3_MASK)
6958 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
6959 {
6960 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
6961 int rc2 = RT_UNLIKELY(VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_NO_MEMORY : VINF_EM_RAW_TO_R3;
6962 Log4(("hmR0VmxCheckForceFlags: HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc2));
6963 return rc2;
6964 }
6965
6966 /* Pending VM request packets, such as hardware interrupts. */
6967 if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST)
6968 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
6969 {
6970 Log4(("hmR0VmxCheckForceFlags: Pending VM request forcing us back to ring-3\n"));
6971 return VINF_EM_PENDING_REQUEST;
6972 }
6973
6974 /* Pending PGM pool flushes. */
6975 if (VM_FF_IS_PENDING(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
6976 {
6977 Log4(("hmR0VmxCheckForceFlags: PGM pool flush pending forcing us back to ring-3\n"));
6978 return VINF_PGM_POOL_FLUSH_PENDING;
6979 }
6980
6981 /* Pending DMA requests. */
6982 if (VM_FF_IS_PENDING(pVM, VM_FF_PDM_DMA))
6983 {
6984 Log4(("hmR0VmxCheckForceFlags: Pending DMA request forcing us back to ring-3\n"));
6985 return VINF_EM_RAW_TO_R3;
6986 }
6987
6988 return VINF_SUCCESS;
6989}
6990
6991
6992/**
6993 * Converts any TRPM trap into a pending HM event. This is typically used when
6994 * entering from ring-3 (not longjmp returns).
6995 *
6996 * @param pVCpu The cross context virtual CPU structure.
6997 */
6998static void hmR0VmxTrpmTrapToPendingEvent(PVMCPU pVCpu)
6999{
7000 Assert(TRPMHasTrap(pVCpu));
7001 Assert(!pVCpu->hm.s.Event.fPending);
7002
7003 uint8_t uVector;
7004 TRPMEVENT enmTrpmEvent;
7005 RTGCUINT uErrCode;
7006 RTGCUINTPTR GCPtrFaultAddress;
7007 uint8_t cbInstr;
7008
7009 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
7010 AssertRC(rc);
7011
7012 /* Refer Intel spec. 24.8.3 "VM-entry Controls for Event Injection" for the format of u32IntInfo. */
7013 uint32_t u32IntInfo = uVector | VMX_EXIT_INTERRUPTION_INFO_VALID;
7014 if (enmTrpmEvent == TRPM_TRAP)
7015 {
7016 switch (uVector)
7017 {
7018 case X86_XCPT_NMI:
7019 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7020 break;
7021
7022 case X86_XCPT_BP:
7023 case X86_XCPT_OF:
7024 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7025 break;
7026
7027 case X86_XCPT_PF:
7028 case X86_XCPT_DF:
7029 case X86_XCPT_TS:
7030 case X86_XCPT_NP:
7031 case X86_XCPT_SS:
7032 case X86_XCPT_GP:
7033 case X86_XCPT_AC:
7034 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7035 /* no break! */
7036 default:
7037 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7038 break;
7039 }
7040 }
7041 else if (enmTrpmEvent == TRPM_HARDWARE_INT)
7042 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7043 else if (enmTrpmEvent == TRPM_SOFTWARE_INT)
7044 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7045 else
7046 AssertMsgFailed(("Invalid TRPM event type %d\n", enmTrpmEvent));
7047
7048 rc = TRPMResetTrap(pVCpu);
7049 AssertRC(rc);
7050 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
7051 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
7052
7053 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
7054}
7055
7056
7057/**
7058 * Converts the pending HM event into a TRPM trap.
7059 *
7060 * @param pVCpu The cross context virtual CPU structure.
7061 */
7062static void hmR0VmxPendingEventToTrpmTrap(PVMCPU pVCpu)
7063{
7064 Assert(pVCpu->hm.s.Event.fPending);
7065
7066 uint32_t uVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
7067 uint32_t uVector = VMX_IDT_VECTORING_INFO_VECTOR(pVCpu->hm.s.Event.u64IntInfo);
7068 bool fErrorCodeValid = VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVCpu->hm.s.Event.u64IntInfo);
7069 uint32_t uErrorCode = pVCpu->hm.s.Event.u32ErrCode;
7070
7071 /* If a trap was already pending, we did something wrong! */
7072 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
7073
7074 TRPMEVENT enmTrapType;
7075 switch (uVectorType)
7076 {
7077 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
7078 enmTrapType = TRPM_HARDWARE_INT;
7079 break;
7080
7081 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
7082 enmTrapType = TRPM_SOFTWARE_INT;
7083 break;
7084
7085 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
7086 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
7087 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT: /* #BP and #OF */
7088 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
7089 enmTrapType = TRPM_TRAP;
7090 break;
7091
7092 default:
7093 AssertMsgFailed(("Invalid trap type %#x\n", uVectorType));
7094 enmTrapType = TRPM_32BIT_HACK;
7095 break;
7096 }
7097
7098 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
7099
7100 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
7101 AssertRC(rc);
7102
7103 if (fErrorCodeValid)
7104 TRPMSetErrorCode(pVCpu, uErrorCode);
7105
7106 if ( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
7107 && uVector == X86_XCPT_PF)
7108 {
7109 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
7110 }
7111 else if ( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
7112 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
7113 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
7114 {
7115 AssertMsg( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
7116 || (uVector == X86_XCPT_BP || uVector == X86_XCPT_OF),
7117 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
7118 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
7119 }
7120
7121 /* Clear any pending events from the VMCS. */
7122 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
7123 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, 0); AssertRC(rc);
7124
7125 /* We're now done converting the pending event. */
7126 pVCpu->hm.s.Event.fPending = false;
7127}
7128
7129
7130/**
7131 * Does the necessary state syncing before returning to ring-3 for any reason
7132 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
7133 *
7134 * @returns VBox status code.
7135 * @param pVCpu The cross context virtual CPU structure.
7136 * @param pMixedCtx Pointer to the guest-CPU context. The data may
7137 * be out-of-sync. Make sure to update the required
7138 * fields before using them.
7139 * @param fSaveGuestState Whether to save the guest state or not.
7140 *
7141 * @remarks No-long-jmp zone!!!
7142 */
7143static int hmR0VmxLeave(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fSaveGuestState)
7144{
7145 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7146 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7147
7148 RTCPUID idCpu = RTMpCpuId();
7149 Log4Func(("HostCpuId=%u\n", idCpu));
7150
7151 /*
7152 * !!! IMPORTANT !!!
7153 * If you modify code here, check whether hmR0VmxCallRing3Callback() needs to be updated too.
7154 */
7155
7156 /* Save the guest state if necessary. */
7157 if ( fSaveGuestState
7158 && HMVMXCPU_GST_VALUE(pVCpu) != HMVMX_UPDATED_GUEST_ALL)
7159 {
7160 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
7161 AssertRCReturn(rc, rc);
7162 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
7163 }
7164
7165 /* Restore host FPU state if necessary and resync on next R0 reentry .*/
7166 if (CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu))
7167 {
7168 if (fSaveGuestState)
7169 {
7170 /* We shouldn't reload CR0 without saving it first. */
7171 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7172 AssertRCReturn(rc, rc);
7173 }
7174 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
7175 }
7176
7177 /* Restore host debug registers if necessary and resync on next R0 reentry. */
7178#ifdef VBOX_STRICT
7179 if (CPUMIsHyperDebugStateActive(pVCpu))
7180 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT);
7181#endif
7182 if (CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */))
7183 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
7184 Assert(!CPUMIsGuestDebugStateActive(pVCpu) && !CPUMIsGuestDebugStateActivePending(pVCpu));
7185 Assert(!CPUMIsHyperDebugStateActive(pVCpu) && !CPUMIsHyperDebugStateActivePending(pVCpu));
7186
7187#if HC_ARCH_BITS == 64
7188 /* Restore host-state bits that VT-x only restores partially. */
7189 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7190 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7191 {
7192 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
7193 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7194 }
7195 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7196#endif
7197
7198 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7199 if (pVCpu->hm.s.vmx.fLazyMsrs)
7200 {
7201 /* We shouldn't reload the guest MSRs without saving it first. */
7202 if (!fSaveGuestState)
7203 {
7204 int rc = hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
7205 AssertRCReturn(rc, rc);
7206 }
7207 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS));
7208 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7209 Assert(!pVCpu->hm.s.vmx.fLazyMsrs);
7210 }
7211
7212 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7213 pVCpu->hm.s.vmx.fUpdatedHostMsrs = false;
7214
7215 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
7216 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatLoadGuestState);
7217 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExit1);
7218 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExit2);
7219 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
7220 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
7221 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
7222 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7223
7224 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7225
7226 /** @todo This partially defeats the purpose of having preemption hooks.
7227 * The problem is, deregistering the hooks should be moved to a place that
7228 * lasts until the EMT is about to be destroyed not everytime while leaving HM
7229 * context.
7230 */
7231 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_ACTIVE)
7232 {
7233 int rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
7234 AssertRCReturn(rc, rc);
7235
7236 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
7237 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
7238 }
7239 Assert(!(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_LAUNCHED));
7240 NOREF(idCpu);
7241
7242 return VINF_SUCCESS;
7243}
7244
7245
7246/**
7247 * Leaves the VT-x session.
7248 *
7249 * @returns VBox status code.
7250 * @param pVCpu The cross context virtual CPU structure.
7251 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7252 * out-of-sync. Make sure to update the required fields
7253 * before using them.
7254 *
7255 * @remarks No-long-jmp zone!!!
7256 */
7257DECLINLINE(int) hmR0VmxLeaveSession(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7258{
7259 HM_DISABLE_PREEMPT();
7260 HMVMX_ASSERT_CPU_SAFE();
7261 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7262 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7263
7264 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
7265 and done this from the VMXR0ThreadCtxCallback(). */
7266 if (!pVCpu->hm.s.fLeaveDone)
7267 {
7268 int rc2 = hmR0VmxLeave(pVCpu, pMixedCtx, true /* fSaveGuestState */);
7269 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
7270 pVCpu->hm.s.fLeaveDone = true;
7271 }
7272 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
7273
7274 /*
7275 * !!! IMPORTANT !!!
7276 * If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
7277 */
7278
7279 /* Deregister hook now that we've left HM context before re-enabling preemption. */
7280 /** @todo Deregistering here means we need to VMCLEAR always
7281 * (longjmp/exit-to-r3) in VT-x which is not efficient. */
7282 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
7283 VMMR0ThreadCtxHookDisable(pVCpu);
7284
7285 /* Leave HM context. This takes care of local init (term). */
7286 int rc = HMR0LeaveCpu(pVCpu);
7287
7288 HM_RESTORE_PREEMPT();
7289 return rc;
7290}
7291
7292
7293/**
7294 * Does the necessary state syncing before doing a longjmp to ring-3.
7295 *
7296 * @returns VBox status code.
7297 * @param pVCpu The cross context virtual CPU structure.
7298 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7299 * out-of-sync. Make sure to update the required fields
7300 * before using them.
7301 *
7302 * @remarks No-long-jmp zone!!!
7303 */
7304DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7305{
7306 return hmR0VmxLeaveSession(pVCpu, pMixedCtx);
7307}
7308
7309
7310/**
7311 * Take necessary actions before going back to ring-3.
7312 *
7313 * An action requires us to go back to ring-3. This function does the necessary
7314 * steps before we can safely return to ring-3. This is not the same as longjmps
7315 * to ring-3, this is voluntary and prepares the guest so it may continue
7316 * executing outside HM (recompiler/IEM).
7317 *
7318 * @returns VBox status code.
7319 * @param pVM The cross context VM structure.
7320 * @param pVCpu The cross context virtual CPU structure.
7321 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7322 * out-of-sync. Make sure to update the required fields
7323 * before using them.
7324 * @param rcExit The reason for exiting to ring-3. Can be
7325 * VINF_VMM_UNKNOWN_RING3_CALL.
7326 */
7327static int hmR0VmxExitToRing3(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, VBOXSTRICTRC rcExit)
7328{
7329 Assert(pVM);
7330 Assert(pVCpu);
7331 Assert(pMixedCtx);
7332 HMVMX_ASSERT_PREEMPT_SAFE();
7333
7334 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
7335 {
7336 VMXGetActivatedVmcs(&pVCpu->hm.s.vmx.LastError.u64VMCSPhys);
7337 pVCpu->hm.s.vmx.LastError.u32VMCSRevision = *(uint32_t *)pVCpu->hm.s.vmx.pvVmcs;
7338 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
7339 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
7340 }
7341
7342 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
7343 VMMRZCallRing3Disable(pVCpu);
7344 Log4(("hmR0VmxExitToRing3: pVCpu=%p idCpu=%RU32 rcExit=%d\n", pVCpu, pVCpu->idCpu, VBOXSTRICTRC_VAL(rcExit)));
7345
7346 /* We need to do this only while truly exiting the "inner loop" back to ring-3 and -not- for any longjmp to ring3. */
7347 if (pVCpu->hm.s.Event.fPending)
7348 {
7349 hmR0VmxPendingEventToTrpmTrap(pVCpu);
7350 Assert(!pVCpu->hm.s.Event.fPending);
7351 }
7352
7353 /* Clear interrupt-window and NMI-window controls as we re-evaluate it when we return from ring-3. */
7354 hmR0VmxClearIntNmiWindowsVmcs(pVCpu);
7355
7356 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
7357 and if we're injecting an event we should have a TRPM trap pending. */
7358 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
7359#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a tripple fault in progress. */
7360 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
7361#endif
7362
7363 /* Save guest state and restore host state bits. */
7364 int rc = hmR0VmxLeaveSession(pVCpu, pMixedCtx);
7365 AssertRCReturn(rc, rc);
7366 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7367 /* Thread-context hooks are unregistered at this point!!! */
7368
7369 /* Sync recompiler state. */
7370 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
7371 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
7372 | CPUM_CHANGED_LDTR
7373 | CPUM_CHANGED_GDTR
7374 | CPUM_CHANGED_IDTR
7375 | CPUM_CHANGED_TR
7376 | CPUM_CHANGED_HIDDEN_SEL_REGS);
7377 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
7378 if ( pVM->hm.s.fNestedPaging
7379 && CPUMIsGuestPagingEnabledEx(pMixedCtx))
7380 {
7381 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
7382 }
7383
7384 Assert(!pVCpu->hm.s.fClearTrapFlag);
7385
7386 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
7387 if (rcExit != VINF_EM_RAW_INTERRUPT)
7388 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
7389
7390 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
7391
7392 /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
7393 VMMRZCallRing3RemoveNotification(pVCpu);
7394 VMMRZCallRing3Enable(pVCpu);
7395
7396 return rc;
7397}
7398
7399
7400/**
7401 * VMMRZCallRing3() callback wrapper which saves the guest state before we
7402 * longjump to ring-3 and possibly get preempted.
7403 *
7404 * @returns VBox status code.
7405 * @param pVCpu The cross context virtual CPU structure.
7406 * @param enmOperation The operation causing the ring-3 longjump.
7407 * @param pvUser Opaque pointer to the guest-CPU context. The data
7408 * may be out-of-sync. Make sure to update the required
7409 * fields before using them.
7410 */
7411static DECLCALLBACK(int) hmR0VmxCallRing3Callback(PVMCPU pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
7412{
7413 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
7414 {
7415 /*
7416 * !!! IMPORTANT !!!
7417 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
7418 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
7419 */
7420 VMMRZCallRing3RemoveNotification(pVCpu);
7421 VMMRZCallRing3Disable(pVCpu);
7422 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
7423 RTThreadPreemptDisable(&PreemptState);
7424
7425 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
7426 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
7427
7428#if HC_ARCH_BITS == 64
7429 /* Restore host-state bits that VT-x only restores partially. */
7430 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7431 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7432 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7433 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7434#endif
7435 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7436 if (pVCpu->hm.s.vmx.fLazyMsrs)
7437 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7438
7439 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7440 pVCpu->hm.s.vmx.fUpdatedHostMsrs = false;
7441 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7442 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_ACTIVE)
7443 {
7444 VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
7445 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
7446 }
7447
7448 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
7449 VMMR0ThreadCtxHookDisable(pVCpu);
7450 HMR0LeaveCpu(pVCpu);
7451 RTThreadPreemptRestore(&PreemptState);
7452 return VINF_SUCCESS;
7453 }
7454
7455 Assert(pVCpu);
7456 Assert(pvUser);
7457 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7458 HMVMX_ASSERT_PREEMPT_SAFE();
7459
7460 VMMRZCallRing3Disable(pVCpu);
7461 Assert(VMMR0IsLogFlushDisabled(pVCpu));
7462
7463 Log4(("hmR0VmxCallRing3Callback->hmR0VmxLongJmpToRing3 pVCpu=%p idCpu=%RU32 enmOperation=%d\n", pVCpu, pVCpu->idCpu,
7464 enmOperation));
7465
7466 int rc = hmR0VmxLongJmpToRing3(pVCpu, (PCPUMCTX)pvUser);
7467 AssertRCReturn(rc, rc);
7468
7469 VMMRZCallRing3Enable(pVCpu);
7470 return VINF_SUCCESS;
7471}
7472
7473
7474/**
7475 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
7476 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
7477 *
7478 * @param pVCpu The cross context virtual CPU structure.
7479 */
7480DECLINLINE(void) hmR0VmxSetIntWindowExitVmcs(PVMCPU pVCpu)
7481{
7482 if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
7483 {
7484 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
7485 {
7486 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT;
7487 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7488 AssertRC(rc);
7489 Log4(("Setup interrupt-window exiting\n"));
7490 }
7491 } /* else we will deliver interrupts whenever the guest exits next and is in a state to receive events. */
7492}
7493
7494
7495/**
7496 * Clears the interrupt-window exiting control in the VMCS.
7497 *
7498 * @param pVCpu The cross context virtual CPU structure.
7499 */
7500DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMCPU pVCpu)
7501{
7502 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT);
7503 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT;
7504 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7505 AssertRC(rc);
7506 Log4(("Cleared interrupt-window exiting\n"));
7507}
7508
7509
7510/**
7511 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
7512 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
7513 *
7514 * @param pVCpu The cross context virtual CPU structure.
7515 */
7516DECLINLINE(void) hmR0VmxSetNmiWindowExitVmcs(PVMCPU pVCpu)
7517{
7518 if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT))
7519 {
7520 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT))
7521 {
7522 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT;
7523 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7524 AssertRC(rc);
7525 Log4(("Setup NMI-window exiting\n"));
7526 }
7527 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
7528}
7529
7530
7531/**
7532 * Clears the NMI-window exiting control in the VMCS.
7533 *
7534 * @param pVCpu The cross context virtual CPU structure.
7535 */
7536DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMCPU pVCpu)
7537{
7538 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT);
7539 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT;
7540 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7541 AssertRC(rc);
7542 Log4(("Cleared NMI-window exiting\n"));
7543}
7544
7545
7546/**
7547 * Evaluates the event to be delivered to the guest and sets it as the pending
7548 * event.
7549 *
7550 * @returns The VT-x guest-interruptibility state.
7551 * @param pVCpu The cross context virtual CPU structure.
7552 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7553 * out-of-sync. Make sure to update the required fields
7554 * before using them.
7555 */
7556static uint32_t hmR0VmxEvaluatePendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7557{
7558 /* Get the current interruptibility-state of the guest and then figure out what can be injected. */
7559 uint32_t const uIntrState = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx);
7560 bool const fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7561 bool const fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7562 bool const fBlockNmi = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI);
7563
7564 Assert(!fBlockSti || HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS));
7565 Assert(!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
7566 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
7567 Assert(!TRPMHasTrap(pVCpu));
7568
7569 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
7570 APICUpdatePendingInterrupts(pVCpu);
7571
7572 /*
7573 * Toggling of interrupt force-flags here is safe since we update TRPM on premature exits
7574 * to ring-3 before executing guest code, see hmR0VmxExitToRing3(). We must NOT restore these force-flags.
7575 */
7576 /** @todo SMI. SMIs take priority over NMIs. */
7577 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NMI)) /* NMI. NMIs take priority over regular interrupts. */
7578 {
7579 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
7580 if ( !pVCpu->hm.s.Event.fPending
7581 && !fBlockNmi
7582 && !fBlockSti
7583 && !fBlockMovSS)
7584 {
7585 Log4(("Pending NMI vcpu[%RU32]\n", pVCpu->idCpu));
7586 uint32_t u32IntInfo = X86_XCPT_NMI | VMX_EXIT_INTERRUPTION_INFO_VALID;
7587 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7588
7589 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7590 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
7591 }
7592 else
7593 hmR0VmxSetNmiWindowExitVmcs(pVCpu);
7594 }
7595 /*
7596 * Check if the guest can receive external interrupts (PIC/APIC). Once PDMGetInterrupt() returns
7597 * a valid interrupt we must- deliver the interrupt. We can no longer re-request it from the APIC.
7598 */
7599 else if ( VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
7600 && !pVCpu->hm.s.fSingleInstruction)
7601 {
7602 Assert(!DBGFIsStepping(pVCpu));
7603 int rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7604 AssertRC(rc);
7605 bool const fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
7606 if ( !pVCpu->hm.s.Event.fPending
7607 && !fBlockInt
7608 && !fBlockSti
7609 && !fBlockMovSS)
7610 {
7611 uint8_t u8Interrupt;
7612 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
7613 if (RT_SUCCESS(rc))
7614 {
7615 Log4(("Pending interrupt vcpu[%RU32] u8Interrupt=%#x \n", pVCpu->idCpu, u8Interrupt));
7616 uint32_t u32IntInfo = u8Interrupt | VMX_EXIT_INTERRUPTION_INFO_VALID;
7617 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7618
7619 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrfaultAddress */);
7620 }
7621 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
7622 {
7623 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
7624 hmR0VmxApicSetTprThreshold(pVCpu, u8Interrupt >> 4);
7625 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
7626
7627 /*
7628 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
7629 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
7630 * need to re-set this force-flag here.
7631 */
7632 }
7633 else
7634 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
7635 }
7636 else
7637 hmR0VmxSetIntWindowExitVmcs(pVCpu);
7638 }
7639
7640 return uIntrState;
7641}
7642
7643
7644/**
7645 * Sets a pending-debug exception to be delivered to the guest if the guest is
7646 * single-stepping in the VMCS.
7647 *
7648 * @param pVCpu The cross context virtual CPU structure.
7649 */
7650DECLINLINE(void) hmR0VmxSetPendingDebugXcptVmcs(PVMCPU pVCpu)
7651{
7652 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS)); NOREF(pVCpu);
7653 int rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_BS);
7654 AssertRC(rc);
7655}
7656
7657
7658/**
7659 * Injects any pending events into the guest if the guest is in a state to
7660 * receive them.
7661 *
7662 * @returns Strict VBox status code (i.e. informational status codes too).
7663 * @param pVCpu The cross context virtual CPU structure.
7664 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7665 * out-of-sync. Make sure to update the required fields
7666 * before using them.
7667 * @param uIntrState The VT-x guest-interruptibility state.
7668 * @param fStepping Running in hmR0VmxRunGuestCodeStep() and we should
7669 * return VINF_EM_DBG_STEPPED if the event was
7670 * dispatched directly.
7671 */
7672static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t uIntrState, bool fStepping)
7673{
7674 HMVMX_ASSERT_PREEMPT_SAFE();
7675 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7676
7677 bool fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7678 bool fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7679
7680 Assert(!fBlockSti || HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS));
7681 Assert(!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
7682 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
7683 Assert(!TRPMHasTrap(pVCpu));
7684
7685 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
7686 if (pVCpu->hm.s.Event.fPending)
7687 {
7688 /*
7689 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
7690 * pending even while injecting an event and in this case, we want a VM-exit as soon as
7691 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
7692 *
7693 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
7694 */
7695 uint32_t const uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
7696#ifdef VBOX_STRICT
7697 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
7698 {
7699 bool const fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
7700 Assert(!fBlockInt);
7701 Assert(!fBlockSti);
7702 Assert(!fBlockMovSS);
7703 }
7704 else if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
7705 {
7706 bool const fBlockNmi = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI);
7707 Assert(!fBlockSti);
7708 Assert(!fBlockMovSS);
7709 Assert(!fBlockNmi);
7710 }
7711#endif
7712 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#x\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
7713 (uint8_t)uIntType));
7714 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, pVCpu->hm.s.Event.u64IntInfo, pVCpu->hm.s.Event.cbInstr,
7715 pVCpu->hm.s.Event.u32ErrCode, pVCpu->hm.s.Event.GCPtrFaultAddress,
7716 fStepping, &uIntrState);
7717 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
7718
7719 /* Update the interruptibility-state as it could have been changed by
7720 hmR0VmxInjectEventVmcs() (e.g. real-on-v86 guest injecting software interrupts) */
7721 fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7722 fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7723
7724 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
7725 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
7726 else
7727 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
7728 }
7729
7730 /* Deliver pending debug exception if the guest is single-stepping. Evaluate and set the BS bit. */
7731 if ( fBlockSti
7732 || fBlockMovSS)
7733 {
7734 if (!pVCpu->hm.s.fSingleInstruction)
7735 {
7736 /*
7737 * The pending-debug exceptions field is cleared on all VM-exits except VMX_EXIT_TPR_BELOW_THRESHOLD,
7738 * VMX_EXIT_MTF, VMX_EXIT_APIC_WRITE and VMX_EXIT_VIRTUALIZED_EOI.
7739 * See Intel spec. 27.3.4 "Saving Non-Register State".
7740 */
7741 Assert(!DBGFIsStepping(pVCpu));
7742 int rc2 = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7743 AssertRCReturn(rc2, rc2);
7744 if (pMixedCtx->eflags.Bits.u1TF)
7745 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
7746 }
7747 else if (pMixedCtx->eflags.Bits.u1TF)
7748 {
7749 /*
7750 * We are single-stepping in the hypervisor debugger using EFLAGS.TF. Clear interrupt inhibition as setting the
7751 * BS bit would mean delivering a #DB to the guest upon VM-entry when it shouldn't be.
7752 */
7753 Assert(!(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG));
7754 uIntrState = 0;
7755 }
7756 }
7757
7758 /*
7759 * There's no need to clear the VM-entry interruption-information field here if we're not injecting anything.
7760 * VT-x clears the valid bit on every VM-exit. See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
7761 */
7762 int rc2 = hmR0VmxLoadGuestIntrState(pVCpu, uIntrState);
7763 AssertRC(rc2);
7764
7765 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
7766 NOREF(fBlockMovSS); NOREF(fBlockSti);
7767 return rcStrict;
7768}
7769
7770
7771/**
7772 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
7773 *
7774 * @param pVCpu The cross context virtual CPU structure.
7775 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7776 * out-of-sync. Make sure to update the required fields
7777 * before using them.
7778 */
7779DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7780{
7781 NOREF(pMixedCtx);
7782 uint32_t u32IntInfo = X86_XCPT_UD | VMX_EXIT_INTERRUPTION_INFO_VALID;
7783 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7784}
7785
7786
7787/**
7788 * Injects a double-fault (\#DF) exception into the VM.
7789 *
7790 * @returns Strict VBox status code (i.e. informational status codes too).
7791 * @param pVCpu The cross context virtual CPU structure.
7792 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7793 * out-of-sync. Make sure to update the required fields
7794 * before using them.
7795 * @param fStepping Whether we're running in hmR0VmxRunGuestCodeStep()
7796 * and should return VINF_EM_DBG_STEPPED if the event
7797 * is injected directly (register modified by us, not
7798 * by hardware on VM-entry).
7799 * @param puIntrState Pointer to the current guest interruptibility-state.
7800 * This interruptibility-state will be updated if
7801 * necessary. This cannot not be NULL.
7802 */
7803DECLINLINE(VBOXSTRICTRC) hmR0VmxInjectXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fStepping, uint32_t *puIntrState)
7804{
7805 uint32_t u32IntInfo = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
7806 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7807 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7808 return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */,
7809 fStepping, puIntrState);
7810}
7811
7812
7813/**
7814 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
7815 *
7816 * @param pVCpu The cross context virtual CPU structure.
7817 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7818 * out-of-sync. Make sure to update the required fields
7819 * before using them.
7820 */
7821DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7822{
7823 NOREF(pMixedCtx);
7824 uint32_t u32IntInfo = X86_XCPT_DB | VMX_EXIT_INTERRUPTION_INFO_VALID;
7825 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7826 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7827}
7828
7829
7830/**
7831 * Sets an overflow (\#OF) exception as pending-for-injection into the VM.
7832 *
7833 * @param pVCpu The cross context virtual CPU structure.
7834 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7835 * out-of-sync. Make sure to update the required fields
7836 * before using them.
7837 * @param cbInstr The value of RIP that is to be pushed on the guest
7838 * stack.
7839 */
7840DECLINLINE(void) hmR0VmxSetPendingXcptOF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
7841{
7842 NOREF(pMixedCtx);
7843 uint32_t u32IntInfo = X86_XCPT_OF | VMX_EXIT_INTERRUPTION_INFO_VALID;
7844 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7845 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7846}
7847
7848
7849/**
7850 * Injects a general-protection (\#GP) fault into the VM.
7851 *
7852 * @returns Strict VBox status code (i.e. informational status codes too).
7853 * @param pVCpu The cross context virtual CPU structure.
7854 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7855 * out-of-sync. Make sure to update the required fields
7856 * before using them.
7857 * @param fErrorCodeValid Whether the error code is valid (depends on the CPU
7858 * mode, i.e. in real-mode it's not valid).
7859 * @param u32ErrorCode The error code associated with the \#GP.
7860 * @param fStepping Whether we're running in
7861 * hmR0VmxRunGuestCodeStep() and should return
7862 * VINF_EM_DBG_STEPPED if the event is injected
7863 * directly (register modified by us, not by
7864 * hardware on VM-entry).
7865 * @param puIntrState Pointer to the current guest interruptibility-state.
7866 * This interruptibility-state will be updated if
7867 * necessary. This cannot not be NULL.
7868 */
7869DECLINLINE(VBOXSTRICTRC) hmR0VmxInjectXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fErrorCodeValid, uint32_t u32ErrorCode,
7870 bool fStepping, uint32_t *puIntrState)
7871{
7872 uint32_t u32IntInfo = X86_XCPT_GP | VMX_EXIT_INTERRUPTION_INFO_VALID;
7873 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7874 if (fErrorCodeValid)
7875 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7876 return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */,
7877 fStepping, puIntrState);
7878}
7879
7880
7881#if 0 /* unused */
7882/**
7883 * Sets a general-protection (\#GP) exception as pending-for-injection into the
7884 * VM.
7885 *
7886 * @param pVCpu The cross context virtual CPU structure.
7887 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7888 * out-of-sync. Make sure to update the required fields
7889 * before using them.
7890 * @param u32ErrorCode The error code associated with the \#GP.
7891 */
7892DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t u32ErrorCode)
7893{
7894 NOREF(pMixedCtx);
7895 uint32_t u32IntInfo = X86_XCPT_GP | VMX_EXIT_INTERRUPTION_INFO_VALID;
7896 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7897 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7898 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */);
7899}
7900#endif /* unused */
7901
7902
7903/**
7904 * Sets a software interrupt (INTn) as pending-for-injection into the VM.
7905 *
7906 * @param pVCpu The cross context virtual CPU structure.
7907 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7908 * out-of-sync. Make sure to update the required fields
7909 * before using them.
7910 * @param uVector The software interrupt vector number.
7911 * @param cbInstr The value of RIP that is to be pushed on the guest
7912 * stack.
7913 */
7914DECLINLINE(void) hmR0VmxSetPendingIntN(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint16_t uVector, uint32_t cbInstr)
7915{
7916 NOREF(pMixedCtx);
7917 uint32_t u32IntInfo = uVector | VMX_EXIT_INTERRUPTION_INFO_VALID;
7918 if ( uVector == X86_XCPT_BP
7919 || uVector == X86_XCPT_OF)
7920 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7921 else
7922 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7923 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7924}
7925
7926
7927/**
7928 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
7929 * stack.
7930 *
7931 * @returns Strict VBox status code (i.e. informational status codes too).
7932 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
7933 * @param pVM The cross context VM structure.
7934 * @param pMixedCtx Pointer to the guest-CPU context.
7935 * @param uValue The value to push to the guest stack.
7936 */
7937DECLINLINE(VBOXSTRICTRC) hmR0VmxRealModeGuestStackPush(PVM pVM, PCPUMCTX pMixedCtx, uint16_t uValue)
7938{
7939 /*
7940 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
7941 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
7942 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
7943 */
7944 if (pMixedCtx->sp == 1)
7945 return VINF_EM_RESET;
7946 pMixedCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
7947 int rc = PGMPhysSimpleWriteGCPhys(pVM, pMixedCtx->ss.u64Base + pMixedCtx->sp, &uValue, sizeof(uint16_t));
7948 AssertRC(rc);
7949 return rc;
7950}
7951
7952
7953/**
7954 * Injects an event into the guest upon VM-entry by updating the relevant fields
7955 * in the VM-entry area in the VMCS.
7956 *
7957 * @returns Strict VBox status code (i.e. informational status codes too).
7958 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
7959 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
7960 *
7961 * @param pVCpu The cross context virtual CPU structure.
7962 * @param pMixedCtx Pointer to the guest-CPU context. The data may
7963 * be out-of-sync. Make sure to update the required
7964 * fields before using them.
7965 * @param u64IntInfo The VM-entry interruption-information field.
7966 * @param cbInstr The VM-entry instruction length in bytes (for
7967 * software interrupts, exceptions and privileged
7968 * software exceptions).
7969 * @param u32ErrCode The VM-entry exception error code.
7970 * @param GCPtrFaultAddress The page-fault address for \#PF exceptions.
7971 * @param puIntrState Pointer to the current guest interruptibility-state.
7972 * This interruptibility-state will be updated if
7973 * necessary. This cannot not be NULL.
7974 * @param fStepping Whether we're running in
7975 * hmR0VmxRunGuestCodeStep() and should return
7976 * VINF_EM_DBG_STEPPED if the event is injected
7977 * directly (register modified by us, not by
7978 * hardware on VM-entry).
7979 *
7980 * @remarks Requires CR0!
7981 * @remarks No-long-jump zone!!!
7982 */
7983static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
7984 uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, bool fStepping,
7985 uint32_t *puIntrState)
7986{
7987 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
7988 AssertMsg(u64IntInfo >> 32 == 0, ("%#RX64\n", u64IntInfo));
7989 Assert(puIntrState);
7990 uint32_t u32IntInfo = (uint32_t)u64IntInfo;
7991
7992 uint32_t const uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(u32IntInfo);
7993 uint32_t const uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntInfo);
7994
7995#ifdef VBOX_STRICT
7996 /* Validate the error-code-valid bit for hardware exceptions. */
7997 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT)
7998 {
7999 switch (uVector)
8000 {
8001 case X86_XCPT_PF:
8002 case X86_XCPT_DF:
8003 case X86_XCPT_TS:
8004 case X86_XCPT_NP:
8005 case X86_XCPT_SS:
8006 case X86_XCPT_GP:
8007 case X86_XCPT_AC:
8008 AssertMsg(VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(u32IntInfo),
8009 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8010 /* fallthru */
8011 default:
8012 break;
8013 }
8014 }
8015#endif
8016
8017 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8018 Assert( uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
8019 || !(*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS));
8020
8021 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
8022
8023 /* We require CR0 to check if the guest is in real-mode. */
8024 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
8025 AssertRCReturn(rc, rc);
8026
8027 /*
8028 * Hardware interrupts & exceptions cannot be delivered through the software interrupt redirection bitmap to the real
8029 * mode task in virtual-8086 mode. We must jump to the interrupt handler in the (real-mode) guest.
8030 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode" for interrupt & exception classes.
8031 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8032 */
8033 if (CPUMIsGuestInRealModeEx(pMixedCtx))
8034 {
8035 PVM pVM = pVCpu->CTX_SUFF(pVM);
8036 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
8037 {
8038 Assert(PDMVmmDevHeapIsEnabled(pVM));
8039 Assert(pVM->hm.s.vmx.pRealModeTSS);
8040
8041 /* We require RIP, RSP, RFLAGS, CS, IDTR. Save the required ones from the VMCS. */
8042 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
8043 rc |= hmR0VmxSaveGuestTableRegs(pVCpu, pMixedCtx);
8044 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
8045 AssertRCReturn(rc, rc);
8046 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP));
8047
8048 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8049 size_t const cbIdtEntry = sizeof(X86IDTR16);
8050 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pMixedCtx->idtr.cbIdt)
8051 {
8052 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8053 if (uVector == X86_XCPT_DF)
8054 return VINF_EM_RESET;
8055
8056 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault. */
8057 if (uVector == X86_XCPT_GP)
8058 return hmR0VmxInjectXcptDF(pVCpu, pMixedCtx, fStepping, puIntrState);
8059
8060 /* If we're injecting an interrupt/exception with no valid IDT entry, inject a general-protection fault. */
8061 /* No error codes for exceptions in real-mode. See Intel spec. 20.1.4 "Interrupt and Exception Handling" */
8062 return hmR0VmxInjectXcptGP(pVCpu, pMixedCtx, false /* fErrCodeValid */, 0 /* u32ErrCode */,
8063 fStepping, puIntrState);
8064 }
8065
8066 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8067 uint16_t uGuestIp = pMixedCtx->ip;
8068 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT)
8069 {
8070 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8071 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8072 uGuestIp = pMixedCtx->ip + (uint16_t)cbInstr;
8073 }
8074 else if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT)
8075 uGuestIp = pMixedCtx->ip + (uint16_t)cbInstr;
8076
8077 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8078 X86IDTR16 IdtEntry;
8079 RTGCPHYS GCPhysIdtEntry = (RTGCPHYS)pMixedCtx->idtr.pIdt + uVector * cbIdtEntry;
8080 rc = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8081 AssertRCReturn(rc, rc);
8082
8083 /* Construct the stack frame for the interrupt/exception handler. */
8084 VBOXSTRICTRC rcStrict;
8085 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, pMixedCtx->eflags.u32);
8086 if (rcStrict == VINF_SUCCESS)
8087 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, pMixedCtx->cs.Sel);
8088 if (rcStrict == VINF_SUCCESS)
8089 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, uGuestIp);
8090
8091 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8092 if (rcStrict == VINF_SUCCESS)
8093 {
8094 pMixedCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8095 pMixedCtx->rip = IdtEntry.offSel;
8096 pMixedCtx->cs.Sel = IdtEntry.uSel;
8097 pMixedCtx->cs.ValidSel = IdtEntry.uSel;
8098 pMixedCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8099 if ( uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
8100 && uVector == X86_XCPT_PF)
8101 pMixedCtx->cr2 = GCPtrFaultAddress;
8102
8103 /* If any other guest-state bits are changed here, make sure to update
8104 hmR0VmxPreRunGuestCommitted() when thread-context hooks are used. */
8105 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS
8106 | HM_CHANGED_GUEST_RIP
8107 | HM_CHANGED_GUEST_RFLAGS
8108 | HM_CHANGED_GUEST_RSP);
8109
8110 /* We're clearing interrupts, which means no block-by-STI interrupt-inhibition. */
8111 if (*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
8112 {
8113 Assert( uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
8114 && uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
8115 Log4(("Clearing inhibition due to STI.\n"));
8116 *puIntrState &= ~VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
8117 }
8118 Log4(("Injecting real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8119 u32IntInfo, u32ErrCode, cbInstr, pMixedCtx->eflags.u, pMixedCtx->cs.Sel, pMixedCtx->eip));
8120
8121 /* The event has been truly dispatched. Mark it as no longer pending so we don't attempt to 'undo'
8122 it, if we are returning to ring-3 before executing guest code. */
8123 pVCpu->hm.s.Event.fPending = false;
8124
8125 /* Make hmR0VmxPreRunGuest return if we're stepping since we've changed cs:rip. */
8126 if (fStepping)
8127 rcStrict = VINF_EM_DBG_STEPPED;
8128 }
8129 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8130 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8131 return rcStrict;
8132 }
8133
8134 /*
8135 * For unrestricted execution enabled CPUs running real-mode guests, we must not set the deliver-error-code bit.
8136 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8137 */
8138 u32IntInfo &= ~VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
8139 }
8140
8141 /* Validate. */
8142 Assert(VMX_EXIT_INTERRUPTION_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8143 Assert(!VMX_EXIT_INTERRUPTION_INFO_NMI_UNBLOCK_IRET(u32IntInfo)); /* Bit 12 MBZ. */
8144 Assert(!(u32IntInfo & 0x7ffff000)); /* Bits 30:12 MBZ. */
8145
8146 /* Inject. */
8147 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8148 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(u32IntInfo))
8149 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8150 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8151
8152 if ( VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
8153 && uVector == X86_XCPT_PF)
8154 pMixedCtx->cr2 = GCPtrFaultAddress;
8155
8156 Log4(("Injecting vcpu[%RU32] u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x pMixedCtx->uCR2=%#RX64\n", pVCpu->idCpu,
8157 u32IntInfo, u32ErrCode, cbInstr, pMixedCtx->cr2));
8158
8159 AssertRCReturn(rc, rc);
8160 return VINF_SUCCESS;
8161}
8162
8163
8164/**
8165 * Clears the interrupt-window exiting control in the VMCS and if necessary
8166 * clears the current event in the VMCS as well.
8167 *
8168 * @returns VBox status code.
8169 * @param pVCpu The cross context virtual CPU structure.
8170 *
8171 * @remarks Use this function only to clear events that have not yet been
8172 * delivered to the guest but are injected in the VMCS!
8173 * @remarks No-long-jump zone!!!
8174 */
8175static void hmR0VmxClearIntNmiWindowsVmcs(PVMCPU pVCpu)
8176{
8177 Log4Func(("vcpu[%d]\n", pVCpu->idCpu));
8178
8179 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT)
8180 hmR0VmxClearIntWindowExitVmcs(pVCpu);
8181
8182 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT)
8183 hmR0VmxClearNmiWindowExitVmcs(pVCpu);
8184}
8185
8186
8187/**
8188 * Enters the VT-x session.
8189 *
8190 * @returns VBox status code.
8191 * @param pVM The cross context VM structure.
8192 * @param pVCpu The cross context virtual CPU structure.
8193 * @param pCpu Pointer to the CPU info struct.
8194 */
8195VMMR0DECL(int) VMXR0Enter(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
8196{
8197 AssertPtr(pVM);
8198 AssertPtr(pVCpu);
8199 Assert(pVM->hm.s.vmx.fSupported);
8200 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8201 NOREF(pCpu); NOREF(pVM);
8202
8203 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8204 Assert(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE));
8205
8206#ifdef VBOX_STRICT
8207 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
8208 RTCCUINTREG uHostCR4 = ASMGetCR4();
8209 if (!(uHostCR4 & X86_CR4_VMXE))
8210 {
8211 LogRel(("VMXR0Enter: X86_CR4_VMXE bit in CR4 is not set!\n"));
8212 return VERR_VMX_X86_CR4_VMXE_CLEARED;
8213 }
8214#endif
8215
8216 /*
8217 * Load the VCPU's VMCS as the current (and active) one.
8218 */
8219 Assert(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_CLEAR);
8220 int rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
8221 if (RT_FAILURE(rc))
8222 return rc;
8223
8224 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
8225 pVCpu->hm.s.fLeaveDone = false;
8226 Log4Func(("Activated Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8227
8228 return VINF_SUCCESS;
8229}
8230
8231
8232/**
8233 * The thread-context callback (only on platforms which support it).
8234 *
8235 * @param enmEvent The thread-context event.
8236 * @param pVCpu The cross context virtual CPU structure.
8237 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
8238 * @thread EMT(pVCpu)
8239 */
8240VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPU pVCpu, bool fGlobalInit)
8241{
8242 NOREF(fGlobalInit);
8243
8244 switch (enmEvent)
8245 {
8246 case RTTHREADCTXEVENT_OUT:
8247 {
8248 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8249 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8250 VMCPU_ASSERT_EMT(pVCpu);
8251
8252 PCPUMCTX pMixedCtx = CPUMQueryGuestCtxPtr(pVCpu);
8253
8254 /* No longjmps (logger flushes, locks) in this fragile context. */
8255 VMMRZCallRing3Disable(pVCpu);
8256 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
8257
8258 /*
8259 * Restore host-state (FPU, debug etc.)
8260 */
8261 if (!pVCpu->hm.s.fLeaveDone)
8262 {
8263 /* Do -not- save guest-state here as we might already be in the middle of saving it (esp. bad if we are
8264 holding the PGM lock while saving the guest state (see hmR0VmxSaveGuestControlRegs()). */
8265 hmR0VmxLeave(pVCpu, pMixedCtx, false /* fSaveGuestState */);
8266 pVCpu->hm.s.fLeaveDone = true;
8267 }
8268
8269 /* Leave HM context, takes care of local init (term). */
8270 int rc = HMR0LeaveCpu(pVCpu);
8271 AssertRC(rc); NOREF(rc);
8272
8273 /* Restore longjmp state. */
8274 VMMRZCallRing3Enable(pVCpu);
8275 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
8276 break;
8277 }
8278
8279 case RTTHREADCTXEVENT_IN:
8280 {
8281 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8282 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8283 VMCPU_ASSERT_EMT(pVCpu);
8284
8285 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
8286 VMMRZCallRing3Disable(pVCpu);
8287 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
8288
8289 /* Initialize the bare minimum state required for HM. This takes care of
8290 initializing VT-x if necessary (onlined CPUs, local init etc.) */
8291 int rc = HMR0EnterCpu(pVCpu);
8292 AssertRC(rc);
8293 Assert(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE));
8294
8295 /* Load the active VMCS as the current one. */
8296 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_CLEAR)
8297 {
8298 rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
8299 AssertRC(rc); NOREF(rc);
8300 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
8301 Log4Func(("Resumed: Activated Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8302 }
8303 pVCpu->hm.s.fLeaveDone = false;
8304
8305 /* Restore longjmp state. */
8306 VMMRZCallRing3Enable(pVCpu);
8307 break;
8308 }
8309
8310 default:
8311 break;
8312 }
8313}
8314
8315
8316/**
8317 * Saves the host state in the VMCS host-state.
8318 * Sets up the VM-exit MSR-load area.
8319 *
8320 * The CPU state will be loaded from these fields on every successful VM-exit.
8321 *
8322 * @returns VBox status code.
8323 * @param pVM The cross context VM structure.
8324 * @param pVCpu The cross context virtual CPU structure.
8325 *
8326 * @remarks No-long-jump zone!!!
8327 */
8328static int hmR0VmxSaveHostState(PVM pVM, PVMCPU pVCpu)
8329{
8330 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8331
8332 int rc = VINF_SUCCESS;
8333 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT))
8334 {
8335 rc = hmR0VmxSaveHostControlRegs(pVM, pVCpu);
8336 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostControlRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8337
8338 rc = hmR0VmxSaveHostSegmentRegs(pVM, pVCpu);
8339 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostSegmentRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8340
8341 rc = hmR0VmxSaveHostMsrs(pVM, pVCpu);
8342 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostMsrs failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8343
8344 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_HOST_CONTEXT);
8345 }
8346 return rc;
8347}
8348
8349
8350/**
8351 * Saves the host state in the VMCS host-state.
8352 *
8353 * @returns VBox status code.
8354 * @param pVM The cross context VM structure.
8355 * @param pVCpu The cross context virtual CPU structure.
8356 *
8357 * @remarks No-long-jump zone!!!
8358 */
8359VMMR0DECL(int) VMXR0SaveHostState(PVM pVM, PVMCPU pVCpu)
8360{
8361 AssertPtr(pVM);
8362 AssertPtr(pVCpu);
8363
8364 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8365
8366 /* Save the host state here while entering HM context. When thread-context hooks are used, we might get preempted
8367 and have to resave the host state but most of the time we won't be, so do it here before we disable interrupts. */
8368 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8369 return hmR0VmxSaveHostState(pVM, pVCpu);
8370}
8371
8372
8373/**
8374 * Loads the guest state into the VMCS guest-state area.
8375 *
8376 * The will typically be done before VM-entry when the guest-CPU state and the
8377 * VMCS state may potentially be out of sync.
8378 *
8379 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
8380 * VM-entry controls.
8381 * Sets up the appropriate VMX non-root function to execute guest code based on
8382 * the guest CPU mode.
8383 *
8384 * @returns VBox strict status code.
8385 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8386 * without unrestricted guest access and the VMMDev is not presently
8387 * mapped (e.g. EFI32).
8388 *
8389 * @param pVM The cross context VM structure.
8390 * @param pVCpu The cross context virtual CPU structure.
8391 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8392 * out-of-sync. Make sure to update the required fields
8393 * before using them.
8394 *
8395 * @remarks No-long-jump zone!!! (Disables and enables long jmps for itself,
8396 * caller disables then again on successfull return. Confusing.)
8397 */
8398static VBOXSTRICTRC hmR0VmxLoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
8399{
8400 AssertPtr(pVM);
8401 AssertPtr(pVCpu);
8402 AssertPtr(pMixedCtx);
8403 HMVMX_ASSERT_PREEMPT_SAFE();
8404
8405 VMMRZCallRing3Disable(pVCpu);
8406 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8407
8408 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8409
8410 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestState, x);
8411
8412 /* Determine real-on-v86 mode. */
8413 pVCpu->hm.s.vmx.RealMode.fRealOnV86Active = false;
8414 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
8415 && CPUMIsGuestInRealModeEx(pMixedCtx))
8416 {
8417 pVCpu->hm.s.vmx.RealMode.fRealOnV86Active = true;
8418 }
8419
8420 /*
8421 * Load the guest-state into the VMCS.
8422 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
8423 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
8424 */
8425 int rc = hmR0VmxSetupVMRunHandler(pVCpu, pMixedCtx);
8426 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupVMRunHandler! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8427
8428 /* This needs to be done after hmR0VmxSetupVMRunHandler() as changing pfnStartVM may require VM-entry control updates. */
8429 rc = hmR0VmxLoadGuestEntryCtls(pVCpu, pMixedCtx);
8430 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestEntryCtls! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8431
8432 /* This needs to be done after hmR0VmxSetupVMRunHandler() as changing pfnStartVM may require VM-exit control updates. */
8433 rc = hmR0VmxLoadGuestExitCtls(pVCpu, pMixedCtx);
8434 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupExitCtls failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8435
8436 rc = hmR0VmxLoadGuestActivityState(pVCpu, pMixedCtx);
8437 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestActivityState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8438
8439 VBOXSTRICTRC rcStrict = hmR0VmxLoadGuestCR3AndCR4(pVCpu, pMixedCtx);
8440 if (rcStrict == VINF_SUCCESS)
8441 { /* likely */ }
8442 else
8443 {
8444 VMMRZCallRing3Enable(pVCpu);
8445 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
8446 return rcStrict;
8447 }
8448
8449 /* Assumes pMixedCtx->cr0 is up-to-date (strict builds require CR0 for segment register validation checks). */
8450 rc = hmR0VmxLoadGuestSegmentRegs(pVCpu, pMixedCtx);
8451 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestSegmentRegs: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8452
8453 /* This needs to be done after hmR0VmxLoadGuestEntryCtls() and hmR0VmxLoadGuestExitCtls() as it may alter controls if we
8454 determine we don't have to swap EFER after all. */
8455 rc = hmR0VmxLoadGuestMsrs(pVCpu, pMixedCtx);
8456 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadSharedMsrs! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8457
8458 rc = hmR0VmxLoadGuestApicState(pVCpu, pMixedCtx);
8459 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestApicState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8460
8461 rc = hmR0VmxLoadGuestXcptIntercepts(pVCpu, pMixedCtx);
8462 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestXcptIntercepts! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8463
8464 /*
8465 * Loading Rflags here is fine, even though Rflags.TF might depend on guest debug state (which is not loaded here).
8466 * It is re-evaluated and updated if necessary in hmR0VmxLoadSharedState().
8467 */
8468 rc = hmR0VmxLoadGuestRipRspRflags(pVCpu, pMixedCtx);
8469 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestRipRspRflags! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8470
8471 /* Clear any unused and reserved bits. */
8472 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR2);
8473
8474 VMMRZCallRing3Enable(pVCpu);
8475
8476 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
8477 return rc;
8478}
8479
8480
8481/**
8482 * Loads the state shared between the host and guest into the VMCS.
8483 *
8484 * @param pVM The cross context VM structure.
8485 * @param pVCpu The cross context virtual CPU structure.
8486 * @param pCtx Pointer to the guest-CPU context.
8487 *
8488 * @remarks No-long-jump zone!!!
8489 */
8490static void hmR0VmxLoadSharedState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
8491{
8492 NOREF(pVM);
8493
8494 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8495 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8496
8497 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
8498 {
8499 int rc = hmR0VmxLoadSharedCR0(pVCpu, pCtx);
8500 AssertRC(rc);
8501 }
8502
8503 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_DEBUG))
8504 {
8505 int rc = hmR0VmxLoadSharedDebugState(pVCpu, pCtx);
8506 AssertRC(rc);
8507
8508 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
8509 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RFLAGS))
8510 {
8511 rc = hmR0VmxLoadGuestRflags(pVCpu, pCtx);
8512 AssertRC(rc);
8513 }
8514 }
8515
8516 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS))
8517 {
8518 hmR0VmxLazyLoadGuestMsrs(pVCpu, pCtx);
8519 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS);
8520 }
8521
8522 /* Loading CR0, debug state might have changed intercepts, update VMCS. */
8523 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
8524 {
8525 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_AC));
8526 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
8527 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
8528 AssertRC(rc);
8529 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
8530 }
8531
8532 AssertMsg(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE),
8533 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8534}
8535
8536
8537/**
8538 * Worker for loading the guest-state bits in the inner VT-x execution loop.
8539 *
8540 * @returns Strict VBox status code (i.e. informational status codes too).
8541 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8542 * without unrestricted guest access and the VMMDev is not presently
8543 * mapped (e.g. EFI32).
8544 *
8545 * @param pVM The cross context VM structure.
8546 * @param pVCpu The cross context virtual CPU structure.
8547 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8548 * out-of-sync. Make sure to update the required fields
8549 * before using them.
8550 */
8551static VBOXSTRICTRC hmR0VmxLoadGuestStateOptimal(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
8552{
8553 HMVMX_ASSERT_PREEMPT_SAFE();
8554
8555 Log5(("LoadFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8556#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
8557 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
8558#endif
8559
8560 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
8561 if (HMCPU_CF_IS_SET_ONLY(pVCpu, HM_CHANGED_GUEST_RIP))
8562 {
8563 rcStrict = hmR0VmxLoadGuestRip(pVCpu, pMixedCtx);
8564 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8565 { /* likely */}
8566 else
8567 {
8568 AssertMsgFailedReturn(("hmR0VmxLoadGuestStateOptimal: hmR0VmxLoadGuestRip failed! rc=%Rrc\n",
8569 VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
8570 }
8571 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadMinimal);
8572 }
8573 else if (HMCPU_CF_VALUE(pVCpu))
8574 {
8575 rcStrict = hmR0VmxLoadGuestState(pVM, pVCpu, pMixedCtx);
8576 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8577 { /* likely */}
8578 else
8579 {
8580 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM,
8581 ("hmR0VmxLoadGuestStateOptimal: hmR0VmxLoadGuestState failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8582 return rcStrict;
8583 }
8584 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadFull);
8585 }
8586
8587 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
8588 AssertMsg( !HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_ALL_GUEST)
8589 || HMCPU_CF_IS_PENDING_ONLY(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE),
8590 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8591 return rcStrict;
8592}
8593
8594
8595/**
8596 * Does the preparations before executing guest code in VT-x.
8597 *
8598 * This may cause longjmps to ring-3 and may even result in rescheduling to the
8599 * recompiler/IEM. We must be cautious what we do here regarding committing
8600 * guest-state information into the VMCS assuming we assuredly execute the
8601 * guest in VT-x mode.
8602 *
8603 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
8604 * the common-state (TRPM/forceflags), we must undo those changes so that the
8605 * recompiler/IEM can (and should) use them when it resumes guest execution.
8606 * Otherwise such operations must be done when we can no longer exit to ring-3.
8607 *
8608 * @returns Strict VBox status code (i.e. informational status codes too).
8609 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
8610 * have been disabled.
8611 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
8612 * double-fault into the guest.
8613 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
8614 * dispatched directly.
8615 * @retval VINF_* scheduling changes, we have to go back to ring-3.
8616 *
8617 * @param pVM The cross context VM structure.
8618 * @param pVCpu The cross context virtual CPU structure.
8619 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8620 * out-of-sync. Make sure to update the required fields
8621 * before using them.
8622 * @param pVmxTransient Pointer to the VMX transient structure.
8623 * @param fStepping Set if called from hmR0VmxRunGuestCodeStep(). Makes
8624 * us ignore some of the reasons for returning to
8625 * ring-3, and return VINF_EM_DBG_STEPPED if event
8626 * dispatching took place.
8627 */
8628static VBOXSTRICTRC hmR0VmxPreRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, bool fStepping)
8629{
8630 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8631
8632#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
8633 PGMRZDynMapFlushAutoSet(pVCpu);
8634#endif
8635
8636 /* Check force flag actions that might require us to go back to ring-3. */
8637 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVM, pVCpu, pMixedCtx, fStepping);
8638 if (rcStrict == VINF_SUCCESS)
8639 { /* FFs doesn't get set all the time. */ }
8640 else
8641 return rcStrict;
8642
8643 if (TRPMHasTrap(pVCpu))
8644 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
8645 uint32_t uIntrState = hmR0VmxEvaluatePendingEvent(pVCpu, pMixedCtx);
8646
8647 /*
8648 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus needs to be done with
8649 * longjmps or interrupts + preemption enabled. Event injection might also result in triple-faulting the VM.
8650 */
8651 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx, uIntrState, fStepping);
8652 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8653 { /* likely */ }
8654 else
8655 {
8656 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8657 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8658 return rcStrict;
8659 }
8660
8661 /*
8662 * Load the guest state bits, we can handle longjmps/getting preempted here.
8663 *
8664 * If we are injecting events to a real-on-v86 mode guest, we will have to update
8665 * RIP and some segment registers, i.e. hmR0VmxInjectPendingEvent()->hmR0VmxInjectEventVmcs().
8666 * Hence, this needs to be done -after- injection of events.
8667 */
8668 rcStrict = hmR0VmxLoadGuestStateOptimal(pVM, pVCpu, pMixedCtx);
8669 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8670 { /* likely */ }
8671 else
8672 return rcStrict;
8673
8674 /*
8675 * No longjmps to ring-3 from this point on!!!
8676 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
8677 * This also disables flushing of the R0-logger instance (if any).
8678 */
8679 VMMRZCallRing3Disable(pVCpu);
8680
8681 /*
8682 * We disable interrupts so that we don't miss any interrupts that would flag preemption (IPI/timers etc.)
8683 * when thread-context hooks aren't used and we've been running with preemption disabled for a while.
8684 *
8685 * We need to check for force-flags that could've possible been altered since we last checked them (e.g.
8686 * by PDMGetInterrupt() leaving the PDM critical section, see @bugref{6398}).
8687 *
8688 * We also check a couple of other force-flags as a last opportunity to get the EMT back to ring-3 before
8689 * executing guest code.
8690 */
8691 pVmxTransient->fEFlags = ASMIntDisableFlags();
8692
8693 if ( ( !VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
8694 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
8695 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
8696 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
8697 {
8698 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
8699 {
8700 /* We've injected any pending events. This is really the point of no return (to ring-3). */
8701 pVCpu->hm.s.Event.fPending = false;
8702
8703 return VINF_SUCCESS;
8704 }
8705
8706 STAM_COUNTER_INC(&pVCpu->hm.s.StatPendingHostIrq);
8707 rcStrict = VINF_EM_RAW_INTERRUPT;
8708 }
8709 else
8710 {
8711 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
8712 rcStrict = VINF_EM_RAW_TO_R3;
8713 }
8714
8715 ASMSetFlags(pVmxTransient->fEFlags);
8716 VMMRZCallRing3Enable(pVCpu);
8717
8718 return rcStrict;
8719}
8720
8721
8722/**
8723 * Prepares to run guest code in VT-x and we've committed to doing so. This
8724 * means there is no backing out to ring-3 or anywhere else at this
8725 * point.
8726 *
8727 * @param pVM The cross context VM structure.
8728 * @param pVCpu The cross context virtual CPU structure.
8729 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8730 * out-of-sync. Make sure to update the required fields
8731 * before using them.
8732 * @param pVmxTransient Pointer to the VMX transient structure.
8733 *
8734 * @remarks Called with preemption disabled.
8735 * @remarks No-long-jump zone!!!
8736 */
8737static void hmR0VmxPreRunGuestCommitted(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8738{
8739 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8740 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8741 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8742
8743 /*
8744 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
8745 */
8746 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
8747 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
8748
8749#ifdef HMVMX_ALWAYS_SWAP_FPU_STATE
8750 if (!CPUMIsGuestFPUStateActive(pVCpu))
8751 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
8752 HMCPU_CF_SET(pVCpu, HM_CHANGED_HOST_CONTEXT);
8753 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
8754#endif
8755
8756 if ( pVCpu->hm.s.fPreloadGuestFpu
8757 && !CPUMIsGuestFPUStateActive(pVCpu))
8758 {
8759 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
8760 HMCPU_CF_SET(pVCpu, HM_CHANGED_HOST_CONTEXT);
8761 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
8762 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
8763 }
8764
8765 /*
8766 * Lazy-update of the host MSRs values in the auto-load/store MSR area.
8767 */
8768 if ( !pVCpu->hm.s.vmx.fUpdatedHostMsrs
8769 && pVCpu->hm.s.vmx.cMsrs > 0)
8770 {
8771 hmR0VmxUpdateAutoLoadStoreHostMsrs(pVCpu);
8772 }
8773
8774 /*
8775 * Load the host state bits as we may've been preempted (only happens when
8776 * thread-context hooks are used or when hmR0VmxSetupVMRunHandler() changes pfnStartVM).
8777 * Note that the 64-on-32 switcher saves the (64-bit) host state into the VMCS and
8778 * if we change the switcher back to 32-bit, we *must* save the 32-bit host state here.
8779 * See @bugref{8432}.
8780 */
8781 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT))
8782 {
8783 int rc = hmR0VmxSaveHostState(pVM, pVCpu);
8784 AssertRC(rc);
8785 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreemptSaveHostState);
8786 }
8787 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT));
8788
8789 /*
8790 * Load the state shared between host and guest (FPU, debug, lazy MSRs).
8791 */
8792 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE))
8793 hmR0VmxLoadSharedState(pVM, pVCpu, pMixedCtx);
8794 AssertMsg(!HMCPU_CF_VALUE(pVCpu), ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8795
8796 /* Store status of the shared guest-host state at the time of VM-entry. */
8797#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
8798 if (CPUMIsGuestInLongModeEx(pMixedCtx))
8799 {
8800 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActivePending(pVCpu);
8801 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActivePending(pVCpu);
8802 }
8803 else
8804#endif
8805 {
8806 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
8807 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
8808 }
8809 pVmxTransient->fWasGuestFPUStateActive = CPUMIsGuestFPUStateActive(pVCpu);
8810
8811 /*
8812 * Cache the TPR-shadow for checking on every VM-exit if it might have changed.
8813 */
8814 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
8815 pVmxTransient->u8GuestTpr = pVCpu->hm.s.vmx.pbVirtApic[XAPIC_OFF_TPR];
8816
8817 PHMGLOBALCPUINFO pCpu = HMR0GetCurrentCpu();
8818 RTCPUID idCurrentCpu = pCpu->idCpu;
8819 if ( pVmxTransient->fUpdateTscOffsettingAndPreemptTimer
8820 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
8821 {
8822 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVM, pVCpu);
8823 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = false;
8824 }
8825
8826 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
8827 hmR0VmxFlushTaggedTlb(pVCpu, pCpu); /* Invalidate the appropriate guest entries from the TLB. */
8828 Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
8829 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Update the error reporting info. with the current host CPU. */
8830
8831 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
8832
8833 TMNotifyStartOfExecution(pVCpu); /* Finally, notify TM to resume its clocks as we're about
8834 to start executing. */
8835
8836 /*
8837 * Load the TSC_AUX MSR when we are not intercepting RDTSCP.
8838 */
8839 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP)
8840 {
8841 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
8842 {
8843 bool fMsrUpdated;
8844 int rc2 = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
8845 AssertRC(rc2);
8846 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS));
8847
8848 rc2 = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_TSC_AUX, CPUMR0GetGuestTscAux(pVCpu), true /* fUpdateHostMsr */,
8849 &fMsrUpdated);
8850 AssertRC(rc2);
8851 Assert(fMsrUpdated || pVCpu->hm.s.vmx.fUpdatedHostMsrs);
8852
8853 /* Finally, mark that all host MSR values are updated so we don't redo it without leaving VT-x. See @bugref{6956}. */
8854 pVCpu->hm.s.vmx.fUpdatedHostMsrs = true;
8855 }
8856 else
8857 {
8858 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, MSR_K8_TSC_AUX);
8859 Assert(!pVCpu->hm.s.vmx.cMsrs || pVCpu->hm.s.vmx.fUpdatedHostMsrs);
8860 }
8861 }
8862
8863#ifdef VBOX_STRICT
8864 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu);
8865 hmR0VmxCheckHostEferMsr(pVCpu);
8866 AssertRC(hmR0VmxCheckVmcsCtls(pVCpu));
8867#endif
8868#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
8869 uint32_t uInvalidReason = hmR0VmxCheckGuestState(pVM, pVCpu, pMixedCtx);
8870 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
8871 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
8872#endif
8873}
8874
8875
8876/**
8877 * Performs some essential restoration of state after running guest code in
8878 * VT-x.
8879 *
8880 * @param pVM The cross context VM structure.
8881 * @param pVCpu The cross context virtual CPU structure.
8882 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
8883 * out-of-sync. Make sure to update the required fields
8884 * before using them.
8885 * @param pVmxTransient Pointer to the VMX transient structure.
8886 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
8887 *
8888 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
8889 *
8890 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
8891 * unconditionally when it is safe to do so.
8892 */
8893static void hmR0VmxPostRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, int rcVMRun)
8894{
8895 NOREF(pVM);
8896
8897 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8898
8899 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
8900 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
8901 HMVMXCPU_GST_RESET_TO(pVCpu, 0); /* Exits/longjmps to ring-3 requires saving the guest state. */
8902 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
8903 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
8904 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
8905
8906 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
8907 TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVCpu->hm.s.vmx.u64TSCOffset);
8908
8909 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatExit1, x);
8910 TMNotifyEndOfExecution(pVCpu); /* Notify TM that the guest is no longer running. */
8911 Assert(!ASMIntAreEnabled());
8912 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
8913
8914#ifdef HMVMX_ALWAYS_SWAP_FPU_STATE
8915 if (CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVM, pVCpu))
8916 {
8917 hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
8918 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
8919 }
8920#endif
8921
8922#if HC_ARCH_BITS == 64
8923 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Host state messed up by VT-x, we must restore. */
8924#endif
8925#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
8926 /* The 64-on-32 switcher maintains uVmcsState on its own and we need to leave it alone here. */
8927 if (pVCpu->hm.s.vmx.pfnStartVM != VMXR0SwitcherStartVM64)
8928 pVCpu->hm.s.vmx.uVmcsState |= HMVMX_VMCS_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
8929#else
8930 pVCpu->hm.s.vmx.uVmcsState |= HMVMX_VMCS_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
8931#endif
8932#ifdef VBOX_STRICT
8933 hmR0VmxCheckHostEferMsr(pVCpu); /* Verify that VMRUN/VMLAUNCH didn't modify host EFER. */
8934#endif
8935 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
8936 VMMRZCallRing3Enable(pVCpu); /* It is now safe to do longjmps to ring-3!!! */
8937
8938 /* Save the basic VM-exit reason. Refer Intel spec. 24.9.1 "Basic VM-exit Information". */
8939 uint32_t uExitReason;
8940 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8941 rc |= hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
8942 AssertRC(rc);
8943 pVmxTransient->uExitReason = (uint16_t)VMX_EXIT_REASON_BASIC(uExitReason);
8944 pVmxTransient->fVMEntryFailed = VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uEntryIntInfo);
8945
8946 /* If the VMLAUNCH/VMRESUME failed, we can bail out early. This does -not- cover VMX_EXIT_ERR_*. */
8947 if (RT_UNLIKELY(rcVMRun != VINF_SUCCESS))
8948 {
8949 Log4(("VM-entry failure: pVCpu=%p idCpu=%RU32 rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", pVCpu, pVCpu->idCpu, rcVMRun,
8950 pVmxTransient->fVMEntryFailed));
8951 return;
8952 }
8953
8954 /*
8955 * Update the VM-exit history array here even if the VM-entry failed due to:
8956 * - Invalid guest state.
8957 * - MSR loading.
8958 * - Machine-check event.
8959 *
8960 * In any of the above cases we will still have a "valid" VM-exit reason
8961 * despite @a fVMEntryFailed being false.
8962 *
8963 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
8964 */
8965 HMCPU_EXIT_HISTORY_ADD(pVCpu, pVmxTransient->uExitReason);
8966
8967 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
8968 {
8969 /** @todo We can optimize this by only syncing with our force-flags when
8970 * really needed and keeping the VMCS state as it is for most
8971 * VM-exits. */
8972 /* Update the guest interruptibility-state from the VMCS. */
8973 hmR0VmxSaveGuestIntrState(pVCpu, pMixedCtx);
8974
8975#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
8976 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
8977 AssertRC(rc);
8978#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
8979 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
8980 AssertRC(rc);
8981#endif
8982
8983 /*
8984 * If the TPR was raised by the guest, it wouldn't cause a VM-exit immediately. Instead we sync the TPR lazily whenever
8985 * we eventually get a VM-exit for any reason.
8986 *
8987 * This maybe expensive as PDMApicSetTPR() can longjmp to ring-3 and which is why it's done here as it's easier and
8988 * no less efficient to deal with it here than making hmR0VmxSaveGuestState() cope with longjmps safely
8989 * (see VMCPU_FF_HM_UPDATE_CR3 handling).
8990 */
8991 /** @todo r=ramshankar: The 2nd para in the above comment is
8992 * outdated, we no longer longjmp to ring-3 on setting
8993 * the TPR, but regardless we can probably rework this
8994 * portion of the code a bit. */
8995 if ( (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
8996 && pVmxTransient->u8GuestTpr != pVCpu->hm.s.vmx.pbVirtApic[XAPIC_OFF_TPR])
8997 {
8998 rc = APICSetTpr(pVCpu, pVCpu->hm.s.vmx.pbVirtApic[XAPIC_OFF_TPR]);
8999 AssertRC(rc);
9000 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
9001 }
9002 }
9003}
9004
9005
9006/**
9007 * Runs the guest code using VT-x the normal way.
9008 *
9009 * @returns VBox status code.
9010 * @param pVM The cross context VM structure.
9011 * @param pVCpu The cross context virtual CPU structure.
9012 * @param pCtx Pointer to the guest-CPU context.
9013 *
9014 * @note Mostly the same as hmR0VmxRunGuestCodeStep().
9015 */
9016static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
9017{
9018 VMXTRANSIENT VmxTransient;
9019 VmxTransient.fUpdateTscOffsettingAndPreemptTimer = true;
9020 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
9021 uint32_t cLoops = 0;
9022
9023 for (;; cLoops++)
9024 {
9025 Assert(!HMR0SuspendPending());
9026 HMVMX_ASSERT_CPU_SAFE();
9027
9028 /* Preparatory work for running guest code, this may force us to return
9029 to ring-3. This bugger disables interrupts on VINF_SUCCESS! */
9030 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
9031 rcStrict = hmR0VmxPreRunGuest(pVM, pVCpu, pCtx, &VmxTransient, false /* fStepping */);
9032 if (rcStrict != VINF_SUCCESS)
9033 break;
9034
9035 hmR0VmxPreRunGuestCommitted(pVM, pVCpu, pCtx, &VmxTransient);
9036 int rcRun = hmR0VmxRunGuest(pVM, pVCpu, pCtx);
9037 /* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
9038
9039 /* Restore any residual host-state and save any bits shared between host
9040 and guest into the guest-CPU state. Re-enables interrupts! */
9041 hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, rcRun);
9042
9043 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
9044 if (RT_SUCCESS(rcRun))
9045 { /* very likely */ }
9046 else
9047 {
9048 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
9049 hmR0VmxReportWorldSwitchError(pVM, pVCpu, rcRun, pCtx, &VmxTransient);
9050 return rcRun;
9051 }
9052
9053 /* Profile the VM-exit. */
9054 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
9055 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
9056 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
9057 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
9058 HMVMX_START_EXIT_DISPATCH_PROF();
9059
9060 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, pCtx, VmxTransient.uExitReason);
9061
9062 /* Handle the VM-exit. */
9063#ifdef HMVMX_USE_FUNCTION_TABLE
9064 rcStrict = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, pCtx, &VmxTransient);
9065#else
9066 rcStrict = hmR0VmxHandleExit(pVCpu, pCtx, &VmxTransient, VmxTransient.uExitReason);
9067#endif
9068 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
9069 if (rcStrict == VINF_SUCCESS)
9070 {
9071 if (cLoops <= pVM->hm.s.cMaxResumeLoops)
9072 continue; /* likely */
9073 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
9074 rcStrict = VINF_EM_RAW_INTERRUPT;
9075 }
9076 break;
9077 }
9078
9079 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
9080 return rcStrict;
9081}
9082
9083
9084
9085/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
9086 * probes.
9087 *
9088 * The following few functions and associated structure contains the bloat
9089 * necessary for providing detailed debug events and dtrace probes as well as
9090 * reliable host side single stepping. This works on the principle of
9091 * "subclassing" the normal execution loop and workers. We replace the loop
9092 * method completely and override selected helpers to add necessary adjustments
9093 * to their core operation.
9094 *
9095 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
9096 * any performance for debug and analysis features.
9097 *
9098 * @{
9099 */
9100
9101/**
9102 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
9103 * the debug run loop.
9104 */
9105typedef struct VMXRUNDBGSTATE
9106{
9107 /** The RIP we started executing at. This is for detecting that we stepped. */
9108 uint64_t uRipStart;
9109 /** The CS we started executing with. */
9110 uint16_t uCsStart;
9111
9112 /** Whether we've actually modified the 1st execution control field. */
9113 bool fModifiedProcCtls : 1;
9114 /** Whether we've actually modified the 2nd execution control field. */
9115 bool fModifiedProcCtls2 : 1;
9116 /** Whether we've actually modified the exception bitmap. */
9117 bool fModifiedXcptBitmap : 1;
9118
9119 /** We desire the modified the CR0 mask to be cleared. */
9120 bool fClearCr0Mask : 1;
9121 /** We desire the modified the CR4 mask to be cleared. */
9122 bool fClearCr4Mask : 1;
9123 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
9124 uint32_t fCpe1Extra;
9125 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
9126 uint32_t fCpe1Unwanted;
9127 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
9128 uint32_t fCpe2Extra;
9129 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
9130 uint32_t bmXcptExtra;
9131 /** The sequence number of the Dtrace provider settings the state was
9132 * configured against. */
9133 uint32_t uDtraceSettingsSeqNo;
9134 /** VM-exits to check (one bit per VM-exit). */
9135 uint32_t bmExitsToCheck[3];
9136
9137 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
9138 uint32_t fProcCtlsInitial;
9139 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
9140 uint32_t fProcCtls2Initial;
9141 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
9142 uint32_t bmXcptInitial;
9143} VMXRUNDBGSTATE;
9144AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
9145typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
9146
9147
9148/**
9149 * Initializes the VMXRUNDBGSTATE structure.
9150 *
9151 * @param pVCpu The cross context virtual CPU structure of the
9152 * calling EMT.
9153 * @param pCtx The CPU register context to go with @a pVCpu.
9154 * @param pDbgState The structure to initialize.
9155 */
9156DECLINLINE(void) hmR0VmxRunDebugStateInit(PVMCPU pVCpu, PCCPUMCTX pCtx, PVMXRUNDBGSTATE pDbgState)
9157{
9158 pDbgState->uRipStart = pCtx->rip;
9159 pDbgState->uCsStart = pCtx->cs.Sel;
9160
9161 pDbgState->fModifiedProcCtls = false;
9162 pDbgState->fModifiedProcCtls2 = false;
9163 pDbgState->fModifiedXcptBitmap = false;
9164 pDbgState->fClearCr0Mask = false;
9165 pDbgState->fClearCr4Mask = false;
9166 pDbgState->fCpe1Extra = 0;
9167 pDbgState->fCpe1Unwanted = 0;
9168 pDbgState->fCpe2Extra = 0;
9169 pDbgState->bmXcptExtra = 0;
9170 pDbgState->fProcCtlsInitial = pVCpu->hm.s.vmx.u32ProcCtls;
9171 pDbgState->fProcCtls2Initial = pVCpu->hm.s.vmx.u32ProcCtls2;
9172 pDbgState->bmXcptInitial = pVCpu->hm.s.vmx.u32XcptBitmap;
9173}
9174
9175
9176/**
9177 * Updates the VMSC fields with changes requested by @a pDbgState.
9178 *
9179 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
9180 * immediately before executing guest code, i.e. when interrupts are disabled.
9181 * We don't check status codes here as we cannot easily assert or return in the
9182 * latter case.
9183 *
9184 * @param pVCpu The cross context virtual CPU structure.
9185 * @param pDbgState The debug state.
9186 */
9187DECLINLINE(void) hmR0VmxPreRunGuestDebugStateApply(PVMCPU pVCpu, PVMXRUNDBGSTATE pDbgState)
9188{
9189 /*
9190 * Ensure desired flags in VMCS control fields are set.
9191 * (Ignoring write failure here, as we're committed and it's just debug extras.)
9192 *
9193 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
9194 * there should be no stale data in pCtx at this point.
9195 */
9196 if ( (pVCpu->hm.s.vmx.u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
9197 || (pVCpu->hm.s.vmx.u32ProcCtls & pDbgState->fCpe1Unwanted))
9198 {
9199 pVCpu->hm.s.vmx.u32ProcCtls |= pDbgState->fCpe1Extra;
9200 pVCpu->hm.s.vmx.u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
9201 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
9202 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVCpu->hm.s.vmx.u32ProcCtls));
9203 pDbgState->fModifiedProcCtls = true;
9204 }
9205
9206 if ((pVCpu->hm.s.vmx.u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
9207 {
9208 pVCpu->hm.s.vmx.u32ProcCtls2 |= pDbgState->fCpe2Extra;
9209 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVCpu->hm.s.vmx.u32ProcCtls2);
9210 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVCpu->hm.s.vmx.u32ProcCtls2));
9211 pDbgState->fModifiedProcCtls2 = true;
9212 }
9213
9214 if ((pVCpu->hm.s.vmx.u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
9215 {
9216 pVCpu->hm.s.vmx.u32XcptBitmap |= pDbgState->bmXcptExtra;
9217 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
9218 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVCpu->hm.s.vmx.u32XcptBitmap));
9219 pDbgState->fModifiedXcptBitmap = true;
9220 }
9221
9222 if (pDbgState->fClearCr0Mask && pVCpu->hm.s.vmx.u32CR0Mask != 0)
9223 {
9224 pVCpu->hm.s.vmx.u32CR0Mask = 0;
9225 VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_MASK, 0);
9226 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS_CTRL_CR0_MASK: 0\n"));
9227 }
9228
9229 if (pDbgState->fClearCr4Mask && pVCpu->hm.s.vmx.u32CR4Mask != 0)
9230 {
9231 pVCpu->hm.s.vmx.u32CR4Mask = 0;
9232 VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_MASK, 0);
9233 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS_CTRL_CR4_MASK: 0\n"));
9234 }
9235}
9236
9237
9238DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugStateRevert(PVMCPU pVCpu, PVMXRUNDBGSTATE pDbgState, VBOXSTRICTRC rcStrict)
9239{
9240 /*
9241 * Restore VM-exit control settings as we may not reenter this function the
9242 * next time around.
9243 */
9244 /* We reload the initial value, trigger what we can of recalculations the
9245 next time around. From the looks of things, that's all that's required atm. */
9246 if (pDbgState->fModifiedProcCtls)
9247 {
9248 if (!(pDbgState->fProcCtlsInitial & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
9249 pDbgState->fProcCtlsInitial |= VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
9250 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
9251 AssertRCReturn(rc2, rc2);
9252 pVCpu->hm.s.vmx.u32ProcCtls = pDbgState->fProcCtlsInitial;
9253 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0 | HM_CHANGED_GUEST_DEBUG);
9254 }
9255
9256 /* We're currently the only ones messing with this one, so just restore the
9257 cached value and reload the field. */
9258 if ( pDbgState->fModifiedProcCtls2
9259 && pVCpu->hm.s.vmx.u32ProcCtls2 != pDbgState->fProcCtls2Initial)
9260 {
9261 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
9262 AssertRCReturn(rc2, rc2);
9263 pVCpu->hm.s.vmx.u32ProcCtls2 = pDbgState->fProcCtls2Initial;
9264 }
9265
9266 /* If we've modified the exception bitmap, we restore it and trigger
9267 reloading and partial recalculation the next time around. */
9268 if (pDbgState->fModifiedXcptBitmap)
9269 {
9270 pVCpu->hm.s.vmx.u32XcptBitmap = pDbgState->bmXcptInitial;
9271 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS | HM_CHANGED_GUEST_CR0);
9272 }
9273
9274 /* We assume hmR0VmxLoadSharedCR0 will recalculate and load the CR0 mask. */
9275 if (pDbgState->fClearCr0Mask)
9276 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9277
9278 /* We assume hmR0VmxLoadGuestCR3AndCR4 will recalculate and load the CR4 mask. */
9279 if (pDbgState->fClearCr4Mask)
9280 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
9281
9282 return rcStrict;
9283}
9284
9285
9286/**
9287 * Configures VM-exit controls for current DBGF and DTrace settings.
9288 *
9289 * This updates @a pDbgState and the VMCS execution control fields to reflect
9290 * the necessary VM-exits demanded by DBGF and DTrace.
9291 *
9292 * @param pVM The cross context VM structure.
9293 * @param pVCpu The cross context virtual CPU structure.
9294 * @param pCtx Pointer to the guest-CPU context.
9295 * @param pDbgState The debug state.
9296 * @param pVmxTransient Pointer to the VMX transient structure. May update
9297 * fUpdateTscOffsettingAndPreemptTimer.
9298 */
9299static void hmR0VmxPreRunGuestDebugStateUpdate(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx,
9300 PVMXRUNDBGSTATE pDbgState, PVMXTRANSIENT pVmxTransient)
9301{
9302 /*
9303 * Take down the dtrace serial number so we can spot changes.
9304 */
9305 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
9306 ASMCompilerBarrier();
9307
9308 /*
9309 * We'll rebuild most of the middle block of data members (holding the
9310 * current settings) as we go along here, so start by clearing it all.
9311 */
9312 pDbgState->bmXcptExtra = 0;
9313 pDbgState->fCpe1Extra = 0;
9314 pDbgState->fCpe1Unwanted = 0;
9315 pDbgState->fCpe2Extra = 0;
9316 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
9317 pDbgState->bmExitsToCheck[i] = 0;
9318
9319 /*
9320 * Software interrupts (INT XXh) - no idea how to trigger these...
9321 */
9322 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
9323 || VBOXVMM_INT_SOFTWARE_ENABLED())
9324 {
9325 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
9326 }
9327
9328 /*
9329 * INT3 breakpoints - triggered by #BP exceptions.
9330 */
9331 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
9332 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
9333
9334 /*
9335 * Exception bitmap and XCPT events+probes.
9336 */
9337 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
9338 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
9339 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
9340
9341 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
9342 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
9343 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
9344 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
9345 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
9346 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
9347 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
9348 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
9349 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
9350 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
9351 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
9352 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
9353 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
9354 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
9355 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
9356 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
9357 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
9358 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
9359
9360 if (pDbgState->bmXcptExtra)
9361 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
9362
9363 /*
9364 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
9365 *
9366 * Note! This is the reverse of waft hmR0VmxHandleExitDtraceEvents does.
9367 * So, when adding/changing/removing please don't forget to update it.
9368 *
9369 * Some of the macros are picking up local variables to save horizontal space,
9370 * (being able to see it in a table is the lesser evil here).
9371 */
9372#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
9373 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
9374 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
9375#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
9376 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9377 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9378 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9379 } else do { } while (0)
9380#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
9381 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9382 { \
9383 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
9384 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9385 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9386 } else do { } while (0)
9387#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
9388 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9389 { \
9390 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
9391 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9392 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9393 } else do { } while (0)
9394#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
9395 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9396 { \
9397 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
9398 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9399 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9400 } else do { } while (0)
9401
9402 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
9403 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
9404 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
9405 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
9406 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
9407
9408 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
9409 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
9410 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
9411 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
9412 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT); /* paranoia */
9413 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
9414 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
9415 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
9416 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT);
9417 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
9418 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_VMCS_CTRL_PROC_EXEC_RDPMC_EXIT);
9419 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
9420 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT);
9421 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
9422 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
9423 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
9424 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
9425 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
9426 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
9427 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
9428 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
9429 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
9430 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
9431 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
9432 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
9433 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
9434 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
9435 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
9436 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
9437 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
9438 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
9439 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
9440 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
9441 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
9442 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
9443 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
9444
9445 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
9446 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
9447 {
9448 int rc2 = hmR0VmxSaveGuestCR0(pVCpu, pCtx);
9449 rc2 |= hmR0VmxSaveGuestCR4(pVCpu, pCtx);
9450 rc2 |= hmR0VmxSaveGuestApicState(pVCpu, pCtx);
9451 AssertRC(rc2);
9452
9453#if 0 /** @todo fix me */
9454 pDbgState->fClearCr0Mask = true;
9455 pDbgState->fClearCr4Mask = true;
9456#endif
9457 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
9458 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT | VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT;
9459 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
9460 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT | VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT;
9461 pDbgState->fCpe1Unwanted |= VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW; /* risky? */
9462 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
9463 require clearing here and in the loop if we start using it. */
9464 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
9465 }
9466 else
9467 {
9468 if (pDbgState->fClearCr0Mask)
9469 {
9470 pDbgState->fClearCr0Mask = false;
9471 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9472 }
9473 if (pDbgState->fClearCr4Mask)
9474 {
9475 pDbgState->fClearCr4Mask = false;
9476 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
9477 }
9478 }
9479 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
9480 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
9481
9482 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
9483 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
9484 {
9485 /** @todo later, need to fix handler as it assumes this won't usually happen. */
9486 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
9487 }
9488 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
9489 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
9490
9491 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS); /* risky clearing this? */
9492 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
9493 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS);
9494 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
9495 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_VMCS_CTRL_PROC_EXEC_MWAIT_EXIT); /* paranoia */
9496 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
9497 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_VMCS_CTRL_PROC_EXEC_MONITOR_EXIT); /* paranoia */
9498 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
9499#if 0 /** @todo too slow, fix handler. */
9500 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_VMCS_CTRL_PROC_EXEC_PAUSE_EXIT);
9501#endif
9502 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
9503
9504 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
9505 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
9506 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
9507 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
9508 {
9509 pDbgState->fCpe2Extra |= VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT;
9510 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XDTR_ACCESS);
9511 }
9512 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_XDTR_ACCESS);
9513 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_XDTR_ACCESS);
9514 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_XDTR_ACCESS);
9515 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_XDTR_ACCESS);
9516
9517 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
9518 || IS_EITHER_ENABLED(pVM, INSTR_STR)
9519 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
9520 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
9521 {
9522 pDbgState->fCpe2Extra |= VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT;
9523 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_TR_ACCESS);
9524 }
9525 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_TR_ACCESS);
9526 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_TR_ACCESS);
9527 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_TR_ACCESS);
9528 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_TR_ACCESS);
9529
9530 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
9531 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
9532 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT);
9533 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
9534 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
9535 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
9536 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT);
9537 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
9538 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
9539 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
9540 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT);
9541 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
9542 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT);
9543 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
9544 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
9545 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
9546 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_VMCS_CTRL_PROC_EXEC2_RDSEED_EXIT);
9547 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
9548 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
9549 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
9550 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
9551 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
9552
9553#undef IS_EITHER_ENABLED
9554#undef SET_ONLY_XBM_IF_EITHER_EN
9555#undef SET_CPE1_XBM_IF_EITHER_EN
9556#undef SET_CPEU_XBM_IF_EITHER_EN
9557#undef SET_CPE2_XBM_IF_EITHER_EN
9558
9559 /*
9560 * Sanitize the control stuff.
9561 */
9562 pDbgState->fCpe2Extra &= pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1;
9563 if (pDbgState->fCpe2Extra)
9564 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL;
9565 pDbgState->fCpe1Extra &= pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1;
9566 pDbgState->fCpe1Unwanted &= ~pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0;
9567 if (pVCpu->hm.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
9568 {
9569 pVCpu->hm.s.fDebugWantRdTscExit ^= true;
9570 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
9571 }
9572
9573 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
9574 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
9575 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
9576 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
9577}
9578
9579
9580/**
9581 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
9582 * appropriate.
9583 *
9584 * The caller has checked the VM-exit against the
9585 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
9586 * already, so we don't have to do that either.
9587 *
9588 * @returns Strict VBox status code (i.e. informational status codes too).
9589 * @param pVM The cross context VM structure.
9590 * @param pVCpu The cross context virtual CPU structure.
9591 * @param pMixedCtx Pointer to the guest-CPU context.
9592 * @param pVmxTransient Pointer to the VMX-transient structure.
9593 * @param uExitReason The VM-exit reason.
9594 *
9595 * @remarks The name of this function is displayed by dtrace, so keep it short
9596 * and to the point. No longer than 33 chars long, please.
9597 */
9598static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx,
9599 PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
9600{
9601 /*
9602 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
9603 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
9604 *
9605 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
9606 * does. Must add/change/remove both places. Same ordering, please.
9607 *
9608 * Added/removed events must also be reflected in the next section
9609 * where we dispatch dtrace events.
9610 */
9611 bool fDtrace1 = false;
9612 bool fDtrace2 = false;
9613 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
9614 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
9615 uint32_t uEventArg = 0;
9616#define SET_EXIT(a_EventSubName) \
9617 do { \
9618 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
9619 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
9620 } while (0)
9621#define SET_BOTH(a_EventSubName) \
9622 do { \
9623 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
9624 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
9625 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
9626 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
9627 } while (0)
9628 switch (uExitReason)
9629 {
9630 case VMX_EXIT_MTF:
9631 return hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient);
9632
9633 case VMX_EXIT_XCPT_OR_NMI:
9634 {
9635 uint8_t const idxVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
9636 switch (VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo))
9637 {
9638 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT:
9639 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT:
9640 case VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT:
9641 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
9642 {
9643 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uExitIntInfo))
9644 {
9645 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
9646 uEventArg = pVmxTransient->uExitIntErrorCode;
9647 }
9648 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
9649 switch (enmEvent1)
9650 {
9651 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
9652 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
9653 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
9654 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
9655 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
9656 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
9657 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
9658 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
9659 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
9660 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
9661 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
9662 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
9663 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
9664 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
9665 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
9666 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
9667 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
9668 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
9669 default: break;
9670 }
9671 }
9672 else
9673 AssertFailed();
9674 break;
9675
9676 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT:
9677 uEventArg = idxVector;
9678 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
9679 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
9680 break;
9681 }
9682 break;
9683 }
9684
9685 case VMX_EXIT_TRIPLE_FAULT:
9686 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
9687 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
9688 break;
9689 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
9690 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
9691 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
9692 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
9693 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
9694
9695 /* Instruction specific VM-exits: */
9696 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
9697 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
9698 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
9699 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
9700 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
9701 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
9702 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
9703 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
9704 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
9705 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
9706 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
9707 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
9708 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
9709 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
9710 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
9711 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
9712 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
9713 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
9714 case VMX_EXIT_MOV_CRX:
9715 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9716/** @todo r=bird: I feel these macros aren't very descriptive and needs to be at least 30 chars longer! ;-)
9717* Sensible abbreviations strongly recommended here because even with 130 columns this stuff get too wide! */
9718 if ( VMX_EXIT_QUALIFICATION_CRX_ACCESS(pVmxTransient->uExitQualification)
9719 == VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ)
9720 SET_BOTH(CRX_READ);
9721 else
9722 SET_BOTH(CRX_WRITE);
9723 uEventArg = VMX_EXIT_QUALIFICATION_CRX_REGISTER(pVmxTransient->uExitQualification);
9724 break;
9725 case VMX_EXIT_MOV_DRX:
9726 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9727 if ( VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification)
9728 == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_READ)
9729 SET_BOTH(DRX_READ);
9730 else
9731 SET_BOTH(DRX_WRITE);
9732 uEventArg = VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification);
9733 break;
9734 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
9735 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
9736 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
9737 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
9738 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
9739 case VMX_EXIT_XDTR_ACCESS:
9740 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
9741 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_XDTR_INSINFO_INSTR_ID))
9742 {
9743 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
9744 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
9745 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
9746 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
9747 }
9748 break;
9749
9750 case VMX_EXIT_TR_ACCESS:
9751 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
9752 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_YYTR_INSINFO_INSTR_ID))
9753 {
9754 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
9755 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
9756 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
9757 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
9758 }
9759 break;
9760
9761 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
9762 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
9763 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
9764 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
9765 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
9766 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
9767 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
9768 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
9769 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
9770 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
9771 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
9772
9773 /* Events that aren't relevant at this point. */
9774 case VMX_EXIT_EXT_INT:
9775 case VMX_EXIT_INT_WINDOW:
9776 case VMX_EXIT_NMI_WINDOW:
9777 case VMX_EXIT_TPR_BELOW_THRESHOLD:
9778 case VMX_EXIT_PREEMPT_TIMER:
9779 case VMX_EXIT_IO_INSTR:
9780 break;
9781
9782 /* Errors and unexpected events. */
9783 case VMX_EXIT_INIT_SIGNAL:
9784 case VMX_EXIT_SIPI:
9785 case VMX_EXIT_IO_SMI:
9786 case VMX_EXIT_SMI:
9787 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
9788 case VMX_EXIT_ERR_MSR_LOAD:
9789 case VMX_EXIT_ERR_MACHINE_CHECK:
9790 break;
9791
9792 default:
9793 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
9794 break;
9795 }
9796#undef SET_BOTH
9797#undef SET_EXIT
9798
9799 /*
9800 * Dtrace tracepoints go first. We do them here at once so we don't
9801 * have to copy the guest state saving and stuff a few dozen times.
9802 * Down side is that we've got to repeat the switch, though this time
9803 * we use enmEvent since the probes are a subset of what DBGF does.
9804 */
9805 if (fDtrace1 || fDtrace2)
9806 {
9807 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9808 hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
9809 switch (enmEvent1)
9810 {
9811 /** @todo consider which extra parameters would be helpful for each probe. */
9812 case DBGFEVENT_END: break;
9813 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pMixedCtx); break;
9814 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pMixedCtx, pMixedCtx->dr[6]); break;
9815 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pMixedCtx); break;
9816 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pMixedCtx); break;
9817 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pMixedCtx); break;
9818 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pMixedCtx); break;
9819 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pMixedCtx); break;
9820 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pMixedCtx); break;
9821 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pMixedCtx, uEventArg); break;
9822 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pMixedCtx, uEventArg); break;
9823 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pMixedCtx, uEventArg); break;
9824 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pMixedCtx, uEventArg); break;
9825 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pMixedCtx, uEventArg, pMixedCtx->cr2); break;
9826 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pMixedCtx); break;
9827 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pMixedCtx); break;
9828 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pMixedCtx); break;
9829 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pMixedCtx); break;
9830 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pMixedCtx, uEventArg); break;
9831 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9832 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pMixedCtx, pMixedCtx->eax, pMixedCtx->ecx); break;
9833 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pMixedCtx); break;
9834 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pMixedCtx); break;
9835 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pMixedCtx); break;
9836 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pMixedCtx); break;
9837 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pMixedCtx); break;
9838 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pMixedCtx); break;
9839 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pMixedCtx); break;
9840 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9841 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9842 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9843 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9844 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pMixedCtx, pMixedCtx->ecx); break;
9845 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pMixedCtx, pMixedCtx->ecx,
9846 RT_MAKE_U64(pMixedCtx->eax, pMixedCtx->edx)); break;
9847 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pMixedCtx); break;
9848 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pMixedCtx); break;
9849 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pMixedCtx); break;
9850 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pMixedCtx); break;
9851 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pMixedCtx); break;
9852 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pMixedCtx); break;
9853 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pMixedCtx); break;
9854 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pMixedCtx); break;
9855 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pMixedCtx); break;
9856 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pMixedCtx); break;
9857 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pMixedCtx); break;
9858 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pMixedCtx); break;
9859 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pMixedCtx); break;
9860 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pMixedCtx); break;
9861 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pMixedCtx); break;
9862 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pMixedCtx); break;
9863 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pMixedCtx); break;
9864 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pMixedCtx); break;
9865 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pMixedCtx); break;
9866 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pMixedCtx); break;
9867 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pMixedCtx); break;
9868 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pMixedCtx); break;
9869 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pMixedCtx); break;
9870 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pMixedCtx); break;
9871 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pMixedCtx); break;
9872 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pMixedCtx); break;
9873 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pMixedCtx); break;
9874 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pMixedCtx); break;
9875 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pMixedCtx); break;
9876 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pMixedCtx); break;
9877 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pMixedCtx); break;
9878 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pMixedCtx); break;
9879 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
9880 }
9881 switch (enmEvent2)
9882 {
9883 /** @todo consider which extra parameters would be helpful for each probe. */
9884 case DBGFEVENT_END: break;
9885 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pMixedCtx); break;
9886 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pMixedCtx, pMixedCtx->eax, pMixedCtx->ecx); break;
9887 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pMixedCtx); break;
9888 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pMixedCtx); break;
9889 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pMixedCtx); break;
9890 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pMixedCtx); break;
9891 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pMixedCtx); break;
9892 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pMixedCtx); break;
9893 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pMixedCtx); break;
9894 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9895 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9896 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9897 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9898 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pMixedCtx, pMixedCtx->ecx); break;
9899 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pMixedCtx, pMixedCtx->ecx,
9900 RT_MAKE_U64(pMixedCtx->eax, pMixedCtx->edx)); break;
9901 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pMixedCtx); break;
9902 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pMixedCtx); break;
9903 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pMixedCtx); break;
9904 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pMixedCtx); break;
9905 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pMixedCtx); break;
9906 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pMixedCtx); break;
9907 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pMixedCtx); break;
9908 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pMixedCtx); break;
9909 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pMixedCtx); break;
9910 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pMixedCtx); break;
9911 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pMixedCtx); break;
9912 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pMixedCtx); break;
9913 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pMixedCtx); break;
9914 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pMixedCtx); break;
9915 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pMixedCtx); break;
9916 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pMixedCtx); break;
9917 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pMixedCtx); break;
9918 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pMixedCtx); break;
9919 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pMixedCtx); break;
9920 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pMixedCtx); break;
9921 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pMixedCtx); break;
9922 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pMixedCtx); break;
9923 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pMixedCtx); break;
9924 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pMixedCtx); break;
9925 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pMixedCtx); break;
9926 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pMixedCtx); break;
9927 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pMixedCtx); break;
9928 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pMixedCtx); break;
9929 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pMixedCtx); break;
9930 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pMixedCtx); break;
9931 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pMixedCtx); break;
9932 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pMixedCtx); break;
9933 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pMixedCtx); break;
9934 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pMixedCtx); break;
9935 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pMixedCtx); break;
9936 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pMixedCtx); break;
9937 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
9938 }
9939 }
9940
9941 /*
9942 * Fire of the DBGF event, if enabled (our check here is just a quick one,
9943 * the DBGF call will do a full check).
9944 *
9945 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
9946 * Note! If we have to events, we prioritize the first, i.e. the instruction
9947 * one, in order to avoid event nesting.
9948 */
9949 if ( enmEvent1 != DBGFEVENT_END
9950 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
9951 {
9952 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArg(pVM, pVCpu, enmEvent1, uEventArg, DBGFEVENTCTX_HM);
9953 if (rcStrict != VINF_SUCCESS)
9954 return rcStrict;
9955 }
9956 else if ( enmEvent2 != DBGFEVENT_END
9957 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
9958 {
9959 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArg(pVM, pVCpu, enmEvent2, uEventArg, DBGFEVENTCTX_HM);
9960 if (rcStrict != VINF_SUCCESS)
9961 return rcStrict;
9962 }
9963
9964 return VINF_SUCCESS;
9965}
9966
9967
9968/**
9969 * Single-stepping VM-exit filtering.
9970 *
9971 * This is preprocessing the VM-exits and deciding whether we've gotten far
9972 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
9973 * handling is performed.
9974 *
9975 * @returns Strict VBox status code (i.e. informational status codes too).
9976 * @param pVM The cross context VM structure.
9977 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
9978 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
9979 * out-of-sync. Make sure to update the required
9980 * fields before using them.
9981 * @param pVmxTransient Pointer to the VMX-transient structure.
9982 * @param uExitReason The VM-exit reason.
9983 * @param pDbgState The debug state.
9984 */
9985DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient,
9986 uint32_t uExitReason, PVMXRUNDBGSTATE pDbgState)
9987{
9988 /*
9989 * Expensive (saves context) generic dtrace VM-exit probe.
9990 */
9991 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
9992 { /* more likely */ }
9993 else
9994 {
9995 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9996 hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
9997 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, pMixedCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQualification);
9998 }
9999
10000 /*
10001 * Check for host NMI, just to get that out of the way.
10002 */
10003 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
10004 { /* normally likely */ }
10005 else
10006 {
10007 int rc2 = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
10008 AssertRCReturn(rc2, rc2);
10009 uint32_t uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo);
10010 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
10011 return hmR0VmxExitXcptOrNmi(pVCpu, pMixedCtx, pVmxTransient);
10012 }
10013
10014 /*
10015 * Check for single stepping event if we're stepping.
10016 */
10017 if (pVCpu->hm.s.fSingleInstruction)
10018 {
10019 switch (uExitReason)
10020 {
10021 case VMX_EXIT_MTF:
10022 return hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient);
10023
10024 /* Various events: */
10025 case VMX_EXIT_XCPT_OR_NMI:
10026 case VMX_EXIT_EXT_INT:
10027 case VMX_EXIT_TRIPLE_FAULT:
10028 case VMX_EXIT_INT_WINDOW:
10029 case VMX_EXIT_NMI_WINDOW:
10030 case VMX_EXIT_TASK_SWITCH:
10031 case VMX_EXIT_TPR_BELOW_THRESHOLD:
10032 case VMX_EXIT_APIC_ACCESS:
10033 case VMX_EXIT_EPT_VIOLATION:
10034 case VMX_EXIT_EPT_MISCONFIG:
10035 case VMX_EXIT_PREEMPT_TIMER:
10036
10037 /* Instruction specific VM-exits: */
10038 case VMX_EXIT_CPUID:
10039 case VMX_EXIT_GETSEC:
10040 case VMX_EXIT_HLT:
10041 case VMX_EXIT_INVD:
10042 case VMX_EXIT_INVLPG:
10043 case VMX_EXIT_RDPMC:
10044 case VMX_EXIT_RDTSC:
10045 case VMX_EXIT_RSM:
10046 case VMX_EXIT_VMCALL:
10047 case VMX_EXIT_VMCLEAR:
10048 case VMX_EXIT_VMLAUNCH:
10049 case VMX_EXIT_VMPTRLD:
10050 case VMX_EXIT_VMPTRST:
10051 case VMX_EXIT_VMREAD:
10052 case VMX_EXIT_VMRESUME:
10053 case VMX_EXIT_VMWRITE:
10054 case VMX_EXIT_VMXOFF:
10055 case VMX_EXIT_VMXON:
10056 case VMX_EXIT_MOV_CRX:
10057 case VMX_EXIT_MOV_DRX:
10058 case VMX_EXIT_IO_INSTR:
10059 case VMX_EXIT_RDMSR:
10060 case VMX_EXIT_WRMSR:
10061 case VMX_EXIT_MWAIT:
10062 case VMX_EXIT_MONITOR:
10063 case VMX_EXIT_PAUSE:
10064 case VMX_EXIT_XDTR_ACCESS:
10065 case VMX_EXIT_TR_ACCESS:
10066 case VMX_EXIT_INVEPT:
10067 case VMX_EXIT_RDTSCP:
10068 case VMX_EXIT_INVVPID:
10069 case VMX_EXIT_WBINVD:
10070 case VMX_EXIT_XSETBV:
10071 case VMX_EXIT_RDRAND:
10072 case VMX_EXIT_INVPCID:
10073 case VMX_EXIT_VMFUNC:
10074 case VMX_EXIT_RDSEED:
10075 case VMX_EXIT_XSAVES:
10076 case VMX_EXIT_XRSTORS:
10077 {
10078 int rc2 = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
10079 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
10080 AssertRCReturn(rc2, rc2);
10081 if ( pMixedCtx->rip != pDbgState->uRipStart
10082 || pMixedCtx->cs.Sel != pDbgState->uCsStart)
10083 return VINF_EM_DBG_STEPPED;
10084 break;
10085 }
10086
10087 /* Errors and unexpected events: */
10088 case VMX_EXIT_INIT_SIGNAL:
10089 case VMX_EXIT_SIPI:
10090 case VMX_EXIT_IO_SMI:
10091 case VMX_EXIT_SMI:
10092 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
10093 case VMX_EXIT_ERR_MSR_LOAD:
10094 case VMX_EXIT_ERR_MACHINE_CHECK:
10095 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
10096 break;
10097
10098 default:
10099 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
10100 break;
10101 }
10102 }
10103
10104 /*
10105 * Check for debugger event breakpoints and dtrace probes.
10106 */
10107 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
10108 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
10109 {
10110 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVM, pVCpu, pMixedCtx, pVmxTransient, uExitReason);
10111 if (rcStrict != VINF_SUCCESS)
10112 return rcStrict;
10113 }
10114
10115 /*
10116 * Normal processing.
10117 */
10118#ifdef HMVMX_USE_FUNCTION_TABLE
10119 return g_apfnVMExitHandlers[uExitReason](pVCpu, pMixedCtx, pVmxTransient);
10120#else
10121 return hmR0VmxHandleExit(pVCpu, pMixedCtx, pVmxTransient, uExitReason);
10122#endif
10123}
10124
10125
10126/**
10127 * Single steps guest code using VT-x.
10128 *
10129 * @returns Strict VBox status code (i.e. informational status codes too).
10130 * @param pVM The cross context VM structure.
10131 * @param pVCpu The cross context virtual CPU structure.
10132 * @param pCtx Pointer to the guest-CPU context.
10133 *
10134 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
10135 */
10136static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10137{
10138 VMXTRANSIENT VmxTransient;
10139 VmxTransient.fUpdateTscOffsettingAndPreemptTimer = true;
10140
10141 /* Set HMCPU indicators. */
10142 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
10143 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
10144 pVCpu->hm.s.fDebugWantRdTscExit = false;
10145 pVCpu->hm.s.fUsingDebugLoop = true;
10146
10147 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
10148 VMXRUNDBGSTATE DbgState;
10149 hmR0VmxRunDebugStateInit(pVCpu, pCtx, &DbgState);
10150 hmR0VmxPreRunGuestDebugStateUpdate(pVM, pVCpu, pCtx, &DbgState, &VmxTransient);
10151
10152 /*
10153 * The loop.
10154 */
10155 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10156 for (uint32_t cLoops = 0; ; cLoops++)
10157 {
10158 Assert(!HMR0SuspendPending());
10159 HMVMX_ASSERT_CPU_SAFE();
10160 bool fStepping = pVCpu->hm.s.fSingleInstruction;
10161
10162 /*
10163 * Preparatory work for running guest code, this may force us to return
10164 * to ring-3. This bugger disables interrupts on VINF_SUCCESS!
10165 */
10166 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10167 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &DbgState); /* Set up execute controls the next to can respond to. */
10168 rcStrict = hmR0VmxPreRunGuest(pVM, pVCpu, pCtx, &VmxTransient, fStepping);
10169 if (rcStrict != VINF_SUCCESS)
10170 break;
10171
10172 hmR0VmxPreRunGuestCommitted(pVM, pVCpu, pCtx, &VmxTransient);
10173 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &DbgState); /* Override any obnoxious code in the above two calls. */
10174
10175 /*
10176 * Now we can run the guest code.
10177 */
10178 int rcRun = hmR0VmxRunGuest(pVM, pVCpu, pCtx);
10179
10180 /* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
10181
10182 /*
10183 * Restore any residual host-state and save any bits shared between host
10184 * and guest into the guest-CPU state. Re-enables interrupts!
10185 */
10186 hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, rcRun);
10187
10188 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
10189 if (RT_SUCCESS(rcRun))
10190 { /* very likely */ }
10191 else
10192 {
10193 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
10194 hmR0VmxReportWorldSwitchError(pVM, pVCpu, rcRun, pCtx, &VmxTransient);
10195 return rcRun;
10196 }
10197
10198 /* Profile the VM-exit. */
10199 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10200 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10201 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10202 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
10203 HMVMX_START_EXIT_DISPATCH_PROF();
10204
10205 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, pCtx, VmxTransient.uExitReason);
10206
10207 /*
10208 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
10209 */
10210 rcStrict = hmR0VmxRunDebugHandleExit(pVM, pVCpu, pCtx, &VmxTransient, VmxTransient.uExitReason, &DbgState);
10211 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
10212 if (rcStrict != VINF_SUCCESS)
10213 break;
10214 if (cLoops > pVM->hm.s.cMaxResumeLoops)
10215 {
10216 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10217 rcStrict = VINF_EM_RAW_INTERRUPT;
10218 break;
10219 }
10220
10221 /*
10222 * Stepping: Did the RIP change, if so, consider it a single step.
10223 * Otherwise, make sure one of the TFs gets set.
10224 */
10225 if (fStepping)
10226 {
10227 int rc2 = hmR0VmxSaveGuestRip(pVCpu, pCtx);
10228 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pCtx);
10229 AssertRCReturn(rc2, rc2);
10230 if ( pCtx->rip != DbgState.uRipStart
10231 || pCtx->cs.Sel != DbgState.uCsStart)
10232 {
10233 rcStrict = VINF_EM_DBG_STEPPED;
10234 break;
10235 }
10236 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
10237 }
10238
10239 /*
10240 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
10241 */
10242 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
10243 hmR0VmxPreRunGuestDebugStateUpdate(pVM, pVCpu, pCtx, &DbgState, &VmxTransient);
10244 }
10245
10246 /*
10247 * Clear the X86_EFL_TF if necessary.
10248 */
10249 if (pVCpu->hm.s.fClearTrapFlag)
10250 {
10251 int rc2 = hmR0VmxSaveGuestRflags(pVCpu, pCtx);
10252 AssertRCReturn(rc2, rc2);
10253 pVCpu->hm.s.fClearTrapFlag = false;
10254 pCtx->eflags.Bits.u1TF = 0;
10255 }
10256 /** @todo there seems to be issues with the resume flag when the monitor trap
10257 * flag is pending without being used. Seen early in bios init when
10258 * accessing APIC page in protected mode. */
10259
10260 /*
10261 * Restore VM-exit control settings as we may not reenter this function the
10262 * next time around.
10263 */
10264 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &DbgState, rcStrict);
10265
10266 /* Restore HMCPU indicators. */
10267 pVCpu->hm.s.fUsingDebugLoop = false;
10268 pVCpu->hm.s.fDebugWantRdTscExit = false;
10269 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
10270
10271 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10272 return rcStrict;
10273}
10274
10275
10276/** @} */
10277
10278
10279/**
10280 * Checks if any expensive dtrace probes are enabled and we should go to the
10281 * debug loop.
10282 *
10283 * @returns true if we should use debug loop, false if not.
10284 */
10285static bool hmR0VmxAnyExpensiveProbesEnabled(void)
10286{
10287 /* It's probably faster to OR the raw 32-bit counter variables together.
10288 Since the variables are in an array and the probes are next to one
10289 another (more or less), we have good locality. So, better read
10290 eight-nine cache lines ever time and only have one conditional, than
10291 128+ conditionals, right? */
10292 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
10293 | VBOXVMM_XCPT_DE_ENABLED_RAW()
10294 | VBOXVMM_XCPT_DB_ENABLED_RAW()
10295 | VBOXVMM_XCPT_BP_ENABLED_RAW()
10296 | VBOXVMM_XCPT_OF_ENABLED_RAW()
10297 | VBOXVMM_XCPT_BR_ENABLED_RAW()
10298 | VBOXVMM_XCPT_UD_ENABLED_RAW()
10299 | VBOXVMM_XCPT_NM_ENABLED_RAW()
10300 | VBOXVMM_XCPT_DF_ENABLED_RAW()
10301 | VBOXVMM_XCPT_TS_ENABLED_RAW()
10302 | VBOXVMM_XCPT_NP_ENABLED_RAW()
10303 | VBOXVMM_XCPT_SS_ENABLED_RAW()
10304 | VBOXVMM_XCPT_GP_ENABLED_RAW()
10305 | VBOXVMM_XCPT_PF_ENABLED_RAW()
10306 | VBOXVMM_XCPT_MF_ENABLED_RAW()
10307 | VBOXVMM_XCPT_AC_ENABLED_RAW()
10308 | VBOXVMM_XCPT_XF_ENABLED_RAW()
10309 | VBOXVMM_XCPT_VE_ENABLED_RAW()
10310 | VBOXVMM_XCPT_SX_ENABLED_RAW()
10311 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
10312 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
10313 ) != 0
10314 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
10315 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
10316 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
10317 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
10318 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
10319 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
10320 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
10321 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
10322 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
10323 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
10324 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
10325 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
10326 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
10327 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
10328 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
10329 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
10330 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
10331 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
10332 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
10333 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
10334 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
10335 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
10336 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
10337 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
10338 | VBOXVMM_INSTR_STR_ENABLED_RAW()
10339 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
10340 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
10341 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
10342 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
10343 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
10344 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
10345 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
10346 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
10347 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
10348 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
10349 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
10350 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
10351 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
10352 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
10353 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
10354 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
10355 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
10356 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
10357 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
10358 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
10359 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
10360 ) != 0
10361 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
10362 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
10363 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
10364 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
10365 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
10366 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
10367 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
10368 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
10369 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
10370 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
10371 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
10372 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
10373 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
10374 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
10375 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
10376 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
10377 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
10378 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
10379 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
10380 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
10381 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
10382 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
10383 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
10384 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
10385 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
10386 | VBOXVMM_EXIT_STR_ENABLED_RAW()
10387 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
10388 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
10389 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
10390 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
10391 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
10392 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
10393 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
10394 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
10395 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
10396 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
10397 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
10398 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
10399 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
10400 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
10401 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
10402 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
10403 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
10404 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
10405 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
10406 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
10407 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
10408 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
10409 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
10410 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
10411 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
10412 ) != 0;
10413}
10414
10415
10416/**
10417 * Runs the guest code using VT-x.
10418 *
10419 * @returns Strict VBox status code (i.e. informational status codes too).
10420 * @param pVM The cross context VM structure.
10421 * @param pVCpu The cross context virtual CPU structure.
10422 * @param pCtx Pointer to the guest-CPU context.
10423 */
10424VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10425{
10426 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10427 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
10428 HMVMX_ASSERT_PREEMPT_SAFE();
10429
10430 VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pCtx);
10431
10432 VBOXSTRICTRC rcStrict;
10433 if ( !pVCpu->hm.s.fUseDebugLoop
10434 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
10435 && !DBGFIsStepping(pVCpu)
10436 && !pVM->dbgf.ro.cEnabledInt3Breakpoints)
10437 rcStrict = hmR0VmxRunGuestCodeNormal(pVM, pVCpu, pCtx);
10438 else
10439 rcStrict = hmR0VmxRunGuestCodeDebug(pVM, pVCpu, pCtx);
10440
10441 if (rcStrict == VERR_EM_INTERPRETER)
10442 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
10443 else if (rcStrict == VINF_EM_RESET)
10444 rcStrict = VINF_EM_TRIPLE_FAULT;
10445
10446 int rc2 = hmR0VmxExitToRing3(pVM, pVCpu, pCtx, rcStrict);
10447 if (RT_FAILURE(rc2))
10448 {
10449 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
10450 rcStrict = rc2;
10451 }
10452 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
10453 return rcStrict;
10454}
10455
10456
10457#ifndef HMVMX_USE_FUNCTION_TABLE
10458DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason)
10459{
10460# ifdef DEBUG_ramshankar
10461# define RETURN_EXIT_CALL(a_CallExpr) \
10462 do { \
10463 int rc2 = hmR0VmxSaveGuestState(pVCpu, pMixedCtx); AssertRC(rc2); \
10464 VBOXSTRICTRC rcStrict = a_CallExpr; \
10465 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST); \
10466 return rcStrict; \
10467 } while (0)
10468# else
10469# define RETURN_EXIT_CALL(a_CallExpr) return a_CallExpr
10470# endif
10471 switch (rcReason)
10472 {
10473 case VMX_EXIT_EPT_MISCONFIG: RETURN_EXIT_CALL(hmR0VmxExitEptMisconfig(pVCpu, pMixedCtx, pVmxTransient));
10474 case VMX_EXIT_EPT_VIOLATION: RETURN_EXIT_CALL(hmR0VmxExitEptViolation(pVCpu, pMixedCtx, pVmxTransient));
10475 case VMX_EXIT_IO_INSTR: RETURN_EXIT_CALL(hmR0VmxExitIoInstr(pVCpu, pMixedCtx, pVmxTransient));
10476 case VMX_EXIT_CPUID: RETURN_EXIT_CALL(hmR0VmxExitCpuid(pVCpu, pMixedCtx, pVmxTransient));
10477 case VMX_EXIT_RDTSC: RETURN_EXIT_CALL(hmR0VmxExitRdtsc(pVCpu, pMixedCtx, pVmxTransient));
10478 case VMX_EXIT_RDTSCP: RETURN_EXIT_CALL(hmR0VmxExitRdtscp(pVCpu, pMixedCtx, pVmxTransient));
10479 case VMX_EXIT_APIC_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitApicAccess(pVCpu, pMixedCtx, pVmxTransient));
10480 case VMX_EXIT_XCPT_OR_NMI: RETURN_EXIT_CALL(hmR0VmxExitXcptOrNmi(pVCpu, pMixedCtx, pVmxTransient));
10481 case VMX_EXIT_MOV_CRX: RETURN_EXIT_CALL(hmR0VmxExitMovCRx(pVCpu, pMixedCtx, pVmxTransient));
10482 case VMX_EXIT_EXT_INT: RETURN_EXIT_CALL(hmR0VmxExitExtInt(pVCpu, pMixedCtx, pVmxTransient));
10483 case VMX_EXIT_INT_WINDOW: RETURN_EXIT_CALL(hmR0VmxExitIntWindow(pVCpu, pMixedCtx, pVmxTransient));
10484 case VMX_EXIT_MWAIT: RETURN_EXIT_CALL(hmR0VmxExitMwait(pVCpu, pMixedCtx, pVmxTransient));
10485 case VMX_EXIT_MONITOR: RETURN_EXIT_CALL(hmR0VmxExitMonitor(pVCpu, pMixedCtx, pVmxTransient));
10486 case VMX_EXIT_TASK_SWITCH: RETURN_EXIT_CALL(hmR0VmxExitTaskSwitch(pVCpu, pMixedCtx, pVmxTransient));
10487 case VMX_EXIT_PREEMPT_TIMER: RETURN_EXIT_CALL(hmR0VmxExitPreemptTimer(pVCpu, pMixedCtx, pVmxTransient));
10488 case VMX_EXIT_RDMSR: RETURN_EXIT_CALL(hmR0VmxExitRdmsr(pVCpu, pMixedCtx, pVmxTransient));
10489 case VMX_EXIT_WRMSR: RETURN_EXIT_CALL(hmR0VmxExitWrmsr(pVCpu, pMixedCtx, pVmxTransient));
10490 case VMX_EXIT_MOV_DRX: RETURN_EXIT_CALL(hmR0VmxExitMovDRx(pVCpu, pMixedCtx, pVmxTransient));
10491 case VMX_EXIT_TPR_BELOW_THRESHOLD: RETURN_EXIT_CALL(hmR0VmxExitTprBelowThreshold(pVCpu, pMixedCtx, pVmxTransient));
10492 case VMX_EXIT_HLT: RETURN_EXIT_CALL(hmR0VmxExitHlt(pVCpu, pMixedCtx, pVmxTransient));
10493 case VMX_EXIT_INVD: RETURN_EXIT_CALL(hmR0VmxExitInvd(pVCpu, pMixedCtx, pVmxTransient));
10494 case VMX_EXIT_INVLPG: RETURN_EXIT_CALL(hmR0VmxExitInvlpg(pVCpu, pMixedCtx, pVmxTransient));
10495 case VMX_EXIT_RSM: RETURN_EXIT_CALL(hmR0VmxExitRsm(pVCpu, pMixedCtx, pVmxTransient));
10496 case VMX_EXIT_MTF: RETURN_EXIT_CALL(hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient));
10497 case VMX_EXIT_PAUSE: RETURN_EXIT_CALL(hmR0VmxExitPause(pVCpu, pMixedCtx, pVmxTransient));
10498 case VMX_EXIT_XDTR_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient));
10499 case VMX_EXIT_TR_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient));
10500 case VMX_EXIT_WBINVD: RETURN_EXIT_CALL(hmR0VmxExitWbinvd(pVCpu, pMixedCtx, pVmxTransient));
10501 case VMX_EXIT_XSETBV: RETURN_EXIT_CALL(hmR0VmxExitXsetbv(pVCpu, pMixedCtx, pVmxTransient));
10502 case VMX_EXIT_RDRAND: RETURN_EXIT_CALL(hmR0VmxExitRdrand(pVCpu, pMixedCtx, pVmxTransient));
10503 case VMX_EXIT_INVPCID: RETURN_EXIT_CALL(hmR0VmxExitInvpcid(pVCpu, pMixedCtx, pVmxTransient));
10504 case VMX_EXIT_GETSEC: RETURN_EXIT_CALL(hmR0VmxExitGetsec(pVCpu, pMixedCtx, pVmxTransient));
10505 case VMX_EXIT_RDPMC: RETURN_EXIT_CALL(hmR0VmxExitRdpmc(pVCpu, pMixedCtx, pVmxTransient));
10506 case VMX_EXIT_VMCALL: RETURN_EXIT_CALL(hmR0VmxExitVmcall(pVCpu, pMixedCtx, pVmxTransient));
10507
10508 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pMixedCtx, pVmxTransient);
10509 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pMixedCtx, pVmxTransient);
10510 case VMX_EXIT_INIT_SIGNAL: return hmR0VmxExitInitSignal(pVCpu, pMixedCtx, pVmxTransient);
10511 case VMX_EXIT_SIPI: return hmR0VmxExitSipi(pVCpu, pMixedCtx, pVmxTransient);
10512 case VMX_EXIT_IO_SMI: return hmR0VmxExitIoSmi(pVCpu, pMixedCtx, pVmxTransient);
10513 case VMX_EXIT_SMI: return hmR0VmxExitSmi(pVCpu, pMixedCtx, pVmxTransient);
10514 case VMX_EXIT_ERR_MSR_LOAD: return hmR0VmxExitErrMsrLoad(pVCpu, pMixedCtx, pVmxTransient);
10515 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pMixedCtx, pVmxTransient);
10516 case VMX_EXIT_ERR_MACHINE_CHECK: return hmR0VmxExitErrMachineCheck(pVCpu, pMixedCtx, pVmxTransient);
10517
10518 case VMX_EXIT_VMCLEAR:
10519 case VMX_EXIT_VMLAUNCH:
10520 case VMX_EXIT_VMPTRLD:
10521 case VMX_EXIT_VMPTRST:
10522 case VMX_EXIT_VMREAD:
10523 case VMX_EXIT_VMRESUME:
10524 case VMX_EXIT_VMWRITE:
10525 case VMX_EXIT_VMXOFF:
10526 case VMX_EXIT_VMXON:
10527 case VMX_EXIT_INVEPT:
10528 case VMX_EXIT_INVVPID:
10529 case VMX_EXIT_VMFUNC:
10530 case VMX_EXIT_XSAVES:
10531 case VMX_EXIT_XRSTORS:
10532 return hmR0VmxExitSetPendingXcptUD(pVCpu, pMixedCtx, pVmxTransient);
10533 case VMX_EXIT_ENCLS:
10534 case VMX_EXIT_RDSEED: /* only spurious VM-exits, so undefined */
10535 case VMX_EXIT_PML_FULL:
10536 default:
10537 return hmR0VmxExitErrUndefined(pVCpu, pMixedCtx, pVmxTransient);
10538 }
10539#undef RETURN_EXIT_CALL
10540}
10541#endif /* !HMVMX_USE_FUNCTION_TABLE */
10542
10543
10544#ifdef VBOX_STRICT
10545/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
10546# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
10547 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
10548
10549# define HMVMX_ASSERT_PREEMPT_CPUID() \
10550 do { \
10551 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
10552 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
10553 } while (0)
10554
10555# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS() \
10556 do { \
10557 AssertPtr(pVCpu); \
10558 AssertPtr(pMixedCtx); \
10559 AssertPtr(pVmxTransient); \
10560 Assert(pVmxTransient->fVMEntryFailed == false); \
10561 Assert(ASMIntAreEnabled()); \
10562 HMVMX_ASSERT_PREEMPT_SAFE(); \
10563 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
10564 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)); \
10565 HMVMX_ASSERT_PREEMPT_SAFE(); \
10566 if (VMMR0IsLogFlushDisabled(pVCpu)) \
10567 HMVMX_ASSERT_PREEMPT_CPUID(); \
10568 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
10569 } while (0)
10570
10571# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() \
10572 do { \
10573 Log4Func(("\n")); \
10574 } while (0)
10575#else /* nonstrict builds: */
10576# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS() \
10577 do { \
10578 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
10579 NOREF(pVCpu); NOREF(pMixedCtx); NOREF(pVmxTransient); \
10580 } while (0)
10581# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() do { } while (0)
10582#endif
10583
10584
10585/**
10586 * Advances the guest RIP by the specified number of bytes.
10587 *
10588 * @param pVCpu The cross context virtual CPU structure.
10589 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
10590 * out-of-sync. Make sure to update the required fields
10591 * before using them.
10592 * @param cbInstr Number of bytes to advance the RIP by.
10593 *
10594 * @remarks No-long-jump zone!!!
10595 */
10596DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
10597{
10598 /* Advance the RIP. */
10599 pMixedCtx->rip += cbInstr;
10600 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
10601
10602 /* Update interrupt inhibition. */
10603 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
10604 && pMixedCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
10605 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
10606}
10607
10608
10609/**
10610 * Advances the guest RIP after reading it from the VMCS.
10611 *
10612 * @returns VBox status code, no informational status codes.
10613 * @param pVCpu The cross context virtual CPU structure.
10614 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
10615 * out-of-sync. Make sure to update the required fields
10616 * before using them.
10617 * @param pVmxTransient Pointer to the VMX transient structure.
10618 *
10619 * @remarks No-long-jump zone!!!
10620 */
10621static int hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
10622{
10623 int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
10624 rc |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
10625 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
10626 AssertRCReturn(rc, rc);
10627
10628 hmR0VmxAdvanceGuestRipBy(pVCpu, pMixedCtx, pVmxTransient->cbInstr);
10629
10630 /*
10631 * Deliver a debug exception to the guest if it is single-stepping. Don't directly inject a #DB but use the
10632 * pending debug exception field as it takes care of priority of events.
10633 *
10634 * See Intel spec. 32.2.1 "Debug Exceptions".
10635 */
10636 if ( !pVCpu->hm.s.fSingleInstruction
10637 && pMixedCtx->eflags.Bits.u1TF)
10638 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
10639
10640 return VINF_SUCCESS;
10641}
10642
10643
10644/**
10645 * Tries to determine what part of the guest-state VT-x has deemed as invalid
10646 * and update error record fields accordingly.
10647 *
10648 * @return VMX_IGS_* return codes.
10649 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
10650 * wrong with the guest state.
10651 *
10652 * @param pVM The cross context VM structure.
10653 * @param pVCpu The cross context virtual CPU structure.
10654 * @param pCtx Pointer to the guest-CPU state.
10655 *
10656 * @remarks This function assumes our cache of the VMCS controls
10657 * are valid, i.e. hmR0VmxCheckVmcsCtls() succeeded.
10658 */
10659static uint32_t hmR0VmxCheckGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10660{
10661#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
10662#define HMVMX_CHECK_BREAK(expr, err) if (!(expr)) { \
10663 uError = (err); \
10664 break; \
10665 } else do { } while (0)
10666
10667 int rc;
10668 uint32_t uError = VMX_IGS_ERROR;
10669 uint32_t u32Val;
10670 bool fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuest;
10671
10672 do
10673 {
10674 /*
10675 * CR0.
10676 */
10677 uint32_t uSetCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
10678 uint32_t uZapCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
10679 /* Exceptions for unrestricted-guests for fixed CR0 bits (PE, PG).
10680 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
10681 if (fUnrestrictedGuest)
10682 uSetCR0 &= ~(X86_CR0_PE | X86_CR0_PG);
10683
10684 uint32_t u32GuestCR0;
10685 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32GuestCR0);
10686 AssertRCBreak(rc);
10687 HMVMX_CHECK_BREAK((u32GuestCR0 & uSetCR0) == uSetCR0, VMX_IGS_CR0_FIXED1);
10688 HMVMX_CHECK_BREAK(!(u32GuestCR0 & ~uZapCR0), VMX_IGS_CR0_FIXED0);
10689 if ( !fUnrestrictedGuest
10690 && (u32GuestCR0 & X86_CR0_PG)
10691 && !(u32GuestCR0 & X86_CR0_PE))
10692 {
10693 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
10694 }
10695
10696 /*
10697 * CR4.
10698 */
10699 uint64_t uSetCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
10700 uint64_t uZapCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
10701
10702 uint32_t u32GuestCR4;
10703 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &u32GuestCR4);
10704 AssertRCBreak(rc);
10705 HMVMX_CHECK_BREAK((u32GuestCR4 & uSetCR4) == uSetCR4, VMX_IGS_CR4_FIXED1);
10706 HMVMX_CHECK_BREAK(!(u32GuestCR4 & ~uZapCR4), VMX_IGS_CR4_FIXED0);
10707
10708 /*
10709 * IA32_DEBUGCTL MSR.
10710 */
10711 uint64_t u64Val;
10712 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
10713 AssertRCBreak(rc);
10714 if ( (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
10715 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
10716 {
10717 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
10718 }
10719 uint64_t u64DebugCtlMsr = u64Val;
10720
10721#ifdef VBOX_STRICT
10722 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
10723 AssertRCBreak(rc);
10724 Assert(u32Val == pVCpu->hm.s.vmx.u32EntryCtls);
10725#endif
10726 bool const fLongModeGuest = RT_BOOL(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST);
10727
10728 /*
10729 * RIP and RFLAGS.
10730 */
10731 uint32_t u32Eflags;
10732#if HC_ARCH_BITS == 64
10733 rc = VMXReadVmcs64(VMX_VMCS_GUEST_RIP, &u64Val);
10734 AssertRCBreak(rc);
10735 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
10736 if ( !fLongModeGuest
10737 || !pCtx->cs.Attr.n.u1Long)
10738 {
10739 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
10740 }
10741 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
10742 * must be identical if the "IA-32e mode guest" VM-entry
10743 * control is 1 and CS.L is 1. No check applies if the
10744 * CPU supports 64 linear-address bits. */
10745
10746 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
10747 rc = VMXReadVmcs64(VMX_VMCS_GUEST_RFLAGS, &u64Val);
10748 AssertRCBreak(rc);
10749 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
10750 VMX_IGS_RFLAGS_RESERVED);
10751 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
10752 u32Eflags = u64Val;
10753#else
10754 rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &u32Eflags);
10755 AssertRCBreak(rc);
10756 HMVMX_CHECK_BREAK(!(u32Eflags & 0xffc08028), VMX_IGS_RFLAGS_RESERVED); /* Bit 31:22, Bit 15, 5, 3 MBZ. */
10757 HMVMX_CHECK_BREAK((u32Eflags & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
10758#endif
10759
10760 if ( fLongModeGuest
10761 || ( fUnrestrictedGuest
10762 && !(u32GuestCR0 & X86_CR0_PE)))
10763 {
10764 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
10765 }
10766
10767 uint32_t u32EntryInfo;
10768 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
10769 AssertRCBreak(rc);
10770 if ( VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo)
10771 && VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
10772 {
10773 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
10774 }
10775
10776 /*
10777 * 64-bit checks.
10778 */
10779#if HC_ARCH_BITS == 64
10780 if (fLongModeGuest)
10781 {
10782 HMVMX_CHECK_BREAK(u32GuestCR0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
10783 HMVMX_CHECK_BREAK(u32GuestCR4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
10784 }
10785
10786 if ( !fLongModeGuest
10787 && (u32GuestCR4 & X86_CR4_PCIDE))
10788 {
10789 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
10790 }
10791
10792 /** @todo CR3 field must be such that bits 63:52 and bits in the range
10793 * 51:32 beyond the processor's physical-address width are 0. */
10794
10795 if ( (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
10796 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
10797 {
10798 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
10799 }
10800
10801 rc = VMXReadVmcs64(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
10802 AssertRCBreak(rc);
10803 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
10804
10805 rc = VMXReadVmcs64(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
10806 AssertRCBreak(rc);
10807 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
10808#endif
10809
10810 /*
10811 * PERF_GLOBAL MSR.
10812 */
10813 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PERF_MSR)
10814 {
10815 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
10816 AssertRCBreak(rc);
10817 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
10818 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
10819 }
10820
10821 /*
10822 * PAT MSR.
10823 */
10824 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PAT_MSR)
10825 {
10826 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
10827 AssertRCBreak(rc);
10828 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
10829 for (unsigned i = 0; i < 8; i++)
10830 {
10831 uint8_t u8Val = (u64Val & 0xff);
10832 if ( u8Val != 0 /* UC */
10833 && u8Val != 1 /* WC */
10834 && u8Val != 4 /* WT */
10835 && u8Val != 5 /* WP */
10836 && u8Val != 6 /* WB */
10837 && u8Val != 7 /* UC- */)
10838 {
10839 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
10840 }
10841 u64Val >>= 8;
10842 }
10843 }
10844
10845 /*
10846 * EFER MSR.
10847 */
10848 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR)
10849 {
10850 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
10851 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
10852 AssertRCBreak(rc);
10853 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
10854 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
10855 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVCpu->hm.s.vmx.u32EntryCtls
10856 & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST),
10857 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
10858 HMVMX_CHECK_BREAK( fUnrestrictedGuest
10859 || !(u32GuestCR0 & X86_CR0_PG)
10860 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
10861 VMX_IGS_EFER_LMA_LME_MISMATCH);
10862 }
10863
10864 /*
10865 * Segment registers.
10866 */
10867 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10868 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
10869 if (!(u32Eflags & X86_EFL_VM))
10870 {
10871 /* CS */
10872 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
10873 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
10874 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
10875 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
10876 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
10877 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
10878 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
10879 /* CS cannot be loaded with NULL in protected mode. */
10880 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
10881 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
10882 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
10883 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
10884 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
10885 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
10886 else if (pVM->hm.s.vmx.fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
10887 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
10888 else
10889 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
10890
10891 /* SS */
10892 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10893 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
10894 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
10895 if ( !(pCtx->cr0 & X86_CR0_PE)
10896 || pCtx->cs.Attr.n.u4Type == 3)
10897 {
10898 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
10899 }
10900 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
10901 {
10902 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
10903 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
10904 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
10905 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
10906 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
10907 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
10908 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
10909 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
10910 }
10911
10912 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxWriteSegmentReg(). */
10913 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
10914 {
10915 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
10916 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
10917 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10918 || pCtx->ds.Attr.n.u4Type > 11
10919 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
10920 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
10921 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
10922 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
10923 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
10924 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
10925 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
10926 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10927 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
10928 }
10929 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
10930 {
10931 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
10932 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
10933 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10934 || pCtx->es.Attr.n.u4Type > 11
10935 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
10936 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
10937 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
10938 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
10939 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
10940 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
10941 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
10942 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10943 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
10944 }
10945 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
10946 {
10947 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
10948 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
10949 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10950 || pCtx->fs.Attr.n.u4Type > 11
10951 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
10952 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
10953 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
10954 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
10955 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
10956 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
10957 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
10958 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10959 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
10960 }
10961 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
10962 {
10963 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
10964 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
10965 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10966 || pCtx->gs.Attr.n.u4Type > 11
10967 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
10968 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
10969 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
10970 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
10971 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10972 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
10973 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10974 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10975 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
10976 }
10977 /* 64-bit capable CPUs. */
10978#if HC_ARCH_BITS == 64
10979 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10980 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10981 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10982 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10983 HMVMX_CHECK_BREAK(!(pCtx->cs.u64Base >> 32), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10984 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ss.u64Base >> 32),
10985 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10986 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ds.u64Base >> 32),
10987 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10988 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->es.u64Base >> 32),
10989 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10990#endif
10991 }
10992 else
10993 {
10994 /* V86 mode checks. */
10995 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
10996 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
10997 {
10998 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
10999 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
11000 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
11001 }
11002 else
11003 {
11004 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
11005 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
11006 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
11007 }
11008
11009 /* CS */
11010 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
11011 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
11012 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
11013 /* SS */
11014 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
11015 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
11016 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
11017 /* DS */
11018 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
11019 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
11020 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
11021 /* ES */
11022 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
11023 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
11024 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
11025 /* FS */
11026 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
11027 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
11028 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
11029 /* GS */
11030 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
11031 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
11032 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
11033 /* 64-bit capable CPUs. */
11034#if HC_ARCH_BITS == 64
11035 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
11036 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
11037 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
11038 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
11039 HMVMX_CHECK_BREAK(!(pCtx->cs.u64Base >> 32), VMX_IGS_LONGMODE_CS_BASE_INVALID);
11040 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ss.u64Base >> 32),
11041 VMX_IGS_LONGMODE_SS_BASE_INVALID);
11042 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ds.u64Base >> 32),
11043 VMX_IGS_LONGMODE_DS_BASE_INVALID);
11044 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->es.u64Base >> 32),
11045 VMX_IGS_LONGMODE_ES_BASE_INVALID);
11046#endif
11047 }
11048
11049 /*
11050 * TR.
11051 */
11052 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
11053 /* 64-bit capable CPUs. */
11054#if HC_ARCH_BITS == 64
11055 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
11056#endif
11057 if (fLongModeGuest)
11058 {
11059 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
11060 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
11061 }
11062 else
11063 {
11064 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
11065 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
11066 VMX_IGS_TR_ATTR_TYPE_INVALID);
11067 }
11068 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
11069 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
11070 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
11071 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
11072 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
11073 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
11074 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
11075 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
11076
11077 /*
11078 * GDTR and IDTR.
11079 */
11080#if HC_ARCH_BITS == 64
11081 rc = VMXReadVmcs64(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
11082 AssertRCBreak(rc);
11083 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
11084
11085 rc = VMXReadVmcs64(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
11086 AssertRCBreak(rc);
11087 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
11088#endif
11089
11090 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
11091 AssertRCBreak(rc);
11092 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
11093
11094 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
11095 AssertRCBreak(rc);
11096 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
11097
11098 /*
11099 * Guest Non-Register State.
11100 */
11101 /* Activity State. */
11102 uint32_t u32ActivityState;
11103 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
11104 AssertRCBreak(rc);
11105 HMVMX_CHECK_BREAK( !u32ActivityState
11106 || (u32ActivityState & MSR_IA32_VMX_MISC_ACTIVITY_STATES(pVM->hm.s.vmx.Msrs.u64Misc)),
11107 VMX_IGS_ACTIVITY_STATE_INVALID);
11108 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
11109 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
11110 uint32_t u32IntrState;
11111 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &u32IntrState);
11112 AssertRCBreak(rc);
11113 if ( u32IntrState == VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS
11114 || u32IntrState == VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
11115 {
11116 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
11117 }
11118
11119 /** @todo Activity state and injecting interrupts. Left as a todo since we
11120 * currently don't use activity states but ACTIVE. */
11121
11122 HMVMX_CHECK_BREAK( !(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_ENTRY_SMM)
11123 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
11124
11125 /* Guest interruptibility-state. */
11126 HMVMX_CHECK_BREAK(!(u32IntrState & 0xfffffff0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
11127 HMVMX_CHECK_BREAK((u32IntrState & ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI
11128 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS))
11129 != ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI
11130 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
11131 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
11132 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
11133 || !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI),
11134 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
11135 if (VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo))
11136 {
11137 if (VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
11138 {
11139 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
11140 && !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
11141 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
11142 }
11143 else if (VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11144 {
11145 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
11146 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
11147 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI),
11148 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
11149 }
11150 }
11151 /** @todo Assumes the processor is not in SMM. */
11152 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI),
11153 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
11154 HMVMX_CHECK_BREAK( !(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_ENTRY_SMM)
11155 || (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI),
11156 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
11157 if ( (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
11158 && VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo)
11159 && VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11160 {
11161 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI),
11162 VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
11163 }
11164
11165 /* Pending debug exceptions. */
11166#if HC_ARCH_BITS == 64
11167 rc = VMXReadVmcs64(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, &u64Val);
11168 AssertRCBreak(rc);
11169 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
11170 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
11171 u32Val = u64Val; /* For pending debug exceptions checks below. */
11172#else
11173 rc = VMXReadVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, &u32Val);
11174 AssertRCBreak(rc);
11175 /* Bits 31:15, Bit 13, Bits 11:4 MBZ. */
11176 HMVMX_CHECK_BREAK(!(u32Val & 0xffffaff0), VMX_IGS_PENDING_DEBUG_RESERVED);
11177#endif
11178
11179 if ( (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
11180 || (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS)
11181 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
11182 {
11183 if ( (u32Eflags & X86_EFL_TF)
11184 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
11185 {
11186 /* Bit 14 is PendingDebug.BS. */
11187 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
11188 }
11189 if ( !(u32Eflags & X86_EFL_TF)
11190 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
11191 {
11192 /* Bit 14 is PendingDebug.BS. */
11193 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
11194 }
11195 }
11196
11197 /* VMCS link pointer. */
11198 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
11199 AssertRCBreak(rc);
11200 if (u64Val != UINT64_C(0xffffffffffffffff))
11201 {
11202 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
11203 /** @todo Bits beyond the processor's physical-address width MBZ. */
11204 /** @todo 32-bit located in memory referenced by value of this field (as a
11205 * physical address) must contain the processor's VMCS revision ID. */
11206 /** @todo SMM checks. */
11207 }
11208
11209 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
11210 * not using Nested Paging? */
11211 if ( pVM->hm.s.fNestedPaging
11212 && !fLongModeGuest
11213 && CPUMIsGuestInPAEModeEx(pCtx))
11214 {
11215 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
11216 AssertRCBreak(rc);
11217 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11218
11219 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
11220 AssertRCBreak(rc);
11221 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11222
11223 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
11224 AssertRCBreak(rc);
11225 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11226
11227 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
11228 AssertRCBreak(rc);
11229 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11230 }
11231
11232 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
11233 if (uError == VMX_IGS_ERROR)
11234 uError = VMX_IGS_REASON_NOT_FOUND;
11235 } while (0);
11236
11237 pVCpu->hm.s.u32HMError = uError;
11238 return uError;
11239
11240#undef HMVMX_ERROR_BREAK
11241#undef HMVMX_CHECK_BREAK
11242}
11243
11244/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
11245/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
11246/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
11247
11248/** @name VM-exit handlers.
11249 * @{
11250 */
11251
11252/**
11253 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
11254 */
11255HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11256{
11257 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11258 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
11259 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
11260 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
11261 return VINF_SUCCESS;
11262 return VINF_EM_RAW_INTERRUPT;
11263}
11264
11265
11266/**
11267 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
11268 */
11269HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11270{
11271 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11272 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
11273
11274 int rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
11275 AssertRCReturn(rc, rc);
11276
11277 uint32_t uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo);
11278 Assert( !(pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT)
11279 && uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
11280 Assert(VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
11281
11282 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11283 {
11284 /*
11285 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we injected it ourselves and
11286 * anything we inject is not going to cause a VM-exit directly for the event being injected.
11287 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
11288 *
11289 * Dispatch the NMI to the host. See Intel spec. 27.5.5 "Updating Non-Register State".
11290 */
11291 VMXDispatchHostNmi();
11292 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
11293 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11294 return VINF_SUCCESS;
11295 }
11296
11297 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
11298 VBOXSTRICTRC rcStrictRc1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
11299 if (RT_UNLIKELY(rcStrictRc1 == VINF_SUCCESS))
11300 { /* likely */ }
11301 else
11302 {
11303 if (rcStrictRc1 == VINF_HM_DOUBLE_FAULT)
11304 rcStrictRc1 = VINF_SUCCESS;
11305 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11306 return rcStrictRc1;
11307 }
11308
11309 uint32_t uExitIntInfo = pVmxTransient->uExitIntInfo;
11310 uint32_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(uExitIntInfo);
11311 switch (uIntType)
11312 {
11313 case VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT: /* Privileged software exception. (#DB from ICEBP) */
11314 Assert(uVector == X86_XCPT_DB);
11315 /* no break */
11316 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT: /* Software exception. (#BP or #OF) */
11317 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT);
11318 /* no break */
11319 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT:
11320 {
11321 /*
11322 * If there's any exception caused as a result of event injection, go back to
11323 * the interpreter. The page-fault case is complicated and we manually handle
11324 * any currently pending event in hmR0VmxExitXcptPF. Nested #ACs are already
11325 * handled in hmR0VmxCheckExitDueToEventDelivery.
11326 */
11327 if (!pVCpu->hm.s.Event.fPending)
11328 { /* likely */ }
11329 else if ( uVector != X86_XCPT_PF
11330 && uVector != X86_XCPT_AC)
11331 {
11332 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
11333 rc = VERR_EM_INTERPRETER;
11334 break;
11335 }
11336
11337 switch (uVector)
11338 {
11339 case X86_XCPT_PF: rc = hmR0VmxExitXcptPF(pVCpu, pMixedCtx, pVmxTransient); break;
11340 case X86_XCPT_GP: rc = hmR0VmxExitXcptGP(pVCpu, pMixedCtx, pVmxTransient); break;
11341 case X86_XCPT_NM: rc = hmR0VmxExitXcptNM(pVCpu, pMixedCtx, pVmxTransient); break;
11342 case X86_XCPT_MF: rc = hmR0VmxExitXcptMF(pVCpu, pMixedCtx, pVmxTransient); break;
11343 case X86_XCPT_DB: rc = hmR0VmxExitXcptDB(pVCpu, pMixedCtx, pVmxTransient); break;
11344 case X86_XCPT_BP: rc = hmR0VmxExitXcptBP(pVCpu, pMixedCtx, pVmxTransient); break;
11345 case X86_XCPT_AC: rc = hmR0VmxExitXcptAC(pVCpu, pMixedCtx, pVmxTransient); break;
11346
11347 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF);
11348 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11349 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE);
11350 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11351 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD);
11352 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11353 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS);
11354 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11355 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP);
11356 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11357 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS);
11358 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11359 default:
11360 {
11361 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11362 AssertRCReturn(rc, rc);
11363
11364 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
11365 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
11366 {
11367 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
11368 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
11369 Assert(CPUMIsGuestInRealModeEx(pMixedCtx));
11370
11371 rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
11372 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
11373 AssertRCReturn(rc, rc);
11374 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(uExitIntInfo),
11375 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode,
11376 0 /* GCPtrFaultAddress */);
11377 AssertRCReturn(rc, rc);
11378 }
11379 else
11380 {
11381 AssertMsgFailed(("Unexpected VM-exit caused by exception %#x\n", uVector));
11382 pVCpu->hm.s.u32HMError = uVector;
11383 rc = VERR_VMX_UNEXPECTED_EXCEPTION;
11384 }
11385 break;
11386 }
11387 }
11388 break;
11389 }
11390
11391 default:
11392 {
11393 pVCpu->hm.s.u32HMError = uExitIntInfo;
11394 rc = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
11395 AssertMsgFailed(("Unexpected interruption info %#x\n", VMX_EXIT_INTERRUPTION_INFO_TYPE(uExitIntInfo)));
11396 break;
11397 }
11398 }
11399 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11400 return rc;
11401}
11402
11403
11404/**
11405 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
11406 */
11407HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11408{
11409 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11410
11411 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
11412 hmR0VmxClearIntWindowExitVmcs(pVCpu);
11413
11414 /* Deliver the pending interrupts via hmR0VmxEvaluatePendingEvent() and resume guest execution. */
11415 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
11416 return VINF_SUCCESS;
11417}
11418
11419
11420/**
11421 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
11422 */
11423HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11424{
11425 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11426 if (RT_UNLIKELY(!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT)))
11427 {
11428 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
11429 HMVMX_RETURN_UNEXPECTED_EXIT();
11430 }
11431
11432 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS));
11433
11434 /*
11435 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
11436 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
11437 */
11438 uint32_t uIntrState = 0;
11439 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
11440 AssertRCReturn(rc, rc);
11441
11442 bool const fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
11443 if ( fBlockSti
11444 && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
11445 {
11446 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
11447 }
11448
11449 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
11450 hmR0VmxClearNmiWindowExitVmcs(pVCpu);
11451
11452 /* Deliver the pending NMI via hmR0VmxEvaluatePendingEvent() and resume guest execution. */
11453 return VINF_SUCCESS;
11454}
11455
11456
11457/**
11458 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
11459 */
11460HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11461{
11462 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11463 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWbinvd);
11464 return hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11465}
11466
11467
11468/**
11469 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
11470 */
11471HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11472{
11473 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11474 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvd);
11475 return hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11476}
11477
11478
11479/**
11480 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
11481 */
11482HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11483{
11484 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11485 PVM pVM = pVCpu->CTX_SUFF(pVM);
11486 int rc = EMInterpretCpuId(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11487 if (RT_LIKELY(rc == VINF_SUCCESS))
11488 {
11489 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11490 Assert(pVmxTransient->cbInstr == 2);
11491 }
11492 else
11493 {
11494 AssertMsgFailed(("hmR0VmxExitCpuid: EMInterpretCpuId failed with %Rrc\n", rc));
11495 rc = VERR_EM_INTERPRETER;
11496 }
11497 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCpuid);
11498 return rc;
11499}
11500
11501
11502/**
11503 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
11504 */
11505HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11506{
11507 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11508 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11509 AssertRCReturn(rc, rc);
11510
11511 if (pMixedCtx->cr4 & X86_CR4_SMXE)
11512 return VINF_EM_RAW_EMULATE_INSTR;
11513
11514 AssertMsgFailed(("hmR0VmxExitGetsec: unexpected VM-exit when CR4.SMXE is 0.\n"));
11515 HMVMX_RETURN_UNEXPECTED_EXIT();
11516}
11517
11518
11519/**
11520 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
11521 */
11522HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11523{
11524 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11525 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11526 AssertRCReturn(rc, rc);
11527
11528 PVM pVM = pVCpu->CTX_SUFF(pVM);
11529 rc = EMInterpretRdtsc(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11530 if (RT_LIKELY(rc == VINF_SUCCESS))
11531 {
11532 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11533 Assert(pVmxTransient->cbInstr == 2);
11534 /* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
11535 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING)
11536 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11537 }
11538 else
11539 rc = VERR_EM_INTERPRETER;
11540 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
11541 return rc;
11542}
11543
11544
11545/**
11546 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
11547 */
11548HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11549{
11550 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11551 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11552 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx); /* For MSR_K8_TSC_AUX */
11553 AssertRCReturn(rc, rc);
11554
11555 PVM pVM = pVCpu->CTX_SUFF(pVM);
11556 rc = EMInterpretRdtscp(pVM, pVCpu, pMixedCtx);
11557 if (RT_SUCCESS(rc))
11558 {
11559 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11560 Assert(pVmxTransient->cbInstr == 3);
11561 /* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
11562 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING)
11563 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11564 }
11565 else
11566 {
11567 AssertMsgFailed(("hmR0VmxExitRdtscp: EMInterpretRdtscp failed with %Rrc\n", rc));
11568 rc = VERR_EM_INTERPRETER;
11569 }
11570 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
11571 return rc;
11572}
11573
11574
11575/**
11576 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
11577 */
11578HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11579{
11580 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11581 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11582 rc |= hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11583 AssertRCReturn(rc, rc);
11584
11585 PVM pVM = pVCpu->CTX_SUFF(pVM);
11586 rc = EMInterpretRdpmc(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11587 if (RT_LIKELY(rc == VINF_SUCCESS))
11588 {
11589 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11590 Assert(pVmxTransient->cbInstr == 2);
11591 }
11592 else
11593 {
11594 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
11595 rc = VERR_EM_INTERPRETER;
11596 }
11597 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdpmc);
11598 return rc;
11599}
11600
11601
11602/**
11603 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
11604 */
11605HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11606{
11607 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11608 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
11609
11610 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
11611 if (pVCpu->hm.s.fHypercallsEnabled)
11612 {
11613#if 0
11614 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
11615#else
11616 /* Aggressive state sync. for now. */
11617 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
11618 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* For long-mode checks in gimKvmHypercall(). */
11619 AssertRCReturn(rc, rc);
11620#endif
11621
11622 /* Perform the hypercall. */
11623 rcStrict = GIMHypercall(pVCpu, pMixedCtx);
11624 if (rcStrict == VINF_SUCCESS)
11625 {
11626 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11627 AssertRCReturn(rc, rc);
11628 }
11629 else
11630 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
11631 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
11632 || RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)));
11633
11634 /* If the hypercall changes anything other than guest's general-purpose registers,
11635 we would need to reload the guest changed bits here before VM-entry. */
11636 }
11637 else
11638 Log4(("hmR0VmxExitVmcall: Hypercalls not enabled\n"));
11639
11640 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
11641 if (RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)))
11642 {
11643 hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
11644 rcStrict = VINF_SUCCESS;
11645 }
11646
11647 return rcStrict;
11648}
11649
11650
11651/**
11652 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
11653 */
11654HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11655{
11656 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11657 PVM pVM = pVCpu->CTX_SUFF(pVM);
11658 Assert(!pVM->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
11659
11660 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
11661 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
11662 AssertRCReturn(rc, rc);
11663
11664 VBOXSTRICTRC rcStrict = EMInterpretInvlpg(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), pVmxTransient->uExitQualification);
11665 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
11666 rcStrict = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11667 else
11668 AssertMsg(rcStrict == VERR_EM_INTERPRETER, ("hmR0VmxExitInvlpg: EMInterpretInvlpg %#RX64 failed with %Rrc\n",
11669 pVmxTransient->uExitQualification, VBOXSTRICTRC_VAL(rcStrict)));
11670 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvlpg);
11671 return rcStrict;
11672}
11673
11674
11675/**
11676 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
11677 */
11678HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11679{
11680 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11681 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11682 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
11683 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
11684 AssertRCReturn(rc, rc);
11685
11686 PVM pVM = pVCpu->CTX_SUFF(pVM);
11687 rc = EMInterpretMonitor(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11688 if (RT_LIKELY(rc == VINF_SUCCESS))
11689 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11690 else
11691 {
11692 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMonitor: EMInterpretMonitor failed with %Rrc\n", rc));
11693 rc = VERR_EM_INTERPRETER;
11694 }
11695 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMonitor);
11696 return rc;
11697}
11698
11699
11700/**
11701 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
11702 */
11703HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11704{
11705 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11706 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11707 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
11708 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
11709 AssertRCReturn(rc, rc);
11710
11711 PVM pVM = pVCpu->CTX_SUFF(pVM);
11712 VBOXSTRICTRC rc2 = EMInterpretMWait(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11713 rc = VBOXSTRICTRC_VAL(rc2);
11714 if (RT_LIKELY( rc == VINF_SUCCESS
11715 || rc == VINF_EM_HALT))
11716 {
11717 int rc3 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11718 AssertRCReturn(rc3, rc3);
11719
11720 if ( rc == VINF_EM_HALT
11721 && EMMonitorWaitShouldContinue(pVCpu, pMixedCtx))
11722 {
11723 rc = VINF_SUCCESS;
11724 }
11725 }
11726 else
11727 {
11728 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMwait: EMInterpretMWait failed with %Rrc\n", rc));
11729 rc = VERR_EM_INTERPRETER;
11730 }
11731 AssertMsg(rc == VINF_SUCCESS || rc == VINF_EM_HALT || rc == VERR_EM_INTERPRETER,
11732 ("hmR0VmxExitMwait: failed, invalid error code %Rrc\n", rc));
11733 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMwait);
11734 return rc;
11735}
11736
11737
11738/**
11739 * VM-exit handler for RSM (VMX_EXIT_RSM). Unconditional VM-exit.
11740 */
11741HMVMX_EXIT_NSRC_DECL hmR0VmxExitRsm(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11742{
11743 /*
11744 * Execution of RSM outside of SMM mode causes #UD regardless of VMX root or VMX non-root mode. In theory, we should never
11745 * get this VM-exit. This can happen only if dual-monitor treatment of SMI and VMX is enabled, which can (only?) be done by
11746 * executing VMCALL in VMX root operation. If we get here, something funny is going on.
11747 * See Intel spec. "33.15.5 Enabling the Dual-Monitor Treatment".
11748 */
11749 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11750 AssertMsgFailed(("Unexpected RSM VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11751 HMVMX_RETURN_UNEXPECTED_EXIT();
11752}
11753
11754
11755/**
11756 * VM-exit handler for SMI (VMX_EXIT_SMI). Unconditional VM-exit.
11757 */
11758HMVMX_EXIT_NSRC_DECL hmR0VmxExitSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11759{
11760 /*
11761 * This can only happen if we support dual-monitor treatment of SMI, which can be activated by executing VMCALL in VMX
11762 * root operation. Only an STM (SMM transfer monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL
11763 * in VMX root mode or receive an SMI. If we get here, something funny is going on.
11764 * See Intel spec. "33.15.6 Activating the Dual-Monitor Treatment" and Intel spec. 25.3 "Other Causes of VM-Exits"
11765 */
11766 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11767 AssertMsgFailed(("Unexpected SMI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11768 HMVMX_RETURN_UNEXPECTED_EXIT();
11769}
11770
11771
11772/**
11773 * VM-exit handler for IO SMI (VMX_EXIT_IO_SMI). Unconditional VM-exit.
11774 */
11775HMVMX_EXIT_NSRC_DECL hmR0VmxExitIoSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11776{
11777 /* Same treatment as VMX_EXIT_SMI. See comment in hmR0VmxExitSmi(). */
11778 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11779 AssertMsgFailed(("Unexpected IO SMI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11780 HMVMX_RETURN_UNEXPECTED_EXIT();
11781}
11782
11783
11784/**
11785 * VM-exit handler for SIPI (VMX_EXIT_SIPI). Conditional VM-exit.
11786 */
11787HMVMX_EXIT_NSRC_DECL hmR0VmxExitSipi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11788{
11789 /*
11790 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest activity state is used. We currently
11791 * don't make use of it (see hmR0VmxLoadGuestActivityState()) as our guests don't have direct access to the host LAPIC.
11792 * See Intel spec. 25.3 "Other Causes of VM-exits".
11793 */
11794 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11795 AssertMsgFailed(("Unexpected SIPI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11796 HMVMX_RETURN_UNEXPECTED_EXIT();
11797}
11798
11799
11800/**
11801 * VM-exit handler for INIT signal (VMX_EXIT_INIT_SIGNAL). Unconditional
11802 * VM-exit.
11803 */
11804HMVMX_EXIT_NSRC_DECL hmR0VmxExitInitSignal(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11805{
11806 /*
11807 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
11808 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery" and Intel spec. 29.3 "VMX Instructions" for "VMXON".
11809 *
11810 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these VM-exits.
11811 * See Intel spec. "23.8 Restrictions on VMX operation".
11812 */
11813 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11814 return VINF_SUCCESS;
11815}
11816
11817
11818/**
11819 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
11820 * VM-exit.
11821 */
11822HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11823{
11824 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11825 return VINF_EM_RESET;
11826}
11827
11828
11829/**
11830 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
11831 */
11832HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11833{
11834 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11835 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT);
11836
11837 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11838 AssertRCReturn(rc, rc);
11839
11840 if (EMShouldContinueAfterHalt(pVCpu, pMixedCtx)) /* Requires eflags. */
11841 rc = VINF_SUCCESS;
11842 else
11843 rc = VINF_EM_HALT;
11844
11845 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
11846 if (rc != VINF_SUCCESS)
11847 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
11848 return rc;
11849}
11850
11851
11852/**
11853 * VM-exit handler for instructions that result in a \#UD exception delivered to
11854 * the guest.
11855 */
11856HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11857{
11858 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11859 hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
11860 return VINF_SUCCESS;
11861}
11862
11863
11864/**
11865 * VM-exit handler for expiry of the VMX preemption timer.
11866 */
11867HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11868{
11869 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11870
11871 /* If the preemption-timer has expired, reinitialize the preemption timer on next VM-entry. */
11872 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11873
11874 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
11875 PVM pVM = pVCpu->CTX_SUFF(pVM);
11876 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
11877 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
11878 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
11879}
11880
11881
11882/**
11883 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
11884 */
11885HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11886{
11887 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11888
11889 int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
11890 rc |= hmR0VmxSaveGuestRegsForIemExec(pVCpu, pMixedCtx, false /*fMemory*/, false /*fNeedRsp*/);
11891 rc |= hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11892 AssertRCReturn(rc, rc);
11893
11894 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbInstr);
11895 HMCPU_CF_SET(pVCpu, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS : HM_CHANGED_ALL_GUEST);
11896
11897 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pMixedCtx->cr4 & X86_CR4_OSXSAVE) && pMixedCtx->aXcr[0] != ASMGetXcr0();
11898
11899 return rcStrict;
11900}
11901
11902
11903/**
11904 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
11905 */
11906HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11907{
11908 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11909
11910 /* The guest should not invalidate the host CPU's TLBs, fallback to interpreter. */
11911 /** @todo implement EMInterpretInvpcid() */
11912 return VERR_EM_INTERPRETER;
11913}
11914
11915
11916/**
11917 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE).
11918 * Error VM-exit.
11919 */
11920HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11921{
11922 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
11923 AssertRCReturn(rc, rc);
11924
11925 rc = hmR0VmxCheckVmcsCtls(pVCpu);
11926 AssertRCReturn(rc, rc);
11927
11928 uint32_t uInvalidReason = hmR0VmxCheckGuestState(pVCpu->CTX_SUFF(pVM), pVCpu, pMixedCtx);
11929 NOREF(uInvalidReason);
11930
11931#ifdef VBOX_STRICT
11932 uint32_t uIntrState;
11933 RTHCUINTREG uHCReg;
11934 uint64_t u64Val;
11935 uint32_t u32Val;
11936
11937 rc = hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
11938 rc |= hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
11939 rc |= hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
11940 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
11941 AssertRCReturn(rc, rc);
11942
11943 Log4(("uInvalidReason %u\n", uInvalidReason));
11944 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
11945 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
11946 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
11947 Log4(("VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE %#RX32\n", uIntrState));
11948
11949 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32Val); AssertRC(rc);
11950 Log4(("VMX_VMCS_GUEST_CR0 %#RX32\n", u32Val));
11951 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
11952 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
11953 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
11954 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
11955 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
11956 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
11957 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
11958 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
11959 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
11960 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
11961#else
11962 NOREF(pVmxTransient);
11963#endif
11964
11965 HMDumpRegs(pVCpu->CTX_SUFF(pVM), pVCpu, pMixedCtx);
11966 return VERR_VMX_INVALID_GUEST_STATE;
11967}
11968
11969
11970/**
11971 * VM-exit handler for VM-entry failure due to an MSR-load
11972 * (VMX_EXIT_ERR_MSR_LOAD). Error VM-exit.
11973 */
11974HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrMsrLoad(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11975{
11976 NOREF(pVmxTransient);
11977 AssertMsgFailed(("Unexpected MSR-load exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx)); NOREF(pMixedCtx);
11978 HMVMX_RETURN_UNEXPECTED_EXIT();
11979}
11980
11981
11982/**
11983 * VM-exit handler for VM-entry failure due to a machine-check event
11984 * (VMX_EXIT_ERR_MACHINE_CHECK). Error VM-exit.
11985 */
11986HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrMachineCheck(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11987{
11988 NOREF(pVmxTransient);
11989 AssertMsgFailed(("Unexpected machine-check event exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx)); NOREF(pMixedCtx);
11990 HMVMX_RETURN_UNEXPECTED_EXIT();
11991}
11992
11993
11994/**
11995 * VM-exit handler for all undefined reasons. Should never ever happen.. in
11996 * theory.
11997 */
11998HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUndefined(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11999{
12000 AssertMsgFailed(("Huh!? Undefined VM-exit reason %d. pVCpu=%p pMixedCtx=%p\n", pVmxTransient->uExitReason, pVCpu, pMixedCtx));
12001 NOREF(pVCpu); NOREF(pMixedCtx); NOREF(pVmxTransient);
12002 return VERR_VMX_UNDEFINED_EXIT_CODE;
12003}
12004
12005
12006/**
12007 * VM-exit handler for XDTR (LGDT, SGDT, LIDT, SIDT) accesses
12008 * (VMX_EXIT_XDTR_ACCESS) and LDT and TR access (LLDT, LTR, SLDT, STR).
12009 * Conditional VM-exit.
12010 */
12011HMVMX_EXIT_DECL hmR0VmxExitXdtrAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12012{
12013 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12014
12015 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT. */
12016 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitXdtrAccess);
12017 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT)
12018 return VERR_EM_INTERPRETER;
12019 AssertMsgFailed(("Unexpected XDTR access. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12020 HMVMX_RETURN_UNEXPECTED_EXIT();
12021}
12022
12023
12024/**
12025 * VM-exit handler for RDRAND (VMX_EXIT_RDRAND). Conditional VM-exit.
12026 */
12027HMVMX_EXIT_DECL hmR0VmxExitRdrand(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12028{
12029 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12030
12031 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT. */
12032 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdrand);
12033 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT)
12034 return VERR_EM_INTERPRETER;
12035 AssertMsgFailed(("Unexpected RDRAND exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12036 HMVMX_RETURN_UNEXPECTED_EXIT();
12037}
12038
12039
12040/**
12041 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
12042 */
12043HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12044{
12045 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12046
12047 /* EMInterpretRdmsr() requires CR0, Eflags and SS segment register. */
12048 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
12049 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
12050 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12051 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
12052 {
12053 rc |= hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
12054 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
12055 }
12056 AssertRCReturn(rc, rc);
12057 Log4(("ecx=%#RX32\n", pMixedCtx->ecx));
12058
12059#ifdef VBOX_STRICT
12060 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
12061 {
12062 if ( hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx)
12063 && pMixedCtx->ecx != MSR_K6_EFER)
12064 {
12065 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
12066 pMixedCtx->ecx));
12067 HMVMX_RETURN_UNEXPECTED_EXIT();
12068 }
12069 if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
12070 {
12071 VMXMSREXITREAD enmRead;
12072 VMXMSREXITWRITE enmWrite;
12073 int rc2 = hmR0VmxGetMsrPermission(pVCpu, pMixedCtx->ecx, &enmRead, &enmWrite);
12074 AssertRCReturn(rc2, rc2);
12075 if (enmRead == VMXMSREXIT_PASSTHRU_READ)
12076 {
12077 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", pMixedCtx->ecx));
12078 HMVMX_RETURN_UNEXPECTED_EXIT();
12079 }
12080 }
12081 }
12082#endif
12083
12084 PVM pVM = pVCpu->CTX_SUFF(pVM);
12085 rc = EMInterpretRdmsr(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
12086 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER,
12087 ("hmR0VmxExitRdmsr: failed, invalid error code %Rrc\n", rc));
12088 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
12089 if (RT_SUCCESS(rc))
12090 {
12091 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12092 Assert(pVmxTransient->cbInstr == 2);
12093 }
12094 return rc;
12095}
12096
12097
12098/**
12099 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
12100 */
12101HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12102{
12103 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12104 PVM pVM = pVCpu->CTX_SUFF(pVM);
12105 int rc = VINF_SUCCESS;
12106
12107 /* EMInterpretWrmsr() requires CR0, EFLAGS and SS segment register. */
12108 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
12109 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
12110 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12111 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
12112 {
12113 rc |= hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
12114 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
12115 }
12116 AssertRCReturn(rc, rc);
12117 Log4(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", pMixedCtx->ecx, pMixedCtx->edx, pMixedCtx->eax));
12118
12119 rc = EMInterpretWrmsr(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
12120 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER, ("hmR0VmxExitWrmsr: failed, invalid error code %Rrc\n", rc));
12121 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
12122
12123 if (RT_SUCCESS(rc))
12124 {
12125 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12126
12127 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
12128 if ( pMixedCtx->ecx == MSR_IA32_APICBASE
12129 || ( pMixedCtx->ecx >= MSR_IA32_X2APIC_START
12130 && pMixedCtx->ecx <= MSR_IA32_X2APIC_END))
12131 {
12132 /* We've already saved the APIC related guest-state (TPR) in hmR0VmxPostRunGuest(). When full APIC register
12133 * virtualization is implemented we'll have to make sure APIC state is saved from the VMCS before
12134 EMInterpretWrmsr() changes it. */
12135 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
12136 }
12137 else if (pMixedCtx->ecx == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
12138 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
12139 else if (pMixedCtx->ecx == MSR_K6_EFER)
12140 {
12141 /*
12142 * If the guest touches EFER we need to update the VM-Entry and VM-Exit controls as well,
12143 * even if it is -not- touching bits that cause paging mode changes (LMA/LME). We care about
12144 * the other bits as well, SCE and NXE. See @bugref{7368}.
12145 */
12146 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_CTLS | HM_CHANGED_VMX_EXIT_CTLS);
12147 }
12148
12149 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not supported. */
12150 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
12151 {
12152 switch (pMixedCtx->ecx)
12153 {
12154 case MSR_IA32_SYSENTER_CS: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
12155 case MSR_IA32_SYSENTER_EIP: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
12156 case MSR_IA32_SYSENTER_ESP: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
12157 case MSR_K8_FS_BASE: /* no break */
12158 case MSR_K8_GS_BASE: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS); break;
12159 case MSR_K6_EFER: /* already handled above */ break;
12160 default:
12161 {
12162 if (hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx))
12163 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
12164 else if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
12165 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS);
12166 break;
12167 }
12168 }
12169 }
12170#ifdef VBOX_STRICT
12171 else
12172 {
12173 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
12174 switch (pMixedCtx->ecx)
12175 {
12176 case MSR_IA32_SYSENTER_CS:
12177 case MSR_IA32_SYSENTER_EIP:
12178 case MSR_IA32_SYSENTER_ESP:
12179 case MSR_K8_FS_BASE:
12180 case MSR_K8_GS_BASE:
12181 {
12182 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", pMixedCtx->ecx));
12183 HMVMX_RETURN_UNEXPECTED_EXIT();
12184 }
12185
12186 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
12187 default:
12188 {
12189 if (hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx))
12190 {
12191 /* EFER writes are always intercepted, see hmR0VmxLoadGuestMsrs(). */
12192 if (pMixedCtx->ecx != MSR_K6_EFER)
12193 {
12194 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
12195 pMixedCtx->ecx));
12196 HMVMX_RETURN_UNEXPECTED_EXIT();
12197 }
12198 }
12199
12200 if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
12201 {
12202 VMXMSREXITREAD enmRead;
12203 VMXMSREXITWRITE enmWrite;
12204 int rc2 = hmR0VmxGetMsrPermission(pVCpu, pMixedCtx->ecx, &enmRead, &enmWrite);
12205 AssertRCReturn(rc2, rc2);
12206 if (enmWrite == VMXMSREXIT_PASSTHRU_WRITE)
12207 {
12208 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", pMixedCtx->ecx));
12209 HMVMX_RETURN_UNEXPECTED_EXIT();
12210 }
12211 }
12212 break;
12213 }
12214 }
12215 }
12216#endif /* VBOX_STRICT */
12217 }
12218 return rc;
12219}
12220
12221
12222/**
12223 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
12224 */
12225HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12226{
12227 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12228
12229 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPause);
12230 return VINF_EM_RAW_INTERRUPT;
12231}
12232
12233
12234/**
12235 * VM-exit handler for when the TPR value is lowered below the specified
12236 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
12237 */
12238HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12239{
12240 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12241 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW);
12242
12243 /*
12244 * The TPR has already been updated, see hmR0VMXPostRunGuest(). RIP is also updated as part of the VM-exit by VT-x. Update
12245 * the threshold in the VMCS, deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectPendingEvent() and
12246 * resume guest execution.
12247 */
12248 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
12249 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
12250 return VINF_SUCCESS;
12251}
12252
12253
12254/**
12255 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
12256 * VM-exit.
12257 *
12258 * @retval VINF_SUCCESS when guest execution can continue.
12259 * @retval VINF_PGM_CHANGE_MODE when shadow paging mode changed, back to ring-3.
12260 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
12261 * @retval VERR_EM_INTERPRETER when something unexpected happened, fallback to
12262 * interpreter.
12263 */
12264HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12265{
12266 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12267 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
12268 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12269 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12270 AssertRCReturn(rc, rc);
12271
12272 RTGCUINTPTR const uExitQualification = pVmxTransient->uExitQualification;
12273 uint32_t const uAccessType = VMX_EXIT_QUALIFICATION_CRX_ACCESS(uExitQualification);
12274 PVM pVM = pVCpu->CTX_SUFF(pVM);
12275 VBOXSTRICTRC rcStrict;
12276 rc = hmR0VmxSaveGuestRegsForIemExec(pVCpu, pMixedCtx, false /*fMemory*/, true /*fNeedRsp*/);
12277 switch (uAccessType)
12278 {
12279 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_WRITE: /* MOV to CRx */
12280 {
12281 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12282 AssertRCReturn(rc, rc);
12283
12284 rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, pVmxTransient->cbInstr,
12285 VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification),
12286 VMX_EXIT_QUALIFICATION_CRX_GENREG(uExitQualification));
12287 AssertMsg( rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT || rcStrict == VINF_PGM_CHANGE_MODE
12288 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12289 switch (VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification))
12290 {
12291 case 0: /* CR0 */
12292 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
12293 Log4(("CRX CR0 write rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr0));
12294 break;
12295 case 2: /* CR2 */
12296 /* Nothing to do here, CR2 it's not part of the VMCS. */
12297 break;
12298 case 3: /* CR3 */
12299 Assert(!pVM->hm.s.fNestedPaging || !CPUMIsGuestPagingEnabledEx(pMixedCtx) || pVCpu->hm.s.fUsingDebugLoop);
12300 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR3);
12301 Log4(("CRX CR3 write rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr3));
12302 break;
12303 case 4: /* CR4 */
12304 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
12305 Log4(("CRX CR4 write rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n",
12306 VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr4, pVCpu->hm.s.fLoadSaveGuestXcr0));
12307 break;
12308 case 8: /* CR8 */
12309 Assert(!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW));
12310 /* CR8 contains the APIC TPR. Was updated by IEMExecDecodedMovCRxWrite(). */
12311 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
12312 break;
12313 default:
12314 AssertMsgFailed(("Invalid CRx register %#x\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)));
12315 break;
12316 }
12317
12318 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxWrite[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
12319 break;
12320 }
12321
12322 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ: /* MOV from CRx */
12323 {
12324 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12325 AssertRCReturn(rc, rc);
12326
12327 Assert( !pVM->hm.s.fNestedPaging
12328 || !CPUMIsGuestPagingEnabledEx(pMixedCtx)
12329 || pVCpu->hm.s.fUsingDebugLoop
12330 || VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification) != 3);
12331
12332 /* CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
12333 Assert( VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification) != 8
12334 || !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW));
12335
12336 rcStrict = IEMExecDecodedMovCRxRead(pVCpu, pVmxTransient->cbInstr,
12337 VMX_EXIT_QUALIFICATION_CRX_GENREG(uExitQualification),
12338 VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification));
12339 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12340 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxRead[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
12341 Log4(("CRX CR%d Read access rcStrict=%Rrc\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification),
12342 VBOXSTRICTRC_VAL(rcStrict)));
12343 break;
12344 }
12345
12346 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_CLTS: /* CLTS (Clear Task-Switch Flag in CR0) */
12347 {
12348 AssertRCReturn(rc, rc);
12349 rcStrict = IEMExecDecodedClts(pVCpu, pVmxTransient->cbInstr);
12350 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12351 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
12352 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
12353 Log4(("CRX CLTS rcStrict=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
12354 break;
12355 }
12356
12357 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
12358 {
12359 AssertRCReturn(rc, rc);
12360 rcStrict = IEMExecDecodedLmsw(pVCpu, pVmxTransient->cbInstr,
12361 VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(uExitQualification));
12362 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT || rcStrict == VINF_PGM_CHANGE_MODE,
12363 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12364 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
12365 Log4(("CRX LMSW rcStrict=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
12366 break;
12367 }
12368
12369 default:
12370 AssertMsgFailedReturn(("Invalid access-type in Mov CRx VM-exit qualification %#x\n", uAccessType),
12371 VERR_VMX_UNEXPECTED_EXCEPTION);
12372 }
12373
12374 HMCPU_CF_SET(pVCpu, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS : HM_CHANGED_ALL_GUEST);
12375 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
12376 NOREF(pVM);
12377 return rcStrict;
12378}
12379
12380
12381/**
12382 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
12383 * VM-exit.
12384 */
12385HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12386{
12387 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12388 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
12389
12390 int rc2 = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12391 rc2 |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12392 rc2 |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
12393 rc2 |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx); /* Eflag checks in EMInterpretDisasCurrent(). */
12394 rc2 |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx); /* CR0 checks & PGM* in EMInterpretDisasCurrent(). */
12395 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* SELM checks in EMInterpretDisasCurrent(). */
12396 /* EFER also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
12397 AssertRCReturn(rc2, rc2);
12398
12399 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
12400 uint32_t uIOPort = VMX_EXIT_QUALIFICATION_IO_PORT(pVmxTransient->uExitQualification);
12401 uint8_t uIOWidth = VMX_EXIT_QUALIFICATION_IO_WIDTH(pVmxTransient->uExitQualification);
12402 bool fIOWrite = ( VMX_EXIT_QUALIFICATION_IO_DIRECTION(pVmxTransient->uExitQualification)
12403 == VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT);
12404 bool fIOString = VMX_EXIT_QUALIFICATION_IO_IS_STRING(pVmxTransient->uExitQualification);
12405 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
12406 bool fDbgStepping = pVCpu->hm.s.fSingleInstruction;
12407 AssertReturn(uIOWidth <= 3 && uIOWidth != 2, VERR_VMX_IPE_1);
12408
12409 /* I/O operation lookup arrays. */
12410 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses. */
12411 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving the result (in AL/AX/EAX). */
12412
12413 VBOXSTRICTRC rcStrict;
12414 uint32_t const cbValue = s_aIOSizes[uIOWidth];
12415 uint32_t const cbInstr = pVmxTransient->cbInstr;
12416 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
12417 PVM pVM = pVCpu->CTX_SUFF(pVM);
12418 if (fIOString)
12419 {
12420#ifdef VBOX_WITH_2ND_IEM_STEP /* This used to gurus with debian 32-bit guest without NP (on ATA reads).
12421 See @bugref{5752#c158}. Should work now. */
12422 /*
12423 * INS/OUTS - I/O String instruction.
12424 *
12425 * Use instruction-information if available, otherwise fall back on
12426 * interpreting the instruction.
12427 */
12428 Log4(("CS:RIP=%04x:%08RX64 %#06x/%u %c str\n", pMixedCtx->cs.Sel, pMixedCtx->rip, uIOPort, cbValue,
12429 fIOWrite ? 'w' : 'r'));
12430 AssertReturn(pMixedCtx->dx == uIOPort, VERR_VMX_IPE_2);
12431 if (MSR_IA32_VMX_BASIC_INFO_VMCS_INS_OUTS(pVM->hm.s.vmx.Msrs.u64BasicInfo))
12432 {
12433 rc2 = hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12434 /** @todo optimize this, IEM should request the additional state if it needs it (GP, PF, ++). */
12435 rc2 |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12436 AssertRCReturn(rc2, rc2);
12437 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
12438 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
12439 IEMMODE enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
12440 bool fRep = VMX_EXIT_QUALIFICATION_IO_IS_REP(pVmxTransient->uExitQualification);
12441 if (fIOWrite)
12442 {
12443 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
12444 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
12445 }
12446 else
12447 {
12448 /*
12449 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
12450 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
12451 * See Intel Instruction spec. for "INS".
12452 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
12453 */
12454 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
12455 }
12456 }
12457 else
12458 {
12459 /** @todo optimize this, IEM should request the additional state if it needs it (GP, PF, ++). */
12460 rc2 = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12461 AssertRCReturn(rc2, rc2);
12462 rcStrict = IEMExecOne(pVCpu);
12463 }
12464 /** @todo IEM needs to be setting these flags somehow. */
12465 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
12466 fUpdateRipAlready = true;
12467#else
12468 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
12469 rcStrict = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL /* pcbInstr */);
12470 if (RT_SUCCESS(rcStrict))
12471 {
12472 if (fIOWrite)
12473 {
12474 rcStrict = IOMInterpretOUTSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix,
12475 (DISCPUMODE)pDis->uAddrMode, cbValue);
12476 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringWrite);
12477 }
12478 else
12479 {
12480 rcStrict = IOMInterpretINSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix,
12481 (DISCPUMODE)pDis->uAddrMode, cbValue);
12482 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringRead);
12483 }
12484 }
12485 else
12486 {
12487 AssertMsg(rcStrict == VERR_EM_INTERPRETER, ("rcStrict=%Rrc RIP=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict),
12488 pMixedCtx->rip));
12489 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
12490 }
12491#endif
12492 }
12493 else
12494 {
12495 /*
12496 * IN/OUT - I/O instruction.
12497 */
12498 Log4(("CS:RIP=%04x:%08RX64 %#06x/%u %c\n", pMixedCtx->cs.Sel, pMixedCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
12499 uint32_t const uAndVal = s_aIOOpAnd[uIOWidth];
12500 Assert(!VMX_EXIT_QUALIFICATION_IO_IS_REP(pVmxTransient->uExitQualification));
12501 if (fIOWrite)
12502 {
12503 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pMixedCtx->eax & uAndVal, cbValue);
12504 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
12505 }
12506 else
12507 {
12508 uint32_t u32Result = 0;
12509 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
12510 if (IOM_SUCCESS(rcStrict))
12511 {
12512 /* Save result of I/O IN instr. in AL/AX/EAX. */
12513 pMixedCtx->eax = (pMixedCtx->eax & ~uAndVal) | (u32Result & uAndVal);
12514 }
12515 else if (rcStrict == VINF_IOM_R3_IOPORT_READ)
12516 HMR0SavePendingIOPortRead(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbValue);
12517 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
12518 }
12519 }
12520
12521 if (IOM_SUCCESS(rcStrict))
12522 {
12523 if (!fUpdateRipAlready)
12524 {
12525 hmR0VmxAdvanceGuestRipBy(pVCpu, pMixedCtx, cbInstr);
12526 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
12527 }
12528
12529 /*
12530 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru while booting Fedora 17 64-bit guest.
12531 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
12532 */
12533 if (fIOString)
12534 {
12535 /** @todo Single-step for INS/OUTS with REP prefix? */
12536 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
12537 }
12538 else if ( !fDbgStepping
12539 && fGstStepping)
12540 {
12541 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
12542 }
12543
12544 /*
12545 * If any I/O breakpoints are armed, we need to check if one triggered
12546 * and take appropriate action.
12547 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
12548 */
12549 rc2 = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
12550 AssertRCReturn(rc2, rc2);
12551
12552 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
12553 * execution engines about whether hyper BPs and such are pending. */
12554 uint32_t const uDr7 = pMixedCtx->dr[7];
12555 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
12556 && X86_DR7_ANY_RW_IO(uDr7)
12557 && (pMixedCtx->cr4 & X86_CR4_DE))
12558 || DBGFBpIsHwIoArmed(pVM)))
12559 {
12560 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
12561
12562 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
12563 VMMRZCallRing3Disable(pVCpu);
12564 HM_DISABLE_PREEMPT();
12565
12566 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
12567
12568 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pMixedCtx, uIOPort, cbValue);
12569 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
12570 {
12571 /* Raise #DB. */
12572 if (fIsGuestDbgActive)
12573 ASMSetDR6(pMixedCtx->dr[6]);
12574 if (pMixedCtx->dr[7] != uDr7)
12575 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
12576
12577 hmR0VmxSetPendingXcptDB(pVCpu, pMixedCtx);
12578 }
12579 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
12580 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
12581 else if ( rcStrict2 != VINF_SUCCESS
12582 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
12583 rcStrict = rcStrict2;
12584 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
12585
12586 HM_RESTORE_PREEMPT();
12587 VMMRZCallRing3Enable(pVCpu);
12588 }
12589 }
12590
12591#ifdef VBOX_STRICT
12592 if (rcStrict == VINF_IOM_R3_IOPORT_READ)
12593 Assert(!fIOWrite);
12594 else if (rcStrict == VINF_IOM_R3_IOPORT_WRITE || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE)
12595 Assert(fIOWrite);
12596 else
12597 {
12598#if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
12599 * statuses, that the VMM device and some others may return. See
12600 * IOM_SUCCESS() for guidance. */
12601 AssertMsg( RT_FAILURE(rcStrict)
12602 || rcStrict == VINF_SUCCESS
12603 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
12604 || rcStrict == VINF_EM_DBG_BREAKPOINT
12605 || rcStrict == VINF_EM_RAW_GUEST_TRAP
12606 || rcStrict == VINF_EM_RAW_TO_R3
12607 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12608#endif
12609 }
12610#endif
12611
12612 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
12613 return rcStrict;
12614}
12615
12616
12617/**
12618 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
12619 * VM-exit.
12620 */
12621HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12622{
12623 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12624
12625 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
12626 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12627 AssertRCReturn(rc, rc);
12628 if (VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_IDT)
12629 {
12630 rc = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
12631 AssertRCReturn(rc, rc);
12632 if (VMX_IDT_VECTORING_INFO_VALID(pVmxTransient->uIdtVectoringInfo))
12633 {
12634 uint32_t uIntType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
12635
12636 uint32_t uVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
12637 bool fErrorCodeValid = VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo);
12638
12639 /* Save it as a pending event and it'll be converted to a TRPM event on the way out to ring-3. */
12640 Assert(!pVCpu->hm.s.Event.fPending);
12641 pVCpu->hm.s.Event.fPending = true;
12642 pVCpu->hm.s.Event.u64IntInfo = pVmxTransient->uIdtVectoringInfo;
12643 rc = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
12644 AssertRCReturn(rc, rc);
12645 if (fErrorCodeValid)
12646 pVCpu->hm.s.Event.u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
12647 else
12648 pVCpu->hm.s.Event.u32ErrCode = 0;
12649 if ( uIntType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
12650 && uVector == X86_XCPT_PF)
12651 {
12652 pVCpu->hm.s.Event.GCPtrFaultAddress = pMixedCtx->cr2;
12653 }
12654
12655 Log4(("Pending event on TaskSwitch uIntType=%#x uVector=%#x\n", uIntType, uVector));
12656 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
12657 return VINF_EM_RAW_INJECT_TRPM_EVENT;
12658 }
12659 }
12660
12661 /* Fall back to the interpreter to emulate the task-switch. */
12662 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
12663 return VERR_EM_INTERPRETER;
12664}
12665
12666
12667/**
12668 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
12669 */
12670HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12671{
12672 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12673 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG);
12674 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG;
12675 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
12676 AssertRCReturn(rc, rc);
12677 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMtf);
12678 return VINF_EM_DBG_STEPPED;
12679}
12680
12681
12682/**
12683 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
12684 */
12685HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12686{
12687 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12688
12689 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
12690
12691 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
12692 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
12693 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
12694 {
12695 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
12696 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
12697 {
12698 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
12699 return VERR_EM_INTERPRETER;
12700 }
12701 }
12702 else
12703 {
12704 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
12705 rcStrict1 = VINF_SUCCESS;
12706 return rcStrict1;
12707 }
12708
12709#if 0
12710 /** @todo Investigate if IOMMMIOPhysHandler() requires a lot of state, for now
12711 * just sync the whole thing. */
12712 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12713#else
12714 /* Aggressive state sync. for now. */
12715 int rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
12716 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12717 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12718#endif
12719 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12720 AssertRCReturn(rc, rc);
12721
12722 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
12723 uint32_t uAccessType = VMX_EXIT_QUALIFICATION_APIC_ACCESS_TYPE(pVmxTransient->uExitQualification);
12724 VBOXSTRICTRC rcStrict2;
12725 switch (uAccessType)
12726 {
12727 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
12728 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
12729 {
12730 AssertMsg( !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
12731 || VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification) != XAPIC_OFF_TPR,
12732 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
12733
12734 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64MsrApicBase; /* Always up-to-date, u64MsrApicBase is not part of the VMCS. */
12735 GCPhys &= PAGE_BASE_GC_MASK;
12736 GCPhys += VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification);
12737 PVM pVM = pVCpu->CTX_SUFF(pVM);
12738 Log4(("ApicAccess uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
12739 VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification)));
12740
12741 rcStrict2 = IOMMMIOPhysHandler(pVM, pVCpu,
12742 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW,
12743 CPUMCTX2CORE(pMixedCtx), GCPhys);
12744 Log4(("ApicAccess rcStrict2=%d\n", VBOXSTRICTRC_VAL(rcStrict2)));
12745 if ( rcStrict2 == VINF_SUCCESS
12746 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
12747 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
12748 {
12749 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
12750 | HM_CHANGED_GUEST_RSP
12751 | HM_CHANGED_GUEST_RFLAGS
12752 | HM_CHANGED_VMX_GUEST_APIC_STATE);
12753 rcStrict2 = VINF_SUCCESS;
12754 }
12755 break;
12756 }
12757
12758 default:
12759 Log4(("ApicAccess uAccessType=%#x\n", uAccessType));
12760 rcStrict2 = VINF_EM_RAW_EMULATE_INSTR;
12761 break;
12762 }
12763
12764 if (rcStrict2 != VINF_SUCCESS)
12765 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
12766 return rcStrict2;
12767}
12768
12769
12770/**
12771 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
12772 * VM-exit.
12773 */
12774HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12775{
12776 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12777
12778 /* We should -not- get this VM-exit if the guest's debug registers were active. */
12779 if (pVmxTransient->fWasGuestDebugStateActive)
12780 {
12781 AssertMsgFailed(("Unexpected MOV DRx exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12782 HMVMX_RETURN_UNEXPECTED_EXIT();
12783 }
12784
12785 if ( !pVCpu->hm.s.fSingleInstruction
12786 && !pVmxTransient->fWasHyperDebugStateActive)
12787 {
12788 Assert(!DBGFIsStepping(pVCpu));
12789 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
12790
12791 /* Don't intercept MOV DRx any more. */
12792 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
12793 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
12794 AssertRCReturn(rc, rc);
12795
12796 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
12797 VMMRZCallRing3Disable(pVCpu);
12798 HM_DISABLE_PREEMPT();
12799
12800 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
12801 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
12802 Assert(CPUMIsGuestDebugStateActive(pVCpu) || HC_ARCH_BITS == 32);
12803
12804 HM_RESTORE_PREEMPT();
12805 VMMRZCallRing3Enable(pVCpu);
12806
12807#ifdef VBOX_WITH_STATISTICS
12808 rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12809 AssertRCReturn(rc, rc);
12810 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
12811 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
12812 else
12813 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
12814#endif
12815 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
12816 return VINF_SUCCESS;
12817 }
12818
12819 /*
12820 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER, CS. EFER is always up-to-date.
12821 * Update the segment registers and DR7 from the CPU.
12822 */
12823 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12824 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12825 rc |= hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
12826 AssertRCReturn(rc, rc);
12827 Log4(("CS:RIP=%04x:%08RX64\n", pMixedCtx->cs.Sel, pMixedCtx->rip));
12828
12829 PVM pVM = pVCpu->CTX_SUFF(pVM);
12830 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
12831 {
12832 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
12833 VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification),
12834 VMX_EXIT_QUALIFICATION_DRX_GENREG(pVmxTransient->uExitQualification));
12835 if (RT_SUCCESS(rc))
12836 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
12837 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
12838 }
12839 else
12840 {
12841 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
12842 VMX_EXIT_QUALIFICATION_DRX_GENREG(pVmxTransient->uExitQualification),
12843 VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification));
12844 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
12845 }
12846
12847 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
12848 if (RT_SUCCESS(rc))
12849 {
12850 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12851 AssertRCReturn(rc2, rc2);
12852 return VINF_SUCCESS;
12853 }
12854 return rc;
12855}
12856
12857
12858/**
12859 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
12860 * Conditional VM-exit.
12861 */
12862HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12863{
12864 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12865 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
12866
12867 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
12868 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
12869 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
12870 {
12871 /* If event delivery causes an EPT misconfig (MMIO), go back to instruction emulation as otherwise
12872 injecting the original pending event would most likely cause the same EPT misconfig VM-exit. */
12873 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
12874 {
12875 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
12876 return VERR_EM_INTERPRETER;
12877 }
12878 }
12879 else
12880 {
12881 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
12882 rcStrict1 = VINF_SUCCESS;
12883 return rcStrict1;
12884 }
12885
12886 RTGCPHYS GCPhys = 0;
12887 int rc = VMXReadVmcs64(VMX_VMCS64_EXIT_GUEST_PHYS_ADDR_FULL, &GCPhys);
12888
12889#if 0
12890 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx); /** @todo Can we do better? */
12891#else
12892 /* Aggressive state sync. for now. */
12893 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
12894 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12895 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12896#endif
12897 AssertRCReturn(rc, rc);
12898
12899 /*
12900 * If we succeed, resume guest execution.
12901 * If we fail in interpreting the instruction because we couldn't get the guest physical address
12902 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
12903 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
12904 * weird case. See @bugref{6043}.
12905 */
12906 PVM pVM = pVCpu->CTX_SUFF(pVM);
12907 VBOXSTRICTRC rcStrict2 = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pMixedCtx), GCPhys, UINT32_MAX);
12908 Log4(("EPT misconfig at %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pMixedCtx->rip, VBOXSTRICTRC_VAL(rcStrict2)));
12909 if ( rcStrict2 == VINF_SUCCESS
12910 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
12911 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
12912 {
12913 /* Successfully handled MMIO operation. */
12914 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
12915 | HM_CHANGED_GUEST_RSP
12916 | HM_CHANGED_GUEST_RFLAGS
12917 | HM_CHANGED_VMX_GUEST_APIC_STATE);
12918 return VINF_SUCCESS;
12919 }
12920 return rcStrict2;
12921}
12922
12923
12924/**
12925 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
12926 * VM-exit.
12927 */
12928HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12929{
12930 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12931 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
12932
12933 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
12934 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
12935 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
12936 {
12937 /* In the unlikely case that the EPT violation happened as a result of delivering an event, log it. */
12938 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
12939 Log4(("EPT violation with an event pending u64IntInfo=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo));
12940 }
12941 else
12942 {
12943 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
12944 rcStrict1 = VINF_SUCCESS;
12945 return rcStrict1;
12946 }
12947
12948 RTGCPHYS GCPhys = 0;
12949 int rc = VMXReadVmcs64(VMX_VMCS64_EXIT_GUEST_PHYS_ADDR_FULL, &GCPhys);
12950 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12951#if 0
12952 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx); /** @todo Can we do better? */
12953#else
12954 /* Aggressive state sync. for now. */
12955 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
12956 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12957 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12958#endif
12959 AssertRCReturn(rc, rc);
12960
12961 /* Intel spec. Table 27-7 "Exit Qualifications for EPT violations". */
12962 AssertMsg(((pVmxTransient->uExitQualification >> 7) & 3) != 2, ("%#RX64", pVmxTransient->uExitQualification));
12963
12964 RTGCUINT uErrorCode = 0;
12965 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_INSTR_FETCH)
12966 uErrorCode |= X86_TRAP_PF_ID;
12967 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_DATA_WRITE)
12968 uErrorCode |= X86_TRAP_PF_RW;
12969 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_ENTRY_PRESENT)
12970 uErrorCode |= X86_TRAP_PF_P;
12971
12972 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
12973
12974 Log4(("EPT violation %#x at %#RX64 ErrorCode %#x CS:RIP=%04x:%08RX64\n", pVmxTransient->uExitQualification, GCPhys,
12975 uErrorCode, pMixedCtx->cs.Sel, pMixedCtx->rip));
12976
12977 /* Handle the pagefault trap for the nested shadow table. */
12978 PVM pVM = pVCpu->CTX_SUFF(pVM);
12979 VBOXSTRICTRC rcStrict2 = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pMixedCtx), GCPhys);
12980 TRPMResetTrap(pVCpu);
12981
12982 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
12983 if ( rcStrict2 == VINF_SUCCESS
12984 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
12985 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
12986 {
12987 /* Successfully synced our nested page tables. */
12988 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
12989 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
12990 | HM_CHANGED_GUEST_RSP
12991 | HM_CHANGED_GUEST_RFLAGS);
12992 return VINF_SUCCESS;
12993 }
12994
12995 Log4(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)));
12996 return rcStrict2;
12997}
12998
12999/** @} */
13000
13001/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13002/* -=-=-=-=-=-=-=-=-=- VM-exit Exception Handlers -=-=-=-=-=-=-=-=-=-=- */
13003/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13004
13005/** @name VM-exit exception handlers.
13006 * @{
13007 */
13008
13009/**
13010 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
13011 */
13012static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13013{
13014 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13015 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
13016
13017 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
13018 AssertRCReturn(rc, rc);
13019
13020 if (!(pMixedCtx->cr0 & X86_CR0_NE))
13021 {
13022 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
13023 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
13024
13025 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
13026 * provides VM-exit instruction length. If this causes problem later,
13027 * disassemble the instruction like it's done on AMD-V. */
13028 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
13029 AssertRCReturn(rc2, rc2);
13030 return rc;
13031 }
13032
13033 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13034 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13035 return rc;
13036}
13037
13038
13039/**
13040 * VM-exit exception handler for \#BP (Breakpoint exception).
13041 */
13042static int hmR0VmxExitXcptBP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13043{
13044 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13045 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
13046
13047 /** @todo Try optimize this by not saving the entire guest state unless
13048 * really needed. */
13049 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13050 AssertRCReturn(rc, rc);
13051
13052 PVM pVM = pVCpu->CTX_SUFF(pVM);
13053 rc = DBGFRZTrap03Handler(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
13054 if (rc == VINF_EM_RAW_GUEST_TRAP)
13055 {
13056 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13057 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13058 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13059 AssertRCReturn(rc, rc);
13060
13061 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13062 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13063 }
13064
13065 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_EM_DBG_BREAKPOINT);
13066 return rc;
13067}
13068
13069
13070/**
13071 * VM-exit exception handler for \#AC (alignment check exception).
13072 */
13073static int hmR0VmxExitXcptAC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13074{
13075 RT_NOREF_PV(pMixedCtx);
13076 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13077
13078 /*
13079 * Re-inject it. We'll detect any nesting before getting here.
13080 */
13081 int rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13082 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13083 AssertRCReturn(rc, rc);
13084 Assert(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO);
13085
13086 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13087 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13088 return VINF_SUCCESS;
13089}
13090
13091
13092/**
13093 * VM-exit exception handler for \#DB (Debug exception).
13094 */
13095static int hmR0VmxExitXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13096{
13097 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13098 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
13099 Log6(("XcptDB\n"));
13100
13101 /*
13102 * Get the DR6-like values from the VM-exit qualification and pass it to DBGF
13103 * for processing.
13104 */
13105 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
13106 AssertRCReturn(rc, rc);
13107
13108 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
13109 uint64_t uDR6 = X86_DR6_INIT_VAL;
13110 uDR6 |= ( pVmxTransient->uExitQualification
13111 & (X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3 | X86_DR6_BD | X86_DR6_BS));
13112
13113 rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pMixedCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
13114 if (rc == VINF_EM_RAW_GUEST_TRAP)
13115 {
13116 /*
13117 * The exception was for the guest. Update DR6, DR7.GD and
13118 * IA32_DEBUGCTL.LBR before forwarding it.
13119 * (See Intel spec. 27.1 "Architectural State before a VM-Exit".)
13120 */
13121 VMMRZCallRing3Disable(pVCpu);
13122 HM_DISABLE_PREEMPT();
13123
13124 pMixedCtx->dr[6] &= ~X86_DR6_B_MASK;
13125 pMixedCtx->dr[6] |= uDR6;
13126 if (CPUMIsGuestDebugStateActive(pVCpu))
13127 ASMSetDR6(pMixedCtx->dr[6]);
13128
13129 HM_RESTORE_PREEMPT();
13130 VMMRZCallRing3Enable(pVCpu);
13131
13132 rc = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
13133 AssertRCReturn(rc, rc);
13134
13135 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
13136 pMixedCtx->dr[7] &= ~X86_DR7_GD;
13137
13138 /* Paranoia. */
13139 pMixedCtx->dr[7] &= ~X86_DR7_RAZ_MASK;
13140 pMixedCtx->dr[7] |= X86_DR7_RA1_MASK;
13141
13142 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, (uint32_t)pMixedCtx->dr[7]);
13143 AssertRCReturn(rc, rc);
13144
13145 /*
13146 * Raise #DB in the guest.
13147 *
13148 * It is important to reflect what the VM-exit gave us (preserving the interruption-type) rather than use
13149 * hmR0VmxSetPendingXcptDB() as the #DB could've been raised while executing ICEBP and not the 'normal' #DB.
13150 * Thus it -may- trigger different handling in the CPU (like skipped DPL checks). See @bugref{6398}.
13151 *
13152 * Since ICEBP isn't documented on Intel, see AMD spec. 15.20 "Event Injection".
13153 */
13154 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13155 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13156 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13157 AssertRCReturn(rc, rc);
13158 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13159 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13160 return VINF_SUCCESS;
13161 }
13162
13163 /*
13164 * Not a guest trap, must be a hypervisor related debug event then.
13165 * Update DR6 in case someone is interested in it.
13166 */
13167 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
13168 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
13169 CPUMSetHyperDR6(pVCpu, uDR6);
13170
13171 return rc;
13172}
13173
13174
13175/**
13176 * VM-exit exception handler for \#NM (Device-not-available exception: floating
13177 * point exception).
13178 */
13179static int hmR0VmxExitXcptNM(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13180{
13181 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13182
13183 /* We require CR0 and EFER. EFER is always up-to-date. */
13184 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
13185 AssertRCReturn(rc, rc);
13186
13187 /* We're playing with the host CPU state here, have to disable preemption or longjmp. */
13188 VMMRZCallRing3Disable(pVCpu);
13189 HM_DISABLE_PREEMPT();
13190
13191 /* If the guest FPU was active at the time of the #NM VM-exit, then it's a guest fault. */
13192 if (pVmxTransient->fWasGuestFPUStateActive)
13193 {
13194 rc = VINF_EM_RAW_GUEST_TRAP;
13195 Assert(CPUMIsGuestFPUStateActive(pVCpu) || HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0));
13196 }
13197 else
13198 {
13199#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13200 Assert(!pVmxTransient->fWasGuestFPUStateActive || pVCpu->hm.s.fUsingDebugLoop);
13201#endif
13202 rc = CPUMR0Trap07Handler(pVCpu->CTX_SUFF(pVM), pVCpu);
13203 Assert( rc == VINF_EM_RAW_GUEST_TRAP
13204 || ((rc == VINF_SUCCESS || rc == VINF_CPUM_HOST_CR0_MODIFIED) && CPUMIsGuestFPUStateActive(pVCpu)));
13205 if (rc == VINF_CPUM_HOST_CR0_MODIFIED)
13206 HMCPU_CF_SET(pVCpu, HM_CHANGED_HOST_CONTEXT);
13207 }
13208
13209 HM_RESTORE_PREEMPT();
13210 VMMRZCallRing3Enable(pVCpu);
13211
13212 if (rc == VINF_SUCCESS || rc == VINF_CPUM_HOST_CR0_MODIFIED)
13213 {
13214 /* Guest FPU state was activated, we'll want to change CR0 FPU intercepts before the next VM-reentry. */
13215 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
13216 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowNM);
13217 pVCpu->hm.s.fPreloadGuestFpu = true;
13218 }
13219 else
13220 {
13221 /* Forward #NM to the guest. */
13222 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
13223 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13224 AssertRCReturn(rc, rc);
13225 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13226 pVmxTransient->cbInstr, 0 /* error code */, 0 /* GCPtrFaultAddress */);
13227 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNM);
13228 }
13229
13230 return VINF_SUCCESS;
13231}
13232
13233
13234/**
13235 * VM-exit exception handler for \#GP (General-protection exception).
13236 *
13237 * @remarks Requires pVmxTransient->uExitIntInfo to be up-to-date.
13238 */
13239static int hmR0VmxExitXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13240{
13241 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13242 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
13243
13244 int rc;
13245 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
13246 { /* likely */ }
13247 else
13248 {
13249#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13250 Assert(pVCpu->hm.s.fUsingDebugLoop);
13251#endif
13252 /* If the guest is not in real-mode or we have unrestricted execution support, reflect #GP to the guest. */
13253 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13254 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13255 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13256 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13257 AssertRCReturn(rc, rc);
13258 Log4(("#GP Gst: CS:RIP %04x:%08RX64 ErrorCode=%#x CR0=%#RX64 CPL=%u TR=%#04x\n", pMixedCtx->cs.Sel, pMixedCtx->rip,
13259 pVmxTransient->uExitIntErrorCode, pMixedCtx->cr0, CPUMGetGuestCPL(pVCpu), pMixedCtx->tr.Sel));
13260 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13261 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13262 return rc;
13263 }
13264
13265 Assert(CPUMIsGuestInRealModeEx(pMixedCtx));
13266 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
13267
13268 /* EMInterpretDisasCurrent() requires a lot of the state, save the entire state. */
13269 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13270 AssertRCReturn(rc, rc);
13271
13272 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
13273 uint32_t cbOp = 0;
13274 PVM pVM = pVCpu->CTX_SUFF(pVM);
13275 bool fDbgStepping = pVCpu->hm.s.fSingleInstruction;
13276 rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, &cbOp);
13277 if (RT_SUCCESS(rc))
13278 {
13279 rc = VINF_SUCCESS;
13280 Assert(cbOp == pDis->cbInstr);
13281 Log4(("#GP Disas OpCode=%u CS:EIP %04x:%04RX64\n", pDis->pCurInstr->uOpcode, pMixedCtx->cs.Sel, pMixedCtx->rip));
13282 switch (pDis->pCurInstr->uOpcode)
13283 {
13284 case OP_CLI:
13285 {
13286 pMixedCtx->eflags.Bits.u1IF = 0;
13287 pMixedCtx->eflags.Bits.u1RF = 0;
13288 pMixedCtx->rip += pDis->cbInstr;
13289 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13290 if ( !fDbgStepping
13291 && pMixedCtx->eflags.Bits.u1TF)
13292 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13293 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCli);
13294 break;
13295 }
13296
13297 case OP_STI:
13298 {
13299 bool fOldIF = pMixedCtx->eflags.Bits.u1IF;
13300 pMixedCtx->eflags.Bits.u1IF = 1;
13301 pMixedCtx->eflags.Bits.u1RF = 0;
13302 pMixedCtx->rip += pDis->cbInstr;
13303 if (!fOldIF)
13304 {
13305 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
13306 Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
13307 }
13308 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13309 if ( !fDbgStepping
13310 && pMixedCtx->eflags.Bits.u1TF)
13311 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13312 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitSti);
13313 break;
13314 }
13315
13316 case OP_HLT:
13317 {
13318 rc = VINF_EM_HALT;
13319 pMixedCtx->rip += pDis->cbInstr;
13320 pMixedCtx->eflags.Bits.u1RF = 0;
13321 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13322 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
13323 break;
13324 }
13325
13326 case OP_POPF:
13327 {
13328 Log4(("POPF CS:EIP %04x:%04RX64\n", pMixedCtx->cs.Sel, pMixedCtx->rip));
13329 uint32_t cbParm;
13330 uint32_t uMask;
13331 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
13332 if (pDis->fPrefix & DISPREFIX_OPSIZE)
13333 {
13334 cbParm = 4;
13335 uMask = 0xffffffff;
13336 }
13337 else
13338 {
13339 cbParm = 2;
13340 uMask = 0xffff;
13341 }
13342
13343 /* Get the stack pointer & pop the contents of the stack onto Eflags. */
13344 RTGCPTR GCPtrStack = 0;
13345 X86EFLAGS Eflags;
13346 Eflags.u32 = 0;
13347 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
13348 &GCPtrStack);
13349 if (RT_SUCCESS(rc))
13350 {
13351 Assert(sizeof(Eflags.u32) >= cbParm);
13352 rc = VBOXSTRICTRC_TODO(PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &Eflags.u32, cbParm, PGMACCESSORIGIN_HM));
13353 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc)); /** @todo allow strict return codes here */
13354 }
13355 if (RT_FAILURE(rc))
13356 {
13357 rc = VERR_EM_INTERPRETER;
13358 break;
13359 }
13360 Log4(("POPF %#x -> %#RX64 mask=%#x RIP=%#RX64\n", Eflags.u, pMixedCtx->rsp, uMask, pMixedCtx->rip));
13361 pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ~((X86_EFL_POPF_BITS & uMask) | X86_EFL_RF))
13362 | (Eflags.u32 & X86_EFL_POPF_BITS & uMask);
13363 pMixedCtx->esp += cbParm;
13364 pMixedCtx->esp &= uMask;
13365 pMixedCtx->rip += pDis->cbInstr;
13366 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13367 | HM_CHANGED_GUEST_RSP
13368 | HM_CHANGED_GUEST_RFLAGS);
13369 /* Generate a pending-debug exception when the guest stepping over POPF regardless of how
13370 POPF restores EFLAGS.TF. */
13371 if ( !fDbgStepping
13372 && fGstStepping)
13373 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13374 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPopf);
13375 break;
13376 }
13377
13378 case OP_PUSHF:
13379 {
13380 uint32_t cbParm;
13381 uint32_t uMask;
13382 if (pDis->fPrefix & DISPREFIX_OPSIZE)
13383 {
13384 cbParm = 4;
13385 uMask = 0xffffffff;
13386 }
13387 else
13388 {
13389 cbParm = 2;
13390 uMask = 0xffff;
13391 }
13392
13393 /* Get the stack pointer & push the contents of eflags onto the stack. */
13394 RTGCPTR GCPtrStack = 0;
13395 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), (pMixedCtx->esp - cbParm) & uMask,
13396 SELMTOFLAT_FLAGS_CPL0, &GCPtrStack);
13397 if (RT_FAILURE(rc))
13398 {
13399 rc = VERR_EM_INTERPRETER;
13400 break;
13401 }
13402 X86EFLAGS Eflags = pMixedCtx->eflags;
13403 /* The RF & VM bits are cleared on image stored on stack; see Intel Instruction reference for PUSHF. */
13404 Eflags.Bits.u1RF = 0;
13405 Eflags.Bits.u1VM = 0;
13406
13407 rc = VBOXSTRICTRC_TODO(PGMPhysWrite(pVM, (RTGCPHYS)GCPtrStack, &Eflags.u, cbParm, PGMACCESSORIGIN_HM));
13408 if (RT_UNLIKELY(rc != VINF_SUCCESS))
13409 {
13410 AssertMsgFailed(("%Rrc\n", rc)); /** @todo allow strict return codes here */
13411 rc = VERR_EM_INTERPRETER;
13412 break;
13413 }
13414 Log4(("PUSHF %#x -> %#RGv\n", Eflags.u, GCPtrStack));
13415 pMixedCtx->esp -= cbParm;
13416 pMixedCtx->esp &= uMask;
13417 pMixedCtx->rip += pDis->cbInstr;
13418 pMixedCtx->eflags.Bits.u1RF = 0;
13419 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13420 | HM_CHANGED_GUEST_RSP
13421 | HM_CHANGED_GUEST_RFLAGS);
13422 if ( !fDbgStepping
13423 && pMixedCtx->eflags.Bits.u1TF)
13424 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13425 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPushf);
13426 break;
13427 }
13428
13429 case OP_IRET:
13430 {
13431 /** @todo Handle 32-bit operand sizes and check stack limits. See Intel
13432 * instruction reference. */
13433 RTGCPTR GCPtrStack = 0;
13434 uint32_t uMask = 0xffff;
13435 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
13436 uint16_t aIretFrame[3];
13437 if (pDis->fPrefix & (DISPREFIX_OPSIZE | DISPREFIX_ADDRSIZE))
13438 {
13439 rc = VERR_EM_INTERPRETER;
13440 break;
13441 }
13442 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
13443 &GCPtrStack);
13444 if (RT_SUCCESS(rc))
13445 {
13446 rc = VBOXSTRICTRC_TODO(PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &aIretFrame[0], sizeof(aIretFrame),
13447 PGMACCESSORIGIN_HM));
13448 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc)); /** @todo allow strict return codes here */
13449 }
13450 if (RT_FAILURE(rc))
13451 {
13452 rc = VERR_EM_INTERPRETER;
13453 break;
13454 }
13455 pMixedCtx->eip = 0;
13456 pMixedCtx->ip = aIretFrame[0];
13457 pMixedCtx->cs.Sel = aIretFrame[1];
13458 pMixedCtx->cs.ValidSel = aIretFrame[1];
13459 pMixedCtx->cs.u64Base = (uint64_t)pMixedCtx->cs.Sel << 4;
13460 pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ((UINT32_C(0xffff0000) | X86_EFL_1) & ~X86_EFL_RF))
13461 | (aIretFrame[2] & X86_EFL_POPF_BITS & uMask);
13462 pMixedCtx->sp += sizeof(aIretFrame);
13463 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13464 | HM_CHANGED_GUEST_SEGMENT_REGS
13465 | HM_CHANGED_GUEST_RSP
13466 | HM_CHANGED_GUEST_RFLAGS);
13467 /* Generate a pending-debug exception when stepping over IRET regardless of how IRET modifies EFLAGS.TF. */
13468 if ( !fDbgStepping
13469 && fGstStepping)
13470 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13471 Log4(("IRET %#RX32 to %04x:%04x\n", GCPtrStack, pMixedCtx->cs.Sel, pMixedCtx->ip));
13472 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIret);
13473 break;
13474 }
13475
13476 case OP_INT:
13477 {
13478 uint16_t uVector = pDis->Param1.uValue & 0xff;
13479 hmR0VmxSetPendingIntN(pVCpu, pMixedCtx, uVector, pDis->cbInstr);
13480 /* INT clears EFLAGS.TF, we must not set any pending debug exceptions here. */
13481 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
13482 break;
13483 }
13484
13485 case OP_INTO:
13486 {
13487 if (pMixedCtx->eflags.Bits.u1OF)
13488 {
13489 hmR0VmxSetPendingXcptOF(pVCpu, pMixedCtx, pDis->cbInstr);
13490 /* INTO clears EFLAGS.TF, we must not set any pending debug exceptions here. */
13491 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
13492 }
13493 else
13494 {
13495 pMixedCtx->eflags.Bits.u1RF = 0;
13496 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
13497 }
13498 break;
13499 }
13500
13501 default:
13502 {
13503 pMixedCtx->eflags.Bits.u1RF = 0; /* This is correct most of the time... */
13504 VBOXSTRICTRC rc2 = EMInterpretInstructionDisasState(pVCpu, pDis, CPUMCTX2CORE(pMixedCtx), 0 /* pvFault */,
13505 EMCODETYPE_SUPERVISOR);
13506 rc = VBOXSTRICTRC_VAL(rc2);
13507 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
13508 /** @todo We have to set pending-debug exceptions here when the guest is
13509 * single-stepping depending on the instruction that was interpreted. */
13510 Log4(("#GP rc=%Rrc\n", rc));
13511 break;
13512 }
13513 }
13514 }
13515 else
13516 rc = VERR_EM_INTERPRETER;
13517
13518 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_EM_HALT,
13519 ("#GP Unexpected rc=%Rrc\n", rc));
13520 return rc;
13521}
13522
13523
13524/**
13525 * VM-exit exception handler wrapper for generic exceptions. Simply re-injects
13526 * the exception reported in the VMX transient structure back into the VM.
13527 *
13528 * @remarks Requires uExitIntInfo in the VMX transient structure to be
13529 * up-to-date.
13530 */
13531static int hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13532{
13533 RT_NOREF_PV(pMixedCtx);
13534 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13535#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13536 Assert(pVCpu->hm.s.fUsingDebugLoop);
13537#endif
13538
13539 /* Re-inject the exception into the guest. This cannot be a double-fault condition which would have been handled in
13540 hmR0VmxCheckExitDueToEventDelivery(). */
13541 int rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13542 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13543 AssertRCReturn(rc, rc);
13544 Assert(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO);
13545
13546#ifdef DEBUG_ramshankar
13547 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
13548 uint8_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13549 Log(("hmR0VmxExitXcptGeneric: Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
13550#endif
13551
13552 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13553 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13554 return VINF_SUCCESS;
13555}
13556
13557
13558/**
13559 * VM-exit exception handler for \#PF (Page-fault exception).
13560 */
13561static int hmR0VmxExitXcptPF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13562{
13563 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13564 PVM pVM = pVCpu->CTX_SUFF(pVM);
13565 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
13566 rc |= hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13567 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13568 AssertRCReturn(rc, rc);
13569
13570 if (!pVM->hm.s.fNestedPaging)
13571 { /* likely */ }
13572 else
13573 {
13574#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13575 Assert(pVCpu->hm.s.fUsingDebugLoop);
13576#endif
13577 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13578 if (RT_LIKELY(!pVmxTransient->fVectoringDoublePF))
13579 {
13580 pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
13581 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13582 0 /* cbInstr */, pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQualification);
13583 }
13584 else
13585 {
13586 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13587 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
13588 Log4(("Pending #DF due to vectoring #PF. NP\n"));
13589 }
13590 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13591 return rc;
13592 }
13593
13594 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13595 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13596 if (pVmxTransient->fVectoringPF)
13597 {
13598 Assert(pVCpu->hm.s.Event.fPending);
13599 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13600 }
13601
13602 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13603 AssertRCReturn(rc, rc);
13604
13605 Log4(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQualification,
13606 pMixedCtx->cs.Sel, pMixedCtx->rip, pVmxTransient->uExitIntErrorCode, pMixedCtx->cr3));
13607
13608 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQualification, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13609 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pMixedCtx),
13610 (RTGCPTR)pVmxTransient->uExitQualification);
13611
13612 Log4(("#PF: rc=%Rrc\n", rc));
13613 if (rc == VINF_SUCCESS)
13614 {
13615#if 0
13616 /* Successfully synced shadow pages tables or emulated an MMIO instruction. */
13617 /** @todo this isn't quite right, what if guest does lgdt with some MMIO
13618 * memory? We don't update the whole state here... */
13619 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13620 | HM_CHANGED_GUEST_RSP
13621 | HM_CHANGED_GUEST_RFLAGS
13622 | HM_CHANGED_VMX_GUEST_APIC_STATE);
13623#else
13624 /*
13625 * This is typically a shadow page table sync or a MMIO instruction. But we may have
13626 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
13627 */
13628 /** @todo take advantage of CPUM changed flags instead of brute forcing. */
13629 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
13630#endif
13631 TRPMResetTrap(pVCpu);
13632 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
13633 return rc;
13634 }
13635
13636 if (rc == VINF_EM_RAW_GUEST_TRAP)
13637 {
13638 if (!pVmxTransient->fVectoringDoublePF)
13639 {
13640 /* It's a guest page fault and needs to be reflected to the guest. */
13641 uint32_t uGstErrorCode = TRPMGetErrorCode(pVCpu);
13642 TRPMResetTrap(pVCpu);
13643 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
13644 pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
13645 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13646 0 /* cbInstr */, uGstErrorCode, pVmxTransient->uExitQualification);
13647 }
13648 else
13649 {
13650 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13651 TRPMResetTrap(pVCpu);
13652 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
13653 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
13654 Log4(("#PF: Pending #DF due to vectoring #PF\n"));
13655 }
13656
13657 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13658 return VINF_SUCCESS;
13659 }
13660
13661 TRPMResetTrap(pVCpu);
13662 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
13663 return rc;
13664}
13665
13666/** @} */
13667
Note: See TracBrowser for help on using the repository browser.

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