VirtualBox

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

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

bugref:8318 HM: Don't guru when the VMMDev heap is unmapped by 32-bit EFI.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 575.8 KB
Line 
1/* $Id: HMVMXR0.cpp 61013 2016-05-17 20:36:27Z vboxsync $ */
2/** @file
3 * HM VMX (Intel VT-x) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2012-2015 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#ifdef VBOX_WITH_REM
35# include <VBox/vmm/rem.h>
36#endif
37#ifdef VBOX_WITH_NEW_APIC
38# include <VBox/vmm/apic.h>
39#endif
40#include "HMInternal.h"
41#include <VBox/vmm/vm.h>
42#include "HMVMXR0.h"
43#include "dtrace/VBoxVMM.h"
44
45#ifdef DEBUG_ramshankar
46# define HMVMX_ALWAYS_SAVE_GUEST_RFLAGS
47# define HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE
48# define HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
49# define HMVMX_ALWAYS_CHECK_GUEST_STATE
50# define HMVMX_ALWAYS_TRAP_ALL_XCPTS
51# define HMVMX_ALWAYS_TRAP_PF
52# define HMVMX_ALWAYS_SWAP_FPU_STATE
53# define HMVMX_ALWAYS_FLUSH_TLB
54# define HMVMX_ALWAYS_SWAP_EFER
55#endif
56
57
58/*********************************************************************************************************************************
59* Defined Constants And Macros *
60*********************************************************************************************************************************/
61/** Use the function table. */
62#define HMVMX_USE_FUNCTION_TABLE
63
64/** Determine which tagged-TLB flush handler to use. */
65#define HMVMX_FLUSH_TAGGED_TLB_EPT_VPID 0
66#define HMVMX_FLUSH_TAGGED_TLB_EPT 1
67#define HMVMX_FLUSH_TAGGED_TLB_VPID 2
68#define HMVMX_FLUSH_TAGGED_TLB_NONE 3
69
70/** @name Updated-guest-state flags.
71 * @{ */
72#define HMVMX_UPDATED_GUEST_RIP RT_BIT(0)
73#define HMVMX_UPDATED_GUEST_RSP RT_BIT(1)
74#define HMVMX_UPDATED_GUEST_RFLAGS RT_BIT(2)
75#define HMVMX_UPDATED_GUEST_CR0 RT_BIT(3)
76#define HMVMX_UPDATED_GUEST_CR3 RT_BIT(4)
77#define HMVMX_UPDATED_GUEST_CR4 RT_BIT(5)
78#define HMVMX_UPDATED_GUEST_GDTR RT_BIT(6)
79#define HMVMX_UPDATED_GUEST_IDTR RT_BIT(7)
80#define HMVMX_UPDATED_GUEST_LDTR RT_BIT(8)
81#define HMVMX_UPDATED_GUEST_TR RT_BIT(9)
82#define HMVMX_UPDATED_GUEST_SEGMENT_REGS RT_BIT(10)
83#define HMVMX_UPDATED_GUEST_DEBUG RT_BIT(11)
84#define HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR RT_BIT(12)
85#define HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR RT_BIT(13)
86#define HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR RT_BIT(14)
87#define HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS RT_BIT(15)
88#define HMVMX_UPDATED_GUEST_LAZY_MSRS RT_BIT(16)
89#define HMVMX_UPDATED_GUEST_ACTIVITY_STATE RT_BIT(17)
90#define HMVMX_UPDATED_GUEST_INTR_STATE RT_BIT(18)
91#define HMVMX_UPDATED_GUEST_APIC_STATE RT_BIT(19)
92#define HMVMX_UPDATED_GUEST_ALL ( HMVMX_UPDATED_GUEST_RIP \
93 | HMVMX_UPDATED_GUEST_RSP \
94 | HMVMX_UPDATED_GUEST_RFLAGS \
95 | HMVMX_UPDATED_GUEST_CR0 \
96 | HMVMX_UPDATED_GUEST_CR3 \
97 | HMVMX_UPDATED_GUEST_CR4 \
98 | HMVMX_UPDATED_GUEST_GDTR \
99 | HMVMX_UPDATED_GUEST_IDTR \
100 | HMVMX_UPDATED_GUEST_LDTR \
101 | HMVMX_UPDATED_GUEST_TR \
102 | HMVMX_UPDATED_GUEST_SEGMENT_REGS \
103 | HMVMX_UPDATED_GUEST_DEBUG \
104 | HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR \
105 | HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR \
106 | HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR \
107 | HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS \
108 | HMVMX_UPDATED_GUEST_LAZY_MSRS \
109 | HMVMX_UPDATED_GUEST_ACTIVITY_STATE \
110 | HMVMX_UPDATED_GUEST_INTR_STATE \
111 | HMVMX_UPDATED_GUEST_APIC_STATE)
112/** @} */
113
114/** @name
115 * Flags to skip redundant reads of some common VMCS fields that are not part of
116 * the guest-CPU state but are in the transient structure.
117 */
118#define HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO RT_BIT(0)
119#define HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE RT_BIT(1)
120#define HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION RT_BIT(2)
121#define HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN RT_BIT(3)
122#define HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO RT_BIT(4)
123#define HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE RT_BIT(5)
124#define HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_INFO RT_BIT(6)
125/** @} */
126
127/** @name
128 * States of the VMCS.
129 *
130 * This does not reflect all possible VMCS states but currently only those
131 * needed for maintaining the VMCS consistently even when thread-context hooks
132 * are used. Maybe later this can be extended (i.e. Nested Virtualization).
133 */
134#define HMVMX_VMCS_STATE_CLEAR RT_BIT(0)
135#define HMVMX_VMCS_STATE_ACTIVE RT_BIT(1)
136#define HMVMX_VMCS_STATE_LAUNCHED RT_BIT(2)
137/** @} */
138
139/**
140 * Exception bitmap mask for real-mode guests (real-on-v86).
141 *
142 * We need to intercept all exceptions manually except:
143 * - \#NM, \#MF handled in hmR0VmxLoadSharedCR0().
144 * - \#AC and \#DB are always intercepted to prevent the CPU from deadlocking
145 * due to bugs in Intel CPUs.
146 * - \#PF need not be intercepted even in real-mode if we have Nested Paging
147 * support.
148 */
149#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) /* always: | RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI) \
150 | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
151 | RT_BIT(X86_XCPT_UD) /* RT_BIT(X86_XCPT_NM) */ | RT_BIT(X86_XCPT_DF) \
152 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
153 | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
154 /* RT_BIT(X86_XCPT_MF) always: | RT_BIT(X86_XCPT_AC) */ | RT_BIT(X86_XCPT_MC) \
155 | RT_BIT(X86_XCPT_XF))
156
157/**
158 * Exception bitmap mask for all contributory exceptions.
159 *
160 * Page fault is deliberately excluded here as it's conditional as to whether
161 * it's contributory or benign. Page faults are handled separately.
162 */
163#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) \
164 | RT_BIT(X86_XCPT_DE))
165
166/** Maximum VM-instruction error number. */
167#define HMVMX_INSTR_ERROR_MAX 28
168
169/** Profiling macro. */
170#ifdef HM_PROFILE_EXIT_DISPATCH
171# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitDispatch, ed)
172# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitDispatch, ed)
173#else
174# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
175# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
176#endif
177
178/** Assert that preemption is disabled or covered by thread-context hooks. */
179#define HMVMX_ASSERT_PREEMPT_SAFE() Assert( VMMR0ThreadCtxHookIsEnabled(pVCpu) \
180 || !RTThreadPreemptIsEnabled(NIL_RTTHREAD));
181
182/** Assert that we haven't migrated CPUs when thread-context hooks are not
183 * used. */
184#define HMVMX_ASSERT_CPU_SAFE() AssertMsg( VMMR0ThreadCtxHookIsEnabled(pVCpu) \
185 || pVCpu->hm.s.idEnteredCpu == RTMpCpuId(), \
186 ("Illegal migration! Entered on CPU %u Current %u\n", \
187 pVCpu->hm.s.idEnteredCpu, RTMpCpuId())); \
188
189/** Helper macro for VM-exit handlers called unexpectedly. */
190#define HMVMX_RETURN_UNEXPECTED_EXIT() \
191 do { \
192 pVCpu->hm.s.u32HMError = pVmxTransient->uExitReason; \
193 return VERR_VMX_UNEXPECTED_EXIT; \
194 } while (0)
195
196
197/*********************************************************************************************************************************
198* Structures and Typedefs *
199*********************************************************************************************************************************/
200/**
201 * VMX transient state.
202 *
203 * A state structure for holding miscellaneous information across
204 * VMX non-root operation and restored after the transition.
205 */
206typedef struct VMXTRANSIENT
207{
208 /** The host's rflags/eflags. */
209 RTCCUINTREG fEFlags;
210#if HC_ARCH_BITS == 32
211 uint32_t u32Alignment0;
212#endif
213 /** The guest's TPR value used for TPR shadowing. */
214 uint8_t u8GuestTpr;
215 /** Alignment. */
216 uint8_t abAlignment0[7];
217
218 /** The basic VM-exit reason. */
219 uint16_t uExitReason;
220 /** Alignment. */
221 uint16_t u16Alignment0;
222 /** The VM-exit interruption error code. */
223 uint32_t uExitIntErrorCode;
224 /** The VM-exit exit code qualification. */
225 uint64_t uExitQualification;
226
227 /** The VM-exit interruption-information field. */
228 uint32_t uExitIntInfo;
229 /** The VM-exit instruction-length field. */
230 uint32_t cbInstr;
231 /** The VM-exit instruction-information field. */
232 union
233 {
234 /** Plain unsigned int representation. */
235 uint32_t u;
236 /** INS and OUTS information. */
237 struct
238 {
239 uint32_t u7Reserved0 : 7;
240 /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */
241 uint32_t u3AddrSize : 3;
242 uint32_t u5Reserved1 : 5;
243 /** The segment register (X86_SREG_XXX). */
244 uint32_t iSegReg : 3;
245 uint32_t uReserved2 : 14;
246 } StrIo;
247 } ExitInstrInfo;
248 /** Whether the VM-entry failed or not. */
249 bool fVMEntryFailed;
250 /** Alignment. */
251 uint8_t abAlignment1[3];
252
253 /** The VM-entry interruption-information field. */
254 uint32_t uEntryIntInfo;
255 /** The VM-entry exception error code field. */
256 uint32_t uEntryXcptErrorCode;
257 /** The VM-entry instruction length field. */
258 uint32_t cbEntryInstr;
259
260 /** IDT-vectoring information field. */
261 uint32_t uIdtVectoringInfo;
262 /** IDT-vectoring error code. */
263 uint32_t uIdtVectoringErrorCode;
264
265 /** Mask of currently read VMCS fields; HMVMX_UPDATED_TRANSIENT_*. */
266 uint32_t fVmcsFieldsRead;
267
268 /** Whether the guest FPU was active at the time of VM-exit. */
269 bool fWasGuestFPUStateActive;
270 /** Whether the guest debug state was active at the time of VM-exit. */
271 bool fWasGuestDebugStateActive;
272 /** Whether the hyper debug state was active at the time of VM-exit. */
273 bool fWasHyperDebugStateActive;
274 /** Whether TSC-offsetting should be setup before VM-entry. */
275 bool fUpdateTscOffsettingAndPreemptTimer;
276 /** Whether the VM-exit was caused by a page-fault during delivery of a
277 * contributory exception or a page-fault. */
278 bool fVectoringDoublePF;
279 /** Whether the VM-exit was caused by a page-fault during delivery of an
280 * external interrupt or NMI. */
281 bool fVectoringPF;
282} VMXTRANSIENT;
283AssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, sizeof(uint64_t));
284AssertCompileMemberAlignment(VMXTRANSIENT, uExitIntInfo, sizeof(uint64_t));
285AssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntInfo, sizeof(uint64_t));
286AssertCompileMemberAlignment(VMXTRANSIENT, fWasGuestFPUStateActive, sizeof(uint64_t));
287AssertCompileMemberSize(VMXTRANSIENT, ExitInstrInfo, sizeof(uint32_t));
288/** Pointer to VMX transient state. */
289typedef VMXTRANSIENT *PVMXTRANSIENT;
290
291
292/**
293 * MSR-bitmap read permissions.
294 */
295typedef enum VMXMSREXITREAD
296{
297 /** Reading this MSR causes a VM-exit. */
298 VMXMSREXIT_INTERCEPT_READ = 0xb,
299 /** Reading this MSR does not cause a VM-exit. */
300 VMXMSREXIT_PASSTHRU_READ
301} VMXMSREXITREAD;
302/** Pointer to MSR-bitmap read permissions. */
303typedef VMXMSREXITREAD* PVMXMSREXITREAD;
304
305/**
306 * MSR-bitmap write permissions.
307 */
308typedef enum VMXMSREXITWRITE
309{
310 /** Writing to this MSR causes a VM-exit. */
311 VMXMSREXIT_INTERCEPT_WRITE = 0xd,
312 /** Writing to this MSR does not cause a VM-exit. */
313 VMXMSREXIT_PASSTHRU_WRITE
314} VMXMSREXITWRITE;
315/** Pointer to MSR-bitmap write permissions. */
316typedef VMXMSREXITWRITE* PVMXMSREXITWRITE;
317
318
319/**
320 * VMX VM-exit handler.
321 *
322 * @returns Strict VBox status code (i.e. informational status codes too).
323 * @param pVCpu The cross context virtual CPU structure.
324 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
325 * out-of-sync. Make sure to update the required
326 * fields before using them.
327 * @param pVmxTransient Pointer to the VMX-transient structure.
328 */
329#ifndef HMVMX_USE_FUNCTION_TABLE
330typedef DECLINLINE(VBOXSTRICTRC) FNVMXEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
331#else
332typedef DECLCALLBACK(VBOXSTRICTRC) FNVMXEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
333/** Pointer to VM-exit handler. */
334typedef FNVMXEXITHANDLER *PFNVMXEXITHANDLER;
335#endif
336
337/**
338 * VMX VM-exit handler, non-strict status code.
339 *
340 * This is generally the same as FNVMXEXITHANDLER, the NSRC bit is just FYI.
341 *
342 * @returns VBox status code, no informational status code returned.
343 * @param pVCpu The cross context virtual CPU structure.
344 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
345 * out-of-sync. Make sure to update the required
346 * fields before using them.
347 * @param pVmxTransient Pointer to the VMX-transient structure.
348 *
349 * @remarks This is not used on anything returning VERR_EM_INTERPRETER as the
350 * use of that status code will be replaced with VINF_EM_SOMETHING
351 * later when switching over to IEM.
352 */
353#ifndef HMVMX_USE_FUNCTION_TABLE
354typedef DECLINLINE(int) FNVMXEXITHANDLERNSRC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
355#else
356typedef FNVMXEXITHANDLER FNVMXEXITHANDLERNSRC;
357#endif
358
359
360/*********************************************************************************************************************************
361* Internal Functions *
362*********************************************************************************************************************************/
363static void hmR0VmxFlushEpt(PVMCPU pVCpu, VMXFLUSHEPT enmFlush);
364static void hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMXFLUSHVPID enmFlush, RTGCPTR GCPtr);
365static void hmR0VmxClearIntNmiWindowsVmcs(PVMCPU pVCpu);
366static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
367 uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress,
368 bool fStepping, uint32_t *puIntState);
369#if HC_ARCH_BITS == 32
370static int hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu);
371#endif
372#ifndef HMVMX_USE_FUNCTION_TABLE
373DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason);
374# define HMVMX_EXIT_DECL DECLINLINE(VBOXSTRICTRC)
375# define HMVMX_EXIT_NSRC_DECL DECLINLINE(int)
376#else
377# define HMVMX_EXIT_DECL static DECLCALLBACK(VBOXSTRICTRC)
378# define HMVMX_EXIT_NSRC_DECL HMVMX_EXIT_DECL
379#endif
380
381
382/** @name VM-exit handlers.
383 * @{
384 */
385static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmi;
386static FNVMXEXITHANDLER hmR0VmxExitExtInt;
387static FNVMXEXITHANDLER hmR0VmxExitTripleFault;
388static FNVMXEXITHANDLERNSRC hmR0VmxExitInitSignal;
389static FNVMXEXITHANDLERNSRC hmR0VmxExitSipi;
390static FNVMXEXITHANDLERNSRC hmR0VmxExitIoSmi;
391static FNVMXEXITHANDLERNSRC hmR0VmxExitSmi;
392static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindow;
393static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindow;
394static FNVMXEXITHANDLER hmR0VmxExitTaskSwitch;
395static FNVMXEXITHANDLER hmR0VmxExitCpuid;
396static FNVMXEXITHANDLER hmR0VmxExitGetsec;
397static FNVMXEXITHANDLER hmR0VmxExitHlt;
398static FNVMXEXITHANDLERNSRC hmR0VmxExitInvd;
399static FNVMXEXITHANDLER hmR0VmxExitInvlpg;
400static FNVMXEXITHANDLER hmR0VmxExitRdpmc;
401static FNVMXEXITHANDLER hmR0VmxExitVmcall;
402static FNVMXEXITHANDLER hmR0VmxExitRdtsc;
403static FNVMXEXITHANDLERNSRC hmR0VmxExitRsm;
404static FNVMXEXITHANDLERNSRC hmR0VmxExitSetPendingXcptUD;
405static FNVMXEXITHANDLER hmR0VmxExitMovCRx;
406static FNVMXEXITHANDLER hmR0VmxExitMovDRx;
407static FNVMXEXITHANDLER hmR0VmxExitIoInstr;
408static FNVMXEXITHANDLER hmR0VmxExitRdmsr;
409static FNVMXEXITHANDLER hmR0VmxExitWrmsr;
410static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestState;
411static FNVMXEXITHANDLERNSRC hmR0VmxExitErrMsrLoad;
412static FNVMXEXITHANDLERNSRC hmR0VmxExitErrUndefined;
413static FNVMXEXITHANDLER hmR0VmxExitMwait;
414static FNVMXEXITHANDLER hmR0VmxExitMtf;
415static FNVMXEXITHANDLER hmR0VmxExitMonitor;
416static FNVMXEXITHANDLER hmR0VmxExitPause;
417static FNVMXEXITHANDLERNSRC hmR0VmxExitErrMachineCheck;
418static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThreshold;
419static FNVMXEXITHANDLER hmR0VmxExitApicAccess;
420static FNVMXEXITHANDLER hmR0VmxExitXdtrAccess;
421static FNVMXEXITHANDLER hmR0VmxExitXdtrAccess;
422static FNVMXEXITHANDLER hmR0VmxExitEptViolation;
423static FNVMXEXITHANDLER hmR0VmxExitEptMisconfig;
424static FNVMXEXITHANDLER hmR0VmxExitRdtscp;
425static FNVMXEXITHANDLER hmR0VmxExitPreemptTimer;
426static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvd;
427static FNVMXEXITHANDLER hmR0VmxExitXsetbv;
428static FNVMXEXITHANDLER hmR0VmxExitRdrand;
429static FNVMXEXITHANDLER hmR0VmxExitInvpcid;
430/** @} */
431
432static int hmR0VmxExitXcptNM(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
433static int hmR0VmxExitXcptPF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
434static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
435static int hmR0VmxExitXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
436static int hmR0VmxExitXcptBP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
437static int hmR0VmxExitXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
438static int hmR0VmxExitXcptAC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
439static int hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
440static uint32_t hmR0VmxCheckGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx);
441
442
443/*********************************************************************************************************************************
444* Global Variables *
445*********************************************************************************************************************************/
446#ifdef HMVMX_USE_FUNCTION_TABLE
447
448/**
449 * VMX_EXIT dispatch table.
450 */
451static const PFNVMXEXITHANDLER g_apfnVMExitHandlers[VMX_EXIT_MAX + 1] =
452{
453 /* 00 VMX_EXIT_XCPT_OR_NMI */ hmR0VmxExitXcptOrNmi,
454 /* 01 VMX_EXIT_EXT_INT */ hmR0VmxExitExtInt,
455 /* 02 VMX_EXIT_TRIPLE_FAULT */ hmR0VmxExitTripleFault,
456 /* 03 VMX_EXIT_INIT_SIGNAL */ hmR0VmxExitInitSignal,
457 /* 04 VMX_EXIT_SIPI */ hmR0VmxExitSipi,
458 /* 05 VMX_EXIT_IO_SMI */ hmR0VmxExitIoSmi,
459 /* 06 VMX_EXIT_SMI */ hmR0VmxExitSmi,
460 /* 07 VMX_EXIT_INT_WINDOW */ hmR0VmxExitIntWindow,
461 /* 08 VMX_EXIT_NMI_WINDOW */ hmR0VmxExitNmiWindow,
462 /* 09 VMX_EXIT_TASK_SWITCH */ hmR0VmxExitTaskSwitch,
463 /* 10 VMX_EXIT_CPUID */ hmR0VmxExitCpuid,
464 /* 11 VMX_EXIT_GETSEC */ hmR0VmxExitGetsec,
465 /* 12 VMX_EXIT_HLT */ hmR0VmxExitHlt,
466 /* 13 VMX_EXIT_INVD */ hmR0VmxExitInvd,
467 /* 14 VMX_EXIT_INVLPG */ hmR0VmxExitInvlpg,
468 /* 15 VMX_EXIT_RDPMC */ hmR0VmxExitRdpmc,
469 /* 16 VMX_EXIT_RDTSC */ hmR0VmxExitRdtsc,
470 /* 17 VMX_EXIT_RSM */ hmR0VmxExitRsm,
471 /* 18 VMX_EXIT_VMCALL */ hmR0VmxExitVmcall,
472 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitSetPendingXcptUD,
473 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitSetPendingXcptUD,
474 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitSetPendingXcptUD,
475 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitSetPendingXcptUD,
476 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitSetPendingXcptUD,
477 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitSetPendingXcptUD,
478 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitSetPendingXcptUD,
479 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitSetPendingXcptUD,
480 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitSetPendingXcptUD,
481 /* 28 VMX_EXIT_MOV_CRX */ hmR0VmxExitMovCRx,
482 /* 29 VMX_EXIT_MOV_DRX */ hmR0VmxExitMovDRx,
483 /* 30 VMX_EXIT_IO_INSTR */ hmR0VmxExitIoInstr,
484 /* 31 VMX_EXIT_RDMSR */ hmR0VmxExitRdmsr,
485 /* 32 VMX_EXIT_WRMSR */ hmR0VmxExitWrmsr,
486 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ hmR0VmxExitErrInvalidGuestState,
487 /* 34 VMX_EXIT_ERR_MSR_LOAD */ hmR0VmxExitErrMsrLoad,
488 /* 35 UNDEFINED */ hmR0VmxExitErrUndefined,
489 /* 36 VMX_EXIT_MWAIT */ hmR0VmxExitMwait,
490 /* 37 VMX_EXIT_MTF */ hmR0VmxExitMtf,
491 /* 38 UNDEFINED */ hmR0VmxExitErrUndefined,
492 /* 39 VMX_EXIT_MONITOR */ hmR0VmxExitMonitor,
493 /* 40 UNDEFINED */ hmR0VmxExitPause,
494 /* 41 VMX_EXIT_PAUSE */ hmR0VmxExitErrMachineCheck,
495 /* 42 VMX_EXIT_ERR_MACHINE_CHECK */ hmR0VmxExitErrUndefined,
496 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ hmR0VmxExitTprBelowThreshold,
497 /* 44 VMX_EXIT_APIC_ACCESS */ hmR0VmxExitApicAccess,
498 /* 45 UNDEFINED */ hmR0VmxExitErrUndefined,
499 /* 46 VMX_EXIT_XDTR_ACCESS */ hmR0VmxExitXdtrAccess,
500 /* 47 VMX_EXIT_TR_ACCESS */ hmR0VmxExitXdtrAccess,
501 /* 48 VMX_EXIT_EPT_VIOLATION */ hmR0VmxExitEptViolation,
502 /* 49 VMX_EXIT_EPT_MISCONFIG */ hmR0VmxExitEptMisconfig,
503 /* 50 VMX_EXIT_INVEPT */ hmR0VmxExitSetPendingXcptUD,
504 /* 51 VMX_EXIT_RDTSCP */ hmR0VmxExitRdtscp,
505 /* 52 VMX_EXIT_PREEMPT_TIMER */ hmR0VmxExitPreemptTimer,
506 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitSetPendingXcptUD,
507 /* 54 VMX_EXIT_WBINVD */ hmR0VmxExitWbinvd,
508 /* 55 VMX_EXIT_XSETBV */ hmR0VmxExitXsetbv,
509 /* 56 VMX_EXIT_APIC_WRITE */ hmR0VmxExitErrUndefined,
510 /* 57 VMX_EXIT_RDRAND */ hmR0VmxExitRdrand,
511 /* 58 VMX_EXIT_INVPCID */ hmR0VmxExitInvpcid,
512 /* 59 VMX_EXIT_VMFUNC */ hmR0VmxExitSetPendingXcptUD,
513 /* 60 VMX_EXIT_RESERVED_60 */ hmR0VmxExitErrUndefined,
514 /* 61 VMX_EXIT_RDSEED */ hmR0VmxExitErrUndefined, /* only spurious exits, so undefined */
515 /* 62 VMX_EXIT_RESERVED_62 */ hmR0VmxExitErrUndefined,
516 /* 63 VMX_EXIT_XSAVES */ hmR0VmxExitSetPendingXcptUD,
517 /* 64 VMX_EXIT_XRSTORS */ hmR0VmxExitSetPendingXcptUD,
518};
519#endif /* HMVMX_USE_FUNCTION_TABLE */
520
521#ifdef VBOX_STRICT
522static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
523{
524 /* 0 */ "(Not Used)",
525 /* 1 */ "VMCALL executed in VMX root operation.",
526 /* 2 */ "VMCLEAR with invalid physical address.",
527 /* 3 */ "VMCLEAR with VMXON pointer.",
528 /* 4 */ "VMLAUNCH with non-clear VMCS.",
529 /* 5 */ "VMRESUME with non-launched VMCS.",
530 /* 6 */ "VMRESUME after VMXOFF",
531 /* 7 */ "VM-entry with invalid control fields.",
532 /* 8 */ "VM-entry with invalid host state fields.",
533 /* 9 */ "VMPTRLD with invalid physical address.",
534 /* 10 */ "VMPTRLD with VMXON pointer.",
535 /* 11 */ "VMPTRLD with incorrect revision identifier.",
536 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
537 /* 13 */ "VMWRITE to read-only VMCS component.",
538 /* 14 */ "(Not Used)",
539 /* 15 */ "VMXON executed in VMX root operation.",
540 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
541 /* 17 */ "VM-entry with non-launched executing VMCS.",
542 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
543 /* 19 */ "VMCALL with non-clear VMCS.",
544 /* 20 */ "VMCALL with invalid VM-exit control fields.",
545 /* 21 */ "(Not Used)",
546 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
547 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
548 /* 24 */ "VMCALL with invalid SMM-monitor features.",
549 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
550 /* 26 */ "VM-entry with events blocked by MOV SS.",
551 /* 27 */ "(Not Used)",
552 /* 28 */ "Invalid operand to INVEPT/INVVPID."
553};
554#endif /* VBOX_STRICT */
555
556
557
558/**
559 * Updates the VM's last error record.
560 *
561 * If there was a VMX instruction error, reads the error data from the VMCS and
562 * updates VCPU's last error record as well.
563 *
564 * @param pVM The cross context VM structure.
565 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
566 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
567 * VERR_VMX_INVALID_VMCS_FIELD.
568 * @param rc The error code.
569 */
570static void hmR0VmxUpdateErrorRecord(PVM pVM, PVMCPU pVCpu, int rc)
571{
572 AssertPtr(pVM);
573 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
574 || rc == VERR_VMX_UNABLE_TO_START_VM)
575 {
576 AssertPtrReturnVoid(pVCpu);
577 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
578 }
579 pVM->hm.s.lLastError = rc;
580}
581
582
583/**
584 * Reads the VM-entry interruption-information field from the VMCS into the VMX
585 * transient structure.
586 *
587 * @returns VBox status code.
588 * @param pVmxTransient Pointer to the VMX transient structure.
589 *
590 * @remarks No-long-jump zone!!!
591 */
592DECLINLINE(int) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
593{
594 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
595 AssertRCReturn(rc, rc);
596 return VINF_SUCCESS;
597}
598
599
600/**
601 * Reads the VM-entry exception error code field from the VMCS into
602 * the VMX transient structure.
603 *
604 * @returns VBox status code.
605 * @param pVmxTransient Pointer to the VMX transient structure.
606 *
607 * @remarks No-long-jump zone!!!
608 */
609DECLINLINE(int) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
610{
611 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
612 AssertRCReturn(rc, rc);
613 return VINF_SUCCESS;
614}
615
616
617/**
618 * Reads the VM-entry exception error code field from the VMCS into
619 * the VMX transient structure.
620 *
621 * @returns VBox status code.
622 * @param pVmxTransient Pointer to the VMX transient structure.
623 *
624 * @remarks No-long-jump zone!!!
625 */
626DECLINLINE(int) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
627{
628 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
629 AssertRCReturn(rc, rc);
630 return VINF_SUCCESS;
631}
632
633
634/**
635 * Reads the VM-exit interruption-information field from the VMCS into the VMX
636 * transient structure.
637 *
638 * @returns VBox status code.
639 * @param pVmxTransient Pointer to the VMX transient structure.
640 */
641DECLINLINE(int) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
642{
643 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO))
644 {
645 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
646 AssertRCReturn(rc, rc);
647 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO;
648 }
649 return VINF_SUCCESS;
650}
651
652
653/**
654 * Reads the VM-exit interruption error code from the VMCS into the VMX
655 * transient structure.
656 *
657 * @returns VBox status code.
658 * @param pVmxTransient Pointer to the VMX transient structure.
659 */
660DECLINLINE(int) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
661{
662 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE))
663 {
664 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
665 AssertRCReturn(rc, rc);
666 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE;
667 }
668 return VINF_SUCCESS;
669}
670
671
672/**
673 * Reads the VM-exit instruction length field from the VMCS into the VMX
674 * transient structure.
675 *
676 * @returns VBox status code.
677 * @param pVmxTransient Pointer to the VMX transient structure.
678 */
679DECLINLINE(int) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
680{
681 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN))
682 {
683 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbInstr);
684 AssertRCReturn(rc, rc);
685 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN;
686 }
687 return VINF_SUCCESS;
688}
689
690
691/**
692 * Reads the VM-exit instruction-information field from the VMCS into
693 * the VMX transient structure.
694 *
695 * @returns VBox status code.
696 * @param pVmxTransient Pointer to the VMX transient structure.
697 */
698DECLINLINE(int) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
699{
700 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_INFO))
701 {
702 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
703 AssertRCReturn(rc, rc);
704 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_INFO;
705 }
706 return VINF_SUCCESS;
707}
708
709
710/**
711 * Reads the exit code qualification from the VMCS into the VMX transient
712 * structure.
713 *
714 * @returns VBox status code.
715 * @param pVCpu The cross context virtual CPU structure of the
716 * calling EMT. (Required for the VMCS cache case.)
717 * @param pVmxTransient Pointer to the VMX transient structure.
718 */
719DECLINLINE(int) hmR0VmxReadExitQualificationVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
720{
721 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION))
722 {
723 int rc = VMXReadVmcsGstN(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQualification); NOREF(pVCpu);
724 AssertRCReturn(rc, rc);
725 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION;
726 }
727 return VINF_SUCCESS;
728}
729
730
731/**
732 * Reads the IDT-vectoring information field from the VMCS into the VMX
733 * transient structure.
734 *
735 * @returns VBox status code.
736 * @param pVmxTransient Pointer to the VMX transient structure.
737 *
738 * @remarks No-long-jump zone!!!
739 */
740DECLINLINE(int) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
741{
742 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO))
743 {
744 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_INFO, &pVmxTransient->uIdtVectoringInfo);
745 AssertRCReturn(rc, rc);
746 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO;
747 }
748 return VINF_SUCCESS;
749}
750
751
752/**
753 * Reads the IDT-vectoring error code from the VMCS into the VMX
754 * transient structure.
755 *
756 * @returns VBox status code.
757 * @param pVmxTransient Pointer to the VMX transient structure.
758 */
759DECLINLINE(int) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
760{
761 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE))
762 {
763 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
764 AssertRCReturn(rc, rc);
765 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE;
766 }
767 return VINF_SUCCESS;
768}
769
770
771/**
772 * Enters VMX root mode operation on the current CPU.
773 *
774 * @returns VBox status code.
775 * @param pVM The cross context VM structure. Can be
776 * NULL, after a resume.
777 * @param HCPhysCpuPage Physical address of the VMXON region.
778 * @param pvCpuPage Pointer to the VMXON region.
779 */
780static int hmR0VmxEnterRootMode(PVM pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
781{
782 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
783 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
784 Assert(pvCpuPage);
785 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
786
787 if (pVM)
788 {
789 /* Write the VMCS revision dword to the VMXON region. */
790 *(uint32_t *)pvCpuPage = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.Msrs.u64BasicInfo);
791 }
792
793 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
794 RTCCUINTREG fEFlags = ASMIntDisableFlags();
795
796 /* Enable the VMX bit in CR4 if necessary. */
797 RTCCUINTREG uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, ~0);
798
799 /* Enter VMX root mode. */
800 int rc = VMXEnable(HCPhysCpuPage);
801 if (RT_FAILURE(rc))
802 {
803 if (!(uOldCr4 & X86_CR4_VMXE))
804 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
805
806 if (pVM)
807 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
808 }
809
810 /* Restore interrupts. */
811 ASMSetFlags(fEFlags);
812 return rc;
813}
814
815
816/**
817 * Exits VMX root mode operation on the current CPU.
818 *
819 * @returns VBox status code.
820 */
821static int hmR0VmxLeaveRootMode(void)
822{
823 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
824
825 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
826 RTCCUINTREG fEFlags = ASMIntDisableFlags();
827
828 /* If we're for some reason not in VMX root mode, then don't leave it. */
829 RTCCUINTREG uHostCR4 = ASMGetCR4();
830
831 int rc;
832 if (uHostCR4 & X86_CR4_VMXE)
833 {
834 /* Exit VMX root mode and clear the VMX bit in CR4. */
835 VMXDisable();
836 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
837 rc = VINF_SUCCESS;
838 }
839 else
840 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
841
842 /* Restore interrupts. */
843 ASMSetFlags(fEFlags);
844 return rc;
845}
846
847
848/**
849 * Allocates and maps one physically contiguous page. The allocated page is
850 * zero'd out. (Used by various VT-x structures).
851 *
852 * @returns IPRT status code.
853 * @param pMemObj Pointer to the ring-0 memory object.
854 * @param ppVirt Where to store the virtual address of the
855 * allocation.
856 * @param pHCPhys Where to store the physical address of the
857 * allocation.
858 */
859DECLINLINE(int) hmR0VmxPageAllocZ(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
860{
861 AssertPtrReturn(pMemObj, VERR_INVALID_PARAMETER);
862 AssertPtrReturn(ppVirt, VERR_INVALID_PARAMETER);
863 AssertPtrReturn(pHCPhys, VERR_INVALID_PARAMETER);
864
865 int rc = RTR0MemObjAllocCont(pMemObj, PAGE_SIZE, false /* fExecutable */);
866 if (RT_FAILURE(rc))
867 return rc;
868 *ppVirt = RTR0MemObjAddress(*pMemObj);
869 *pHCPhys = RTR0MemObjGetPagePhysAddr(*pMemObj, 0 /* iPage */);
870 ASMMemZero32(*ppVirt, PAGE_SIZE);
871 return VINF_SUCCESS;
872}
873
874
875/**
876 * Frees and unmaps an allocated physical page.
877 *
878 * @param pMemObj Pointer to the ring-0 memory object.
879 * @param ppVirt Where to re-initialize the virtual address of
880 * allocation as 0.
881 * @param pHCPhys Where to re-initialize the physical address of the
882 * allocation as 0.
883 */
884DECLINLINE(void) hmR0VmxPageFree(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
885{
886 AssertPtr(pMemObj);
887 AssertPtr(ppVirt);
888 AssertPtr(pHCPhys);
889 if (*pMemObj != NIL_RTR0MEMOBJ)
890 {
891 int rc = RTR0MemObjFree(*pMemObj, true /* fFreeMappings */);
892 AssertRC(rc);
893 *pMemObj = NIL_RTR0MEMOBJ;
894 *ppVirt = 0;
895 *pHCPhys = 0;
896 }
897}
898
899
900/**
901 * Worker function to free VT-x related structures.
902 *
903 * @returns IPRT status code.
904 * @param pVM The cross context VM structure.
905 */
906static void hmR0VmxStructsFree(PVM pVM)
907{
908 for (VMCPUID i = 0; i < pVM->cCpus; i++)
909 {
910 PVMCPU pVCpu = &pVM->aCpus[i];
911 AssertPtr(pVCpu);
912
913 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjHostMsr, &pVCpu->hm.s.vmx.pvHostMsr, &pVCpu->hm.s.vmx.HCPhysHostMsr);
914 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjGuestMsr, &pVCpu->hm.s.vmx.pvGuestMsr, &pVCpu->hm.s.vmx.HCPhysGuestMsr);
915
916 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
917 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjMsrBitmap, &pVCpu->hm.s.vmx.pvMsrBitmap, &pVCpu->hm.s.vmx.HCPhysMsrBitmap);
918
919 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjVirtApic, (PRTR0PTR)&pVCpu->hm.s.vmx.pbVirtApic, &pVCpu->hm.s.vmx.HCPhysVirtApic);
920 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjVmcs, &pVCpu->hm.s.vmx.pvVmcs, &pVCpu->hm.s.vmx.HCPhysVmcs);
921 }
922
923 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess, &pVM->hm.s.vmx.HCPhysApicAccess);
924#ifdef VBOX_WITH_CRASHDUMP_MAGIC
925 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
926#endif
927}
928
929
930/**
931 * Worker function to allocate VT-x related VM structures.
932 *
933 * @returns IPRT status code.
934 * @param pVM The cross context VM structure.
935 */
936static int hmR0VmxStructsAlloc(PVM pVM)
937{
938 /*
939 * Initialize members up-front so we can cleanup properly on allocation failure.
940 */
941#define VMXLOCAL_INIT_VM_MEMOBJ(a_Name, a_VirtPrefix) \
942 pVM->hm.s.vmx.hMemObj##a_Name = NIL_RTR0MEMOBJ; \
943 pVM->hm.s.vmx.a_VirtPrefix##a_Name = 0; \
944 pVM->hm.s.vmx.HCPhys##a_Name = 0;
945
946#define VMXLOCAL_INIT_VMCPU_MEMOBJ(a_Name, a_VirtPrefix) \
947 pVCpu->hm.s.vmx.hMemObj##a_Name = NIL_RTR0MEMOBJ; \
948 pVCpu->hm.s.vmx.a_VirtPrefix##a_Name = 0; \
949 pVCpu->hm.s.vmx.HCPhys##a_Name = 0;
950
951#ifdef VBOX_WITH_CRASHDUMP_MAGIC
952 VMXLOCAL_INIT_VM_MEMOBJ(Scratch, pv);
953#endif
954 VMXLOCAL_INIT_VM_MEMOBJ(ApicAccess, pb);
955
956 AssertCompile(sizeof(VMCPUID) == sizeof(pVM->cCpus));
957 for (VMCPUID i = 0; i < pVM->cCpus; i++)
958 {
959 PVMCPU pVCpu = &pVM->aCpus[i];
960 VMXLOCAL_INIT_VMCPU_MEMOBJ(Vmcs, pv);
961 VMXLOCAL_INIT_VMCPU_MEMOBJ(VirtApic, pb);
962 VMXLOCAL_INIT_VMCPU_MEMOBJ(MsrBitmap, pv);
963 VMXLOCAL_INIT_VMCPU_MEMOBJ(GuestMsr, pv);
964 VMXLOCAL_INIT_VMCPU_MEMOBJ(HostMsr, pv);
965 }
966#undef VMXLOCAL_INIT_VMCPU_MEMOBJ
967#undef VMXLOCAL_INIT_VM_MEMOBJ
968
969 /* The VMCS size cannot be more than 4096 bytes. See Intel spec. Appendix A.1 "Basic VMX Information". */
970 AssertReturnStmt(MSR_IA32_VMX_BASIC_INFO_VMCS_SIZE(pVM->hm.s.vmx.Msrs.u64BasicInfo) <= PAGE_SIZE,
971 (&pVM->aCpus[0])->hm.s.u32HMError = VMX_UFC_INVALID_VMCS_SIZE,
972 VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO);
973
974 /*
975 * Allocate all the VT-x structures.
976 */
977 int rc = VINF_SUCCESS;
978#ifdef VBOX_WITH_CRASHDUMP_MAGIC
979 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
980 if (RT_FAILURE(rc))
981 goto cleanup;
982 strcpy((char *)pVM->hm.s.vmx.pbScratch, "SCRATCH Magic");
983 *(uint64_t *)(pVM->hm.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
984#endif
985
986 /* Allocate the APIC-access page for trapping APIC accesses from the guest. */
987 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC)
988 {
989 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess,
990 &pVM->hm.s.vmx.HCPhysApicAccess);
991 if (RT_FAILURE(rc))
992 goto cleanup;
993 }
994
995 /*
996 * Initialize per-VCPU VT-x structures.
997 */
998 for (VMCPUID i = 0; i < pVM->cCpus; i++)
999 {
1000 PVMCPU pVCpu = &pVM->aCpus[i];
1001 AssertPtr(pVCpu);
1002
1003 /* Allocate the VM control structure (VMCS). */
1004 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjVmcs, &pVCpu->hm.s.vmx.pvVmcs, &pVCpu->hm.s.vmx.HCPhysVmcs);
1005 if (RT_FAILURE(rc))
1006 goto cleanup;
1007
1008 /* Allocate the Virtual-APIC page for transparent TPR accesses. */
1009 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
1010 {
1011 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjVirtApic, (PRTR0PTR)&pVCpu->hm.s.vmx.pbVirtApic,
1012 &pVCpu->hm.s.vmx.HCPhysVirtApic);
1013 if (RT_FAILURE(rc))
1014 goto cleanup;
1015 }
1016
1017 /*
1018 * Allocate the MSR-bitmap if supported by the CPU. The MSR-bitmap is for
1019 * transparent accesses of specific MSRs.
1020 *
1021 * If the condition for enabling MSR bitmaps changes here, don't forget to
1022 * update HMAreMsrBitmapsAvailable().
1023 */
1024 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1025 {
1026 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjMsrBitmap, &pVCpu->hm.s.vmx.pvMsrBitmap,
1027 &pVCpu->hm.s.vmx.HCPhysMsrBitmap);
1028 if (RT_FAILURE(rc))
1029 goto cleanup;
1030 ASMMemFill32(pVCpu->hm.s.vmx.pvMsrBitmap, PAGE_SIZE, UINT32_C(0xffffffff));
1031 }
1032
1033 /* Allocate the VM-entry MSR-load and VM-exit MSR-store page for the guest MSRs. */
1034 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjGuestMsr, &pVCpu->hm.s.vmx.pvGuestMsr, &pVCpu->hm.s.vmx.HCPhysGuestMsr);
1035 if (RT_FAILURE(rc))
1036 goto cleanup;
1037
1038 /* Allocate the VM-exit MSR-load page for the host MSRs. */
1039 rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjHostMsr, &pVCpu->hm.s.vmx.pvHostMsr, &pVCpu->hm.s.vmx.HCPhysHostMsr);
1040 if (RT_FAILURE(rc))
1041 goto cleanup;
1042 }
1043
1044 return VINF_SUCCESS;
1045
1046cleanup:
1047 hmR0VmxStructsFree(pVM);
1048 return rc;
1049}
1050
1051
1052/**
1053 * Does global VT-x initialization (called during module initialization).
1054 *
1055 * @returns VBox status code.
1056 */
1057VMMR0DECL(int) VMXR0GlobalInit(void)
1058{
1059#ifdef HMVMX_USE_FUNCTION_TABLE
1060 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_apfnVMExitHandlers));
1061# ifdef VBOX_STRICT
1062 for (unsigned i = 0; i < RT_ELEMENTS(g_apfnVMExitHandlers); i++)
1063 Assert(g_apfnVMExitHandlers[i]);
1064# endif
1065#endif
1066 return VINF_SUCCESS;
1067}
1068
1069
1070/**
1071 * Does global VT-x termination (called during module termination).
1072 */
1073VMMR0DECL(void) VMXR0GlobalTerm()
1074{
1075 /* Nothing to do currently. */
1076}
1077
1078
1079/**
1080 * Sets up and activates VT-x on the current CPU.
1081 *
1082 * @returns VBox status code.
1083 * @param pCpu Pointer to the global CPU info struct.
1084 * @param pVM The cross context VM structure. Can be
1085 * NULL after a host resume operation.
1086 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
1087 * fEnabledByHost is @c true).
1088 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
1089 * @a fEnabledByHost is @c true).
1090 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
1091 * enable VT-x on the host.
1092 * @param pvMsrs Opaque pointer to VMXMSRS struct.
1093 */
1094VMMR0DECL(int) VMXR0EnableCpu(PHMGLOBALCPUINFO pCpu, PVM pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
1095 void *pvMsrs)
1096{
1097 Assert(pCpu);
1098 Assert(pvMsrs);
1099 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1100
1101 /* Enable VT-x if it's not already enabled by the host. */
1102 if (!fEnabledByHost)
1103 {
1104 int rc = hmR0VmxEnterRootMode(pVM, HCPhysCpuPage, pvCpuPage);
1105 if (RT_FAILURE(rc))
1106 return rc;
1107 }
1108
1109 /*
1110 * Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been using EPTPs) so
1111 * we don't retain any stale guest-physical mappings which won't get invalidated when flushing by VPID.
1112 */
1113 PVMXMSRS pMsrs = (PVMXMSRS)pvMsrs;
1114 if (pMsrs->u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
1115 {
1116 hmR0VmxFlushEpt(NULL /* pVCpu */, VMXFLUSHEPT_ALL_CONTEXTS);
1117 pCpu->fFlushAsidBeforeUse = false;
1118 }
1119 else
1120 pCpu->fFlushAsidBeforeUse = true;
1121
1122 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
1123 ++pCpu->cTlbFlushes;
1124
1125 return VINF_SUCCESS;
1126}
1127
1128
1129/**
1130 * Deactivates VT-x on the current CPU.
1131 *
1132 * @returns VBox status code.
1133 * @param pCpu Pointer to the global CPU info struct.
1134 * @param pvCpuPage Pointer to the VMXON region.
1135 * @param HCPhysCpuPage Physical address of the VMXON region.
1136 *
1137 * @remarks This function should never be called when SUPR0EnableVTx() or
1138 * similar was used to enable VT-x on the host.
1139 */
1140VMMR0DECL(int) VMXR0DisableCpu(PHMGLOBALCPUINFO pCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
1141{
1142 NOREF(pCpu);
1143 NOREF(pvCpuPage);
1144 NOREF(HCPhysCpuPage);
1145
1146 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1147 return hmR0VmxLeaveRootMode();
1148}
1149
1150
1151/**
1152 * Sets the permission bits for the specified MSR in the MSR bitmap.
1153 *
1154 * @param pVCpu The cross context virtual CPU structure.
1155 * @param uMsr The MSR value.
1156 * @param enmRead Whether reading this MSR causes a VM-exit.
1157 * @param enmWrite Whether writing this MSR causes a VM-exit.
1158 */
1159static void hmR0VmxSetMsrPermission(PVMCPU pVCpu, uint32_t uMsr, VMXMSREXITREAD enmRead, VMXMSREXITWRITE enmWrite)
1160{
1161 int32_t iBit;
1162 uint8_t *pbMsrBitmap = (uint8_t *)pVCpu->hm.s.vmx.pvMsrBitmap;
1163
1164 /*
1165 * Layout:
1166 * 0x000 - 0x3ff - Low MSR read bits
1167 * 0x400 - 0x7ff - High MSR read bits
1168 * 0x800 - 0xbff - Low MSR write bits
1169 * 0xc00 - 0xfff - High MSR write bits
1170 */
1171 if (uMsr <= 0x00001FFF)
1172 iBit = uMsr;
1173 else if (uMsr - UINT32_C(0xC0000000) <= UINT32_C(0x00001FFF))
1174 {
1175 iBit = uMsr - UINT32_C(0xC0000000);
1176 pbMsrBitmap += 0x400;
1177 }
1178 else
1179 AssertMsgFailedReturnVoid(("hmR0VmxSetMsrPermission: Invalid MSR %#RX32\n", uMsr));
1180
1181 Assert(iBit <= 0x1fff);
1182 if (enmRead == VMXMSREXIT_INTERCEPT_READ)
1183 ASMBitSet(pbMsrBitmap, iBit);
1184 else
1185 ASMBitClear(pbMsrBitmap, iBit);
1186
1187 if (enmWrite == VMXMSREXIT_INTERCEPT_WRITE)
1188 ASMBitSet(pbMsrBitmap + 0x800, iBit);
1189 else
1190 ASMBitClear(pbMsrBitmap + 0x800, iBit);
1191}
1192
1193
1194#ifdef VBOX_STRICT
1195/**
1196 * Gets the permission bits for the specified MSR in the MSR bitmap.
1197 *
1198 * @returns VBox status code.
1199 * @retval VINF_SUCCESS if the specified MSR is found.
1200 * @retval VERR_NOT_FOUND if the specified MSR is not found.
1201 * @retval VERR_NOT_SUPPORTED if VT-x doesn't allow the MSR.
1202 *
1203 * @param pVCpu The cross context virtual CPU structure.
1204 * @param uMsr The MSR.
1205 * @param penmRead Where to store the read permissions.
1206 * @param penmWrite Where to store the write permissions.
1207 */
1208static int hmR0VmxGetMsrPermission(PVMCPU pVCpu, uint32_t uMsr, PVMXMSREXITREAD penmRead, PVMXMSREXITWRITE penmWrite)
1209{
1210 AssertPtrReturn(penmRead, VERR_INVALID_PARAMETER);
1211 AssertPtrReturn(penmWrite, VERR_INVALID_PARAMETER);
1212 int32_t iBit;
1213 uint8_t *pbMsrBitmap = (uint8_t *)pVCpu->hm.s.vmx.pvMsrBitmap;
1214
1215 /* See hmR0VmxSetMsrPermission() for the layout. */
1216 if (uMsr <= 0x00001FFF)
1217 iBit = uMsr;
1218 else if ( uMsr >= 0xC0000000
1219 && uMsr <= 0xC0001FFF)
1220 {
1221 iBit = (uMsr - 0xC0000000);
1222 pbMsrBitmap += 0x400;
1223 }
1224 else
1225 AssertMsgFailedReturn(("hmR0VmxGetMsrPermission: Invalid MSR %#RX32\n", uMsr), VERR_NOT_SUPPORTED);
1226
1227 Assert(iBit <= 0x1fff);
1228 if (ASMBitTest(pbMsrBitmap, iBit))
1229 *penmRead = VMXMSREXIT_INTERCEPT_READ;
1230 else
1231 *penmRead = VMXMSREXIT_PASSTHRU_READ;
1232
1233 if (ASMBitTest(pbMsrBitmap + 0x800, iBit))
1234 *penmWrite = VMXMSREXIT_INTERCEPT_WRITE;
1235 else
1236 *penmWrite = VMXMSREXIT_PASSTHRU_WRITE;
1237 return VINF_SUCCESS;
1238}
1239#endif /* VBOX_STRICT */
1240
1241
1242/**
1243 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
1244 * area.
1245 *
1246 * @returns VBox status code.
1247 * @param pVCpu The cross context virtual CPU structure.
1248 * @param cMsrs The number of MSRs.
1249 */
1250DECLINLINE(int) hmR0VmxSetAutoLoadStoreMsrCount(PVMCPU pVCpu, uint32_t cMsrs)
1251{
1252 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
1253 uint32_t const cMaxSupportedMsrs = MSR_IA32_VMX_MISC_MAX_MSR(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc);
1254 if (RT_UNLIKELY(cMsrs > cMaxSupportedMsrs))
1255 {
1256 LogRel(("CPU auto-load/store MSR count in VMCS exceeded cMsrs=%u Supported=%u.\n", cMsrs, cMaxSupportedMsrs));
1257 pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
1258 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
1259 }
1260
1261 /* Update number of guest MSRs to load/store across the world-switch. */
1262 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs);
1263 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs);
1264
1265 /* Update number of host MSRs to load after the world-switch. Identical to guest-MSR count as it's always paired. */
1266 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cMsrs);
1267 AssertRCReturn(rc, rc);
1268
1269 /* Update the VCPU's copy of the MSR count. */
1270 pVCpu->hm.s.vmx.cMsrs = cMsrs;
1271
1272 return VINF_SUCCESS;
1273}
1274
1275
1276/**
1277 * Adds a new (or updates the value of an existing) guest/host MSR
1278 * pair to be swapped during the world-switch as part of the
1279 * auto-load/store MSR area in the VMCS.
1280 *
1281 * @returns VBox status code.
1282 * @param pVCpu The cross context virtual CPU structure.
1283 * @param uMsr The MSR.
1284 * @param uGuestMsrValue Value of the guest MSR.
1285 * @param fUpdateHostMsr Whether to update the value of the host MSR if
1286 * necessary.
1287 * @param pfAddedAndUpdated Where to store whether the MSR was added -and-
1288 * its value was updated. Optional, can be NULL.
1289 */
1290static int hmR0VmxAddAutoLoadStoreMsr(PVMCPU pVCpu, uint32_t uMsr, uint64_t uGuestMsrValue, bool fUpdateHostMsr,
1291 bool *pfAddedAndUpdated)
1292{
1293 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1294 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
1295 uint32_t i;
1296 for (i = 0; i < cMsrs; i++)
1297 {
1298 if (pGuestMsr->u32Msr == uMsr)
1299 break;
1300 pGuestMsr++;
1301 }
1302
1303 bool fAdded = false;
1304 if (i == cMsrs)
1305 {
1306 ++cMsrs;
1307 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, cMsrs);
1308 AssertMsgRCReturn(rc, ("hmR0VmxAddAutoLoadStoreMsr: Insufficient space to add MSR %u\n", uMsr), rc);
1309
1310 /* Now that we're swapping MSRs during the world-switch, allow the guest to read/write them without causing VM-exits. */
1311 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1312 hmR0VmxSetMsrPermission(pVCpu, uMsr, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
1313
1314 fAdded = true;
1315 }
1316
1317 /* Update the MSR values in the auto-load/store MSR area. */
1318 pGuestMsr->u32Msr = uMsr;
1319 pGuestMsr->u64Value = uGuestMsrValue;
1320
1321 /* Create/update the MSR slot in the host MSR area. */
1322 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1323 pHostMsr += i;
1324 pHostMsr->u32Msr = uMsr;
1325
1326 /*
1327 * Update the host MSR only when requested by the caller AND when we're
1328 * adding it to the auto-load/store area. Otherwise, it would have been
1329 * updated by hmR0VmxSaveHostMsrs(). We do this for performance reasons.
1330 */
1331 bool fUpdatedMsrValue = false;
1332 if ( fAdded
1333 && fUpdateHostMsr)
1334 {
1335 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1336 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1337 pHostMsr->u64Value = ASMRdMsr(pHostMsr->u32Msr);
1338 fUpdatedMsrValue = true;
1339 }
1340
1341 if (pfAddedAndUpdated)
1342 *pfAddedAndUpdated = fUpdatedMsrValue;
1343 return VINF_SUCCESS;
1344}
1345
1346
1347/**
1348 * Removes a guest/host MSR pair to be swapped during the world-switch from the
1349 * auto-load/store MSR area in the VMCS.
1350 *
1351 * @returns VBox status code.
1352 * @param pVCpu The cross context virtual CPU structure.
1353 * @param uMsr The MSR.
1354 */
1355static int hmR0VmxRemoveAutoLoadStoreMsr(PVMCPU pVCpu, uint32_t uMsr)
1356{
1357 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1358 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
1359 for (uint32_t i = 0; i < cMsrs; i++)
1360 {
1361 /* Find the MSR. */
1362 if (pGuestMsr->u32Msr == uMsr)
1363 {
1364 /* If it's the last MSR, simply reduce the count. */
1365 if (i == cMsrs - 1)
1366 {
1367 --cMsrs;
1368 break;
1369 }
1370
1371 /* Remove it by swapping the last MSR in place of it, and reducing the count. */
1372 PVMXAUTOMSR pLastGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1373 pLastGuestMsr += cMsrs - 1;
1374 pGuestMsr->u32Msr = pLastGuestMsr->u32Msr;
1375 pGuestMsr->u64Value = pLastGuestMsr->u64Value;
1376
1377 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1378 PVMXAUTOMSR pLastHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1379 pLastHostMsr += cMsrs - 1;
1380 pHostMsr->u32Msr = pLastHostMsr->u32Msr;
1381 pHostMsr->u64Value = pLastHostMsr->u64Value;
1382 --cMsrs;
1383 break;
1384 }
1385 pGuestMsr++;
1386 }
1387
1388 /* Update the VMCS if the count changed (meaning the MSR was found). */
1389 if (cMsrs != pVCpu->hm.s.vmx.cMsrs)
1390 {
1391 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, cMsrs);
1392 AssertRCReturn(rc, rc);
1393
1394 /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
1395 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1396 hmR0VmxSetMsrPermission(pVCpu, uMsr, VMXMSREXIT_INTERCEPT_READ, VMXMSREXIT_INTERCEPT_WRITE);
1397
1398 Log4(("Removed MSR %#RX32 new cMsrs=%u\n", uMsr, pVCpu->hm.s.vmx.cMsrs));
1399 return VINF_SUCCESS;
1400 }
1401
1402 return VERR_NOT_FOUND;
1403}
1404
1405
1406/**
1407 * Checks if the specified guest MSR is part of the auto-load/store area in
1408 * the VMCS.
1409 *
1410 * @returns true if found, false otherwise.
1411 * @param pVCpu The cross context virtual CPU structure.
1412 * @param uMsr The MSR to find.
1413 */
1414static bool hmR0VmxIsAutoLoadStoreGuestMsr(PVMCPU pVCpu, uint32_t uMsr)
1415{
1416 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1417 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
1418
1419 for (uint32_t i = 0; i < cMsrs; i++, pGuestMsr++)
1420 {
1421 if (pGuestMsr->u32Msr == uMsr)
1422 return true;
1423 }
1424 return false;
1425}
1426
1427
1428/**
1429 * Updates the value of all host MSRs in the auto-load/store area in the VMCS.
1430 *
1431 * @param pVCpu The cross context virtual CPU structure.
1432 *
1433 * @remarks No-long-jump zone!!!
1434 */
1435static void hmR0VmxUpdateAutoLoadStoreHostMsrs(PVMCPU pVCpu)
1436{
1437 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1438 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1439 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1440 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
1441
1442 for (uint32_t i = 0; i < cMsrs; i++, pHostMsr++, pGuestMsr++)
1443 {
1444 AssertReturnVoid(pHostMsr->u32Msr == pGuestMsr->u32Msr);
1445
1446 /*
1447 * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
1448 * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
1449 */
1450 if (pHostMsr->u32Msr == MSR_K6_EFER)
1451 pHostMsr->u64Value = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostEfer;
1452 else
1453 pHostMsr->u64Value = ASMRdMsr(pHostMsr->u32Msr);
1454 }
1455
1456 pVCpu->hm.s.vmx.fUpdatedHostMsrs = true;
1457}
1458
1459
1460#if HC_ARCH_BITS == 64
1461/**
1462 * Saves a set of host MSRs to allow read/write passthru access to the guest and
1463 * perform lazy restoration of the host MSRs while leaving VT-x.
1464 *
1465 * @param pVCpu The cross context virtual CPU structure.
1466 *
1467 * @remarks No-long-jump zone!!!
1468 */
1469static void hmR0VmxLazySaveHostMsrs(PVMCPU pVCpu)
1470{
1471 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1472
1473 /*
1474 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap permissions in hmR0VmxSetupProcCtls().
1475 */
1476 if (!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
1477 {
1478 pVCpu->hm.s.vmx.u64HostLStarMsr = ASMRdMsr(MSR_K8_LSTAR);
1479 pVCpu->hm.s.vmx.u64HostStarMsr = ASMRdMsr(MSR_K6_STAR);
1480 pVCpu->hm.s.vmx.u64HostSFMaskMsr = ASMRdMsr(MSR_K8_SF_MASK);
1481 pVCpu->hm.s.vmx.u64HostKernelGSBaseMsr = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
1482 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
1483 }
1484}
1485
1486
1487/**
1488 * Checks whether the MSR belongs to the set of guest MSRs that we restore
1489 * lazily while leaving VT-x.
1490 *
1491 * @returns true if it does, false otherwise.
1492 * @param pVCpu The cross context virtual CPU structure.
1493 * @param uMsr The MSR to check.
1494 */
1495static bool hmR0VmxIsLazyGuestMsr(PVMCPU pVCpu, uint32_t uMsr)
1496{
1497 NOREF(pVCpu);
1498 switch (uMsr)
1499 {
1500 case MSR_K8_LSTAR:
1501 case MSR_K6_STAR:
1502 case MSR_K8_SF_MASK:
1503 case MSR_K8_KERNEL_GS_BASE:
1504 return true;
1505 }
1506 return false;
1507}
1508
1509
1510/**
1511 * Saves a set of guest MSRs back into the guest-CPU context.
1512 *
1513 * @param pVCpu The cross context virtual CPU structure.
1514 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
1515 * out-of-sync. Make sure to update the required fields
1516 * before using them.
1517 *
1518 * @remarks No-long-jump zone!!!
1519 */
1520static void hmR0VmxLazySaveGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
1521{
1522 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1523 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1524
1525 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
1526 {
1527 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
1528 pMixedCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
1529 pMixedCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
1530 pMixedCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
1531 pMixedCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
1532 }
1533}
1534
1535
1536/**
1537 * Loads a set of guests MSRs to allow read/passthru to the guest.
1538 *
1539 * The name of this function is slightly confusing. This function does NOT
1540 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
1541 * common prefix for functions dealing with "lazy restoration" of the shared
1542 * MSRs.
1543 *
1544 * @param pVCpu The cross context virtual CPU structure.
1545 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
1546 * out-of-sync. Make sure to update the required fields
1547 * before using them.
1548 *
1549 * @remarks No-long-jump zone!!!
1550 */
1551static void hmR0VmxLazyLoadGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
1552{
1553 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1554 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1555
1556#define VMXLOCAL_LAZY_LOAD_GUEST_MSR(uMsr, a_GuestMsr, a_HostMsr) \
1557 do { \
1558 if (pMixedCtx->msr##a_GuestMsr != pVCpu->hm.s.vmx.u64Host##a_HostMsr##Msr) \
1559 ASMWrMsr(uMsr, pMixedCtx->msr##a_GuestMsr); \
1560 else \
1561 Assert(ASMRdMsr(uMsr) == pVCpu->hm.s.vmx.u64Host##a_HostMsr##Msr); \
1562 } while (0)
1563
1564 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
1565 if (!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
1566 {
1567 VMXLOCAL_LAZY_LOAD_GUEST_MSR(MSR_K8_LSTAR, LSTAR, LStar);
1568 VMXLOCAL_LAZY_LOAD_GUEST_MSR(MSR_K6_STAR, STAR, Star);
1569 VMXLOCAL_LAZY_LOAD_GUEST_MSR(MSR_K8_SF_MASK, SFMASK, SFMask);
1570 VMXLOCAL_LAZY_LOAD_GUEST_MSR(MSR_K8_KERNEL_GS_BASE, KERNELGSBASE, KernelGSBase);
1571 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
1572 }
1573 else
1574 {
1575 ASMWrMsr(MSR_K8_LSTAR, pMixedCtx->msrLSTAR);
1576 ASMWrMsr(MSR_K6_STAR, pMixedCtx->msrSTAR);
1577 ASMWrMsr(MSR_K8_SF_MASK, pMixedCtx->msrSFMASK);
1578 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pMixedCtx->msrKERNELGSBASE);
1579 }
1580
1581#undef VMXLOCAL_LAZY_LOAD_GUEST_MSR
1582}
1583
1584
1585/**
1586 * Performs lazy restoration of the set of host MSRs if they were previously
1587 * loaded with guest MSR values.
1588 *
1589 * @param pVCpu The cross context virtual CPU structure.
1590 *
1591 * @remarks No-long-jump zone!!!
1592 * @remarks The guest MSRs should have been saved back into the guest-CPU
1593 * context by hmR0VmxSaveGuestLazyMsrs()!!!
1594 */
1595static void hmR0VmxLazyRestoreHostMsrs(PVMCPU pVCpu)
1596{
1597 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1598 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1599
1600 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
1601 {
1602 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
1603 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hm.s.vmx.u64HostLStarMsr);
1604 ASMWrMsr(MSR_K6_STAR, pVCpu->hm.s.vmx.u64HostStarMsr);
1605 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hm.s.vmx.u64HostSFMaskMsr);
1606 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hm.s.vmx.u64HostKernelGSBaseMsr);
1607 }
1608 pVCpu->hm.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
1609}
1610#endif /* HC_ARCH_BITS == 64 */
1611
1612
1613/**
1614 * Verifies that our cached values of the VMCS controls are all
1615 * consistent with what's actually present in the VMCS.
1616 *
1617 * @returns VBox status code.
1618 * @param pVCpu The cross context virtual CPU structure.
1619 */
1620static int hmR0VmxCheckVmcsCtls(PVMCPU pVCpu)
1621{
1622 uint32_t u32Val;
1623 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
1624 AssertRCReturn(rc, rc);
1625 AssertMsgReturn(pVCpu->hm.s.vmx.u32EntryCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32EntryCtls, u32Val),
1626 VERR_VMX_ENTRY_CTLS_CACHE_INVALID);
1627
1628 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
1629 AssertRCReturn(rc, rc);
1630 AssertMsgReturn(pVCpu->hm.s.vmx.u32ExitCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32ExitCtls, u32Val),
1631 VERR_VMX_EXIT_CTLS_CACHE_INVALID);
1632
1633 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
1634 AssertRCReturn(rc, rc);
1635 AssertMsgReturn(pVCpu->hm.s.vmx.u32PinCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32PinCtls, u32Val),
1636 VERR_VMX_PIN_EXEC_CTLS_CACHE_INVALID);
1637
1638 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
1639 AssertRCReturn(rc, rc);
1640 AssertMsgReturn(pVCpu->hm.s.vmx.u32ProcCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32ProcCtls, u32Val),
1641 VERR_VMX_PROC_EXEC_CTLS_CACHE_INVALID);
1642
1643 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
1644 {
1645 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
1646 AssertRCReturn(rc, rc);
1647 AssertMsgReturn(pVCpu->hm.s.vmx.u32ProcCtls2 == u32Val,
1648 ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32ProcCtls2, u32Val),
1649 VERR_VMX_PROC_EXEC2_CTLS_CACHE_INVALID);
1650 }
1651
1652 return VINF_SUCCESS;
1653}
1654
1655
1656#ifdef VBOX_STRICT
1657/**
1658 * Verifies that our cached host EFER value has not changed
1659 * since we cached it.
1660 *
1661 * @param pVCpu The cross context virtual CPU structure.
1662 */
1663static void hmR0VmxCheckHostEferMsr(PVMCPU pVCpu)
1664{
1665 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1666
1667 if (pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR)
1668 {
1669 uint64_t u64Val;
1670 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &u64Val);
1671 AssertRC(rc);
1672
1673 uint64_t u64HostEferMsr = ASMRdMsr(MSR_K6_EFER);
1674 AssertMsgReturnVoid(u64HostEferMsr == u64Val, ("u64HostEferMsr=%#RX64 u64Val=%#RX64\n", u64HostEferMsr, u64Val));
1675 }
1676}
1677
1678
1679/**
1680 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
1681 * VMCS are correct.
1682 *
1683 * @param pVCpu The cross context virtual CPU structure.
1684 */
1685static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPU pVCpu)
1686{
1687 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1688
1689 /* Verify MSR counts in the VMCS are what we think it should be. */
1690 uint32_t cMsrs;
1691 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cMsrs); AssertRC(rc);
1692 Assert(cMsrs == pVCpu->hm.s.vmx.cMsrs);
1693
1694 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cMsrs); AssertRC(rc);
1695 Assert(cMsrs == pVCpu->hm.s.vmx.cMsrs);
1696
1697 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cMsrs); AssertRC(rc);
1698 Assert(cMsrs == pVCpu->hm.s.vmx.cMsrs);
1699
1700 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1701 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1702 for (uint32_t i = 0; i < cMsrs; i++, pHostMsr++, pGuestMsr++)
1703 {
1704 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
1705 AssertMsgReturnVoid(pHostMsr->u32Msr == pGuestMsr->u32Msr, ("HostMsr=%#RX32 GuestMsr=%#RX32 cMsrs=%u\n", pHostMsr->u32Msr,
1706 pGuestMsr->u32Msr, cMsrs));
1707
1708 uint64_t u64Msr = ASMRdMsr(pHostMsr->u32Msr);
1709 AssertMsgReturnVoid(pHostMsr->u64Value == u64Msr, ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
1710 pHostMsr->u32Msr, pHostMsr->u64Value, u64Msr, cMsrs));
1711
1712 /* Verify that the permissions are as expected in the MSR bitmap. */
1713 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1714 {
1715 VMXMSREXITREAD enmRead;
1716 VMXMSREXITWRITE enmWrite;
1717 rc = hmR0VmxGetMsrPermission(pVCpu, pGuestMsr->u32Msr, &enmRead, &enmWrite);
1718 AssertMsgReturnVoid(rc == VINF_SUCCESS, ("hmR0VmxGetMsrPermission! failed. rc=%Rrc\n", rc));
1719 if (pGuestMsr->u32Msr == MSR_K6_EFER)
1720 {
1721 AssertMsgReturnVoid(enmRead == VMXMSREXIT_INTERCEPT_READ, ("Passthru read for EFER!?\n"));
1722 AssertMsgReturnVoid(enmWrite == VMXMSREXIT_INTERCEPT_WRITE, ("Passthru write for EFER!?\n"));
1723 }
1724 else
1725 {
1726 AssertMsgReturnVoid(enmRead == VMXMSREXIT_PASSTHRU_READ, ("u32Msr=%#RX32 cMsrs=%u No passthru read!\n",
1727 pGuestMsr->u32Msr, cMsrs));
1728 AssertMsgReturnVoid(enmWrite == VMXMSREXIT_PASSTHRU_WRITE, ("u32Msr=%#RX32 cMsrs=%u No passthru write!\n",
1729 pGuestMsr->u32Msr, cMsrs));
1730 }
1731 }
1732 }
1733}
1734#endif /* VBOX_STRICT */
1735
1736
1737/**
1738 * Flushes the TLB using EPT.
1739 *
1740 * @returns VBox status code.
1741 * @param pVCpu The cross context virtual CPU structure of the calling
1742 * EMT. Can be NULL depending on @a enmFlush.
1743 * @param enmFlush Type of flush.
1744 *
1745 * @remarks Caller is responsible for making sure this function is called only
1746 * when NestedPaging is supported and providing @a enmFlush that is
1747 * supported by the CPU.
1748 * @remarks Can be called with interrupts disabled.
1749 */
1750static void hmR0VmxFlushEpt(PVMCPU pVCpu, VMXFLUSHEPT enmFlush)
1751{
1752 uint64_t au64Descriptor[2];
1753 if (enmFlush == VMXFLUSHEPT_ALL_CONTEXTS)
1754 au64Descriptor[0] = 0;
1755 else
1756 {
1757 Assert(pVCpu);
1758 au64Descriptor[0] = pVCpu->hm.s.vmx.HCPhysEPTP;
1759 }
1760 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
1761
1762 int rc = VMXR0InvEPT(enmFlush, &au64Descriptor[0]);
1763 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %RGv failed with %Rrc\n", enmFlush, pVCpu ? pVCpu->hm.s.vmx.HCPhysEPTP : 0,
1764 rc));
1765 if ( RT_SUCCESS(rc)
1766 && pVCpu)
1767 {
1768 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
1769 }
1770}
1771
1772
1773/**
1774 * Flushes the TLB using VPID.
1775 *
1776 * @returns VBox status code.
1777 * @param pVM The cross context VM structure.
1778 * @param pVCpu The cross context virtual CPU structure of the calling
1779 * EMT. Can be NULL depending on @a enmFlush.
1780 * @param enmFlush Type of flush.
1781 * @param GCPtr Virtual address of the page to flush (can be 0 depending
1782 * on @a enmFlush).
1783 *
1784 * @remarks Can be called with interrupts disabled.
1785 */
1786static void hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMXFLUSHVPID enmFlush, RTGCPTR GCPtr)
1787{
1788 NOREF(pVM);
1789 AssertPtr(pVM);
1790 Assert(pVM->hm.s.vmx.fVpid);
1791
1792 uint64_t au64Descriptor[2];
1793 if (enmFlush == VMXFLUSHVPID_ALL_CONTEXTS)
1794 {
1795 au64Descriptor[0] = 0;
1796 au64Descriptor[1] = 0;
1797 }
1798 else
1799 {
1800 AssertPtr(pVCpu);
1801 AssertMsg(pVCpu->hm.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
1802 AssertMsg(pVCpu->hm.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
1803 au64Descriptor[0] = pVCpu->hm.s.uCurrentAsid;
1804 au64Descriptor[1] = GCPtr;
1805 }
1806
1807 int rc = VMXR0InvVPID(enmFlush, &au64Descriptor[0]); NOREF(rc);
1808 AssertMsg(rc == VINF_SUCCESS,
1809 ("VMXR0InvVPID %#x %u %RGv failed with %d\n", enmFlush, pVCpu ? pVCpu->hm.s.uCurrentAsid : 0, GCPtr, rc));
1810 if ( RT_SUCCESS(rc)
1811 && pVCpu)
1812 {
1813 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
1814 }
1815}
1816
1817
1818/**
1819 * Invalidates a guest page by guest virtual address. Only relevant for
1820 * EPT/VPID, otherwise there is nothing really to invalidate.
1821 *
1822 * @returns VBox status code.
1823 * @param pVM The cross context VM structure.
1824 * @param pVCpu The cross context virtual CPU structure.
1825 * @param GCVirt Guest virtual address of the page to invalidate.
1826 */
1827VMMR0DECL(int) VMXR0InvalidatePage(PVM pVM, PVMCPU pVCpu, RTGCPTR GCVirt)
1828{
1829 AssertPtr(pVM);
1830 AssertPtr(pVCpu);
1831 LogFlowFunc(("pVM=%p pVCpu=%p GCVirt=%RGv\n", pVM, pVCpu, GCVirt));
1832
1833 bool fFlushPending = VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TLB_FLUSH);
1834 if (!fFlushPending)
1835 {
1836 /*
1837 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for the EPT case
1838 * See @bugref{6043} and @bugref{6177}.
1839 *
1840 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*() as this
1841 * function maybe called in a loop with individual addresses.
1842 */
1843 if (pVM->hm.s.vmx.fVpid)
1844 {
1845 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
1846 {
1847 hmR0VmxFlushVpid(pVM, pVCpu, VMXFLUSHVPID_INDIV_ADDR, GCVirt);
1848 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
1849 }
1850 else
1851 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1852 }
1853 else if (pVM->hm.s.fNestedPaging)
1854 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1855 }
1856
1857 return VINF_SUCCESS;
1858}
1859
1860
1861/**
1862 * Invalidates a guest page by physical address. Only relevant for EPT/VPID,
1863 * otherwise there is nothing really to invalidate.
1864 *
1865 * @returns VBox status code.
1866 * @param pVM The cross context VM structure.
1867 * @param pVCpu The cross context virtual CPU structure.
1868 * @param GCPhys Guest physical address of the page to invalidate.
1869 */
1870VMMR0DECL(int) VMXR0InvalidatePhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
1871{
1872 NOREF(pVM); NOREF(GCPhys);
1873 LogFlowFunc(("%RGp\n", GCPhys));
1874
1875 /*
1876 * We cannot flush a page by guest-physical address. invvpid takes only a linear address while invept only flushes
1877 * by EPT not individual addresses. We update the force flag here and flush before the next VM-entry in hmR0VmxFlushTLB*().
1878 * This function might be called in a loop. This should cause a flush-by-EPT if EPT is in use. See @bugref{6568}.
1879 */
1880 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1881 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgPhys);
1882 return VINF_SUCCESS;
1883}
1884
1885
1886/**
1887 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
1888 * case where neither EPT nor VPID is supported by the CPU.
1889 *
1890 * @param pVM The cross context VM structure.
1891 * @param pVCpu The cross context virtual CPU structure.
1892 * @param pCpu Pointer to the global HM struct.
1893 *
1894 * @remarks Called with interrupts disabled.
1895 */
1896static void hmR0VmxFlushTaggedTlbNone(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
1897{
1898 AssertPtr(pVCpu);
1899 AssertPtr(pCpu);
1900 NOREF(pVM);
1901
1902 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
1903
1904 Assert(pCpu->idCpu != NIL_RTCPUID);
1905 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
1906 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
1907 pVCpu->hm.s.fForceTLBFlush = false;
1908 return;
1909}
1910
1911
1912/**
1913 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
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 CPU struct.
1918 * @remarks All references to "ASID" in this function pertains to "VPID" in
1919 * Intel's nomenclature. The reason is, to avoid confusion in compare
1920 * statements since the host-CPU copies are named "ASID".
1921 *
1922 * @remarks Called with interrupts disabled.
1923 */
1924static void hmR0VmxFlushTaggedTlbBoth(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
1925{
1926#ifdef VBOX_WITH_STATISTICS
1927 bool fTlbFlushed = false;
1928# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
1929# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
1930 if (!fTlbFlushed) \
1931 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
1932 } while (0)
1933#else
1934# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
1935# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
1936#endif
1937
1938 AssertPtr(pVM);
1939 AssertPtr(pCpu);
1940 AssertPtr(pVCpu);
1941 Assert(pCpu->idCpu != NIL_RTCPUID);
1942
1943 AssertMsg(pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid,
1944 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
1945 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hm.s.fNestedPaging, pVM->hm.s.vmx.fVpid));
1946
1947 /*
1948 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
1949 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB
1950 * or the host CPU is online after a suspend/resume, so we cannot reuse the current ASID anymore.
1951 */
1952 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
1953 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
1954 {
1955 ++pCpu->uCurrentAsid;
1956 if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
1957 {
1958 pCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
1959 pCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
1960 pCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
1961 }
1962
1963 pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
1964 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
1965 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
1966
1967 /*
1968 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
1969 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
1970 */
1971 hmR0VmxFlushEpt(pVCpu, pVM->hm.s.vmx.enmFlushEpt);
1972 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
1973 HMVMX_SET_TAGGED_TLB_FLUSHED();
1974 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH); /* Already flushed-by-EPT, skip doing it again below. */
1975 }
1976
1977 /* Check for explicit TLB flushes. */
1978 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
1979 {
1980 /*
1981 * Changes to the EPT paging structure by VMM requires flushing by EPT as the CPU creates
1982 * guest-physical (only EPT-tagged) mappings while traversing the EPT tables when EPT is in use.
1983 * Flushing by VPID will only flush linear (only VPID-tagged) and combined (EPT+VPID tagged) mappings
1984 * but not guest-physical mappings.
1985 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information". See @bugref{6568}.
1986 */
1987 hmR0VmxFlushEpt(pVCpu, pVM->hm.s.vmx.enmFlushEpt);
1988 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
1989 HMVMX_SET_TAGGED_TLB_FLUSHED();
1990 }
1991
1992 pVCpu->hm.s.fForceTLBFlush = false;
1993 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
1994
1995 Assert(pVCpu->hm.s.idLastCpu == pCpu->idCpu);
1996 Assert(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes);
1997 AssertMsg(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes,
1998 ("Flush count mismatch for cpu %d (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
1999 AssertMsg(pCpu->uCurrentAsid >= 1 && pCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
2000 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pCpu->idCpu,
2001 pCpu->uCurrentAsid, pCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
2002 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
2003 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
2004
2005 /* Update VMCS with the VPID. */
2006 int rc = VMXWriteVmcs32(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
2007 AssertRC(rc);
2008
2009#undef HMVMX_SET_TAGGED_TLB_FLUSHED
2010}
2011
2012
2013/**
2014 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
2015 *
2016 * @returns VBox status code.
2017 * @param pVM The cross context VM structure.
2018 * @param pVCpu The cross context virtual CPU structure.
2019 * @param pCpu Pointer to the global HM CPU struct.
2020 *
2021 * @remarks Called with interrupts disabled.
2022 */
2023static void hmR0VmxFlushTaggedTlbEpt(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
2024{
2025 AssertPtr(pVM);
2026 AssertPtr(pVCpu);
2027 AssertPtr(pCpu);
2028 Assert(pCpu->idCpu != NIL_RTCPUID);
2029 AssertMsg(pVM->hm.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with NestedPaging disabled."));
2030 AssertMsg(!pVM->hm.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID enabled."));
2031
2032 /*
2033 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
2034 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
2035 */
2036 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
2037 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
2038 {
2039 pVCpu->hm.s.fForceTLBFlush = true;
2040 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2041 }
2042
2043 /* Check for explicit TLB flushes. */
2044 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2045 {
2046 pVCpu->hm.s.fForceTLBFlush = true;
2047 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2048 }
2049
2050 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
2051 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
2052
2053 if (pVCpu->hm.s.fForceTLBFlush)
2054 {
2055 hmR0VmxFlushEpt(pVCpu, pVM->hm.s.vmx.enmFlushEpt);
2056 pVCpu->hm.s.fForceTLBFlush = false;
2057 }
2058}
2059
2060
2061/**
2062 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
2063 *
2064 * @returns VBox status code.
2065 * @param pVM The cross context VM structure.
2066 * @param pVCpu The cross context virtual CPU structure.
2067 * @param pCpu Pointer to the global HM CPU struct.
2068 *
2069 * @remarks Called with interrupts disabled.
2070 */
2071static void hmR0VmxFlushTaggedTlbVpid(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
2072{
2073 AssertPtr(pVM);
2074 AssertPtr(pVCpu);
2075 AssertPtr(pCpu);
2076 Assert(pCpu->idCpu != NIL_RTCPUID);
2077 AssertMsg(pVM->hm.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked with VPID disabled."));
2078 AssertMsg(!pVM->hm.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging enabled"));
2079
2080 /*
2081 * Force a TLB flush for the first world switch if the current CPU differs from the one we ran on last.
2082 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB
2083 * or the host CPU is online after a suspend/resume, so we cannot reuse the current ASID anymore.
2084 */
2085 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
2086 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
2087 {
2088 pVCpu->hm.s.fForceTLBFlush = true;
2089 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2090 }
2091
2092 /* Check for explicit TLB flushes. */
2093 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2094 {
2095 /*
2096 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see hmR0VmxSetupTaggedTlb())
2097 * we would need to explicitly flush in this case (add an fExplicitFlush = true here and change the
2098 * pCpu->fFlushAsidBeforeUse check below to include fExplicitFlush's too) - an obscure corner case.
2099 */
2100 pVCpu->hm.s.fForceTLBFlush = true;
2101 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2102 }
2103
2104 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
2105 if (pVCpu->hm.s.fForceTLBFlush)
2106 {
2107 ++pCpu->uCurrentAsid;
2108 if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
2109 {
2110 pCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
2111 pCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
2112 pCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
2113 }
2114
2115 pVCpu->hm.s.fForceTLBFlush = false;
2116 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
2117 pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
2118 if (pCpu->fFlushAsidBeforeUse)
2119 {
2120 if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_SINGLE_CONTEXT)
2121 hmR0VmxFlushVpid(pVM, pVCpu, VMXFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
2122 else if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_ALL_CONTEXTS)
2123 {
2124 hmR0VmxFlushVpid(pVM, pVCpu, VMXFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
2125 pCpu->fFlushAsidBeforeUse = false;
2126 }
2127 else
2128 {
2129 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
2130 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
2131 }
2132 }
2133 }
2134
2135 AssertMsg(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes,
2136 ("Flush count mismatch for cpu %d (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
2137 AssertMsg(pCpu->uCurrentAsid >= 1 && pCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
2138 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pCpu->idCpu,
2139 pCpu->uCurrentAsid, pCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
2140 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
2141 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
2142
2143 int rc = VMXWriteVmcs32(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
2144 AssertRC(rc);
2145}
2146
2147
2148/**
2149 * Flushes the guest TLB entry based on CPU capabilities.
2150 *
2151 * @param pVCpu The cross context virtual CPU structure.
2152 * @param pCpu Pointer to the global HM CPU struct.
2153 */
2154DECLINLINE(void) hmR0VmxFlushTaggedTlb(PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
2155{
2156#ifdef HMVMX_ALWAYS_FLUSH_TLB
2157 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2158#endif
2159 PVM pVM = pVCpu->CTX_SUFF(pVM);
2160 switch (pVM->hm.s.vmx.uFlushTaggedTlb)
2161 {
2162 case HMVMX_FLUSH_TAGGED_TLB_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pVM, pVCpu, pCpu); break;
2163 case HMVMX_FLUSH_TAGGED_TLB_EPT: hmR0VmxFlushTaggedTlbEpt(pVM, pVCpu, pCpu); break;
2164 case HMVMX_FLUSH_TAGGED_TLB_VPID: hmR0VmxFlushTaggedTlbVpid(pVM, pVCpu, pCpu); break;
2165 case HMVMX_FLUSH_TAGGED_TLB_NONE: hmR0VmxFlushTaggedTlbNone(pVM, pVCpu, pCpu); break;
2166 default:
2167 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
2168 break;
2169 }
2170
2171 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
2172}
2173
2174
2175/**
2176 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
2177 * TLB entries from the host TLB before VM-entry.
2178 *
2179 * @returns VBox status code.
2180 * @param pVM The cross context VM structure.
2181 */
2182static int hmR0VmxSetupTaggedTlb(PVM pVM)
2183{
2184 /*
2185 * Determine optimal flush type for Nested Paging.
2186 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup unrestricted
2187 * guest execution (see hmR3InitFinalizeR0()).
2188 */
2189 if (pVM->hm.s.fNestedPaging)
2190 {
2191 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
2192 {
2193 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
2194 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_SINGLE_CONTEXT;
2195 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
2196 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_ALL_CONTEXTS;
2197 else
2198 {
2199 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
2200 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2201 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
2202 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2203 }
2204
2205 /* Make sure the write-back cacheable memory type for EPT is supported. */
2206 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB)))
2207 {
2208 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2209 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
2210 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2211 }
2212
2213 /* EPT requires a page-walk length of 4. */
2214 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
2215 {
2216 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2217 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
2218 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2219 }
2220 }
2221 else
2222 {
2223 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
2224 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2225 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
2226 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2227 }
2228 }
2229
2230 /*
2231 * Determine optimal flush type for VPID.
2232 */
2233 if (pVM->hm.s.vmx.fVpid)
2234 {
2235 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
2236 {
2237 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
2238 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_SINGLE_CONTEXT;
2239 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
2240 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_ALL_CONTEXTS;
2241 else
2242 {
2243 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
2244 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
2245 LogRel(("hmR0VmxSetupTaggedTlb: Only INDIV_ADDR supported. Ignoring VPID.\n"));
2246 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
2247 LogRel(("hmR0VmxSetupTaggedTlb: Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
2248 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_NOT_SUPPORTED;
2249 pVM->hm.s.vmx.fVpid = false;
2250 }
2251 }
2252 else
2253 {
2254 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
2255 Log4(("hmR0VmxSetupTaggedTlb: VPID supported without INVEPT support. Ignoring VPID.\n"));
2256 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_NOT_SUPPORTED;
2257 pVM->hm.s.vmx.fVpid = false;
2258 }
2259 }
2260
2261 /*
2262 * Setup the handler for flushing tagged-TLBs.
2263 */
2264 if (pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid)
2265 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_EPT_VPID;
2266 else if (pVM->hm.s.fNestedPaging)
2267 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_EPT;
2268 else if (pVM->hm.s.vmx.fVpid)
2269 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_VPID;
2270 else
2271 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_NONE;
2272 return VINF_SUCCESS;
2273}
2274
2275
2276/**
2277 * Sets up pin-based VM-execution controls in the VMCS.
2278 *
2279 * @returns VBox status code.
2280 * @param pVM The cross context VM structure.
2281 * @param pVCpu The cross context virtual CPU structure.
2282 */
2283static int hmR0VmxSetupPinCtls(PVM pVM, PVMCPU pVCpu)
2284{
2285 AssertPtr(pVM);
2286 AssertPtr(pVCpu);
2287
2288 uint32_t val = pVM->hm.s.vmx.Msrs.VmxPinCtls.n.disallowed0; /* Bits set here must always be set. */
2289 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
2290
2291 val |= VMX_VMCS_CTRL_PIN_EXEC_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
2292 | VMX_VMCS_CTRL_PIN_EXEC_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
2293
2294 if (pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
2295 val |= VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
2296
2297 /* Enable the VMX preemption timer. */
2298 if (pVM->hm.s.vmx.fUsePreemptTimer)
2299 {
2300 Assert(pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_PREEMPT_TIMER);
2301 val |= VMX_VMCS_CTRL_PIN_EXEC_PREEMPT_TIMER;
2302 }
2303
2304#ifdef VBOX_WITH_NEW_APIC
2305#if 0
2306 /* Enable posted-interrupt processing. */
2307 if (pVM->hm.s.fPostedIntrs)
2308 {
2309 Assert(pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_POSTED_INTR);
2310 Assert(pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT);
2311 val |= VMX_VMCS_CTRL_PIN_EXEC_POSTED_INTR;
2312 }
2313#endif
2314#endif
2315
2316 if ((val & zap) != val)
2317 {
2318 LogRel(("hmR0VmxSetupPinCtls: Invalid pin-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
2319 pVM->hm.s.vmx.Msrs.VmxPinCtls.n.disallowed0, val, zap));
2320 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
2321 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2322 }
2323
2324 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, val);
2325 AssertRCReturn(rc, rc);
2326
2327 pVCpu->hm.s.vmx.u32PinCtls = val;
2328 return rc;
2329}
2330
2331
2332/**
2333 * Sets up processor-based VM-execution controls in the VMCS.
2334 *
2335 * @returns VBox status code.
2336 * @param pVM The cross context VM structure.
2337 * @param pVCpu The cross context virtual CPU structure.
2338 */
2339static int hmR0VmxSetupProcCtls(PVM pVM, PVMCPU pVCpu)
2340{
2341 AssertPtr(pVM);
2342 AssertPtr(pVCpu);
2343
2344 int rc = VERR_INTERNAL_ERROR_5;
2345 uint32_t val = pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0; /* Bits set here must be set in the VMCS. */
2346 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2347
2348 val |= VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT /* HLT causes a VM-exit. */
2349 | VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
2350 | VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
2351 | VMX_VMCS_CTRL_PROC_EXEC_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
2352 | VMX_VMCS_CTRL_PROC_EXEC_RDPMC_EXIT /* RDPMC causes a VM-exit. */
2353 | VMX_VMCS_CTRL_PROC_EXEC_MONITOR_EXIT /* MONITOR causes a VM-exit. */
2354 | VMX_VMCS_CTRL_PROC_EXEC_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
2355
2356 /* We toggle VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
2357 if ( !(pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT)
2358 || (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0 & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT))
2359 {
2360 LogRel(("hmR0VmxSetupProcCtls: Unsupported VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT combo!"));
2361 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
2362 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2363 }
2364
2365 /* Without Nested Paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
2366 if (!pVM->hm.s.fNestedPaging)
2367 {
2368 Assert(!pVM->hm.s.vmx.fUnrestrictedGuest); /* Paranoia. */
2369 val |= VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT
2370 | VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
2371 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
2372 }
2373
2374 /* Use TPR shadowing if supported by the CPU. */
2375 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
2376 {
2377 Assert(pVCpu->hm.s.vmx.HCPhysVirtApic);
2378 Assert(!(pVCpu->hm.s.vmx.HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
2379 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, 0);
2380 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VAPIC_PAGEADDR_FULL, pVCpu->hm.s.vmx.HCPhysVirtApic);
2381 AssertRCReturn(rc, rc);
2382
2383 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
2384 /* CR8 writes cause a VM-exit based on TPR threshold. */
2385 Assert(!(val & VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT));
2386 Assert(!(val & VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT));
2387 }
2388 else
2389 {
2390 /*
2391 * Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is invalid on 32-bit Intel CPUs.
2392 * Set this control only for 64-bit guests.
2393 */
2394 if (pVM->hm.s.fAllow64BitGuests)
2395 {
2396 val |= VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
2397 | VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
2398 }
2399 }
2400
2401 /* Use MSR-bitmaps if supported by the CPU. */
2402 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
2403 {
2404 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS;
2405
2406 Assert(pVCpu->hm.s.vmx.HCPhysMsrBitmap);
2407 Assert(!(pVCpu->hm.s.vmx.HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
2408 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, pVCpu->hm.s.vmx.HCPhysMsrBitmap);
2409 AssertRCReturn(rc, rc);
2410
2411 /*
2412 * The guest can access the following MSRs (read, write) without causing VM-exits; they are loaded/stored
2413 * automatically using dedicated fields in the VMCS.
2414 */
2415 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_CS, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2416 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_ESP, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2417 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_EIP, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2418 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2419 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_FS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2420
2421#if HC_ARCH_BITS == 64
2422 /*
2423 * Set passthru permissions for the following MSRs (mandatory for VT-x) required for 64-bit guests.
2424 */
2425 if (pVM->hm.s.fAllow64BitGuests)
2426 {
2427 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_LSTAR, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2428 hmR0VmxSetMsrPermission(pVCpu, MSR_K6_STAR, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2429 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_SF_MASK, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2430 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_KERNEL_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2431 }
2432#endif
2433 }
2434
2435 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
2436 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
2437 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL;
2438
2439 if ((val & zap) != val)
2440 {
2441 LogRel(("hmR0VmxSetupProcCtls: Invalid processor-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
2442 pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0, val, zap));
2443 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
2444 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2445 }
2446
2447 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, val);
2448 AssertRCReturn(rc, rc);
2449
2450 pVCpu->hm.s.vmx.u32ProcCtls = val;
2451
2452 /*
2453 * Secondary processor-based VM-execution controls.
2454 */
2455 if (RT_LIKELY(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL))
2456 {
2457 val = pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.disallowed0; /* Bits set here must be set in the VMCS. */
2458 zap = pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2459
2460 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT)
2461 val |= VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT; /* WBINVD causes a VM-exit. */
2462
2463 if (pVM->hm.s.fNestedPaging)
2464 val |= VMX_VMCS_CTRL_PROC_EXEC2_EPT; /* Enable EPT. */
2465 else
2466 {
2467 /*
2468 * Without Nested Paging, INVPCID should cause a VM-exit. Enabling this bit causes the CPU to refer to
2469 * VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT when INVPCID is executed by the guest.
2470 * See Intel spec. 25.4 "Changes to instruction behaviour in VMX non-root operation".
2471 */
2472 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_INVPCID)
2473 val |= VMX_VMCS_CTRL_PROC_EXEC2_INVPCID;
2474 }
2475
2476 if (pVM->hm.s.vmx.fVpid)
2477 val |= VMX_VMCS_CTRL_PROC_EXEC2_VPID; /* Enable VPID. */
2478
2479 if (pVM->hm.s.vmx.fUnrestrictedGuest)
2480 val |= VMX_VMCS_CTRL_PROC_EXEC2_UNRESTRICTED_GUEST; /* Enable Unrestricted Execution. */
2481
2482#ifdef VBOX_WITH_NEW_APIC
2483#if 0
2484 if (pVM->hm.s.fVirtApicRegs)
2485 {
2486 Assert(pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_APIC_REG_VIRT);
2487 val |= VMX_VMCS_CTRL_PROC_EXEC2_APIC_REG_VIRT; /* Enable APIC-register virtualization. */
2488
2489 Assert(pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_INTR_DELIVERY);
2490 val |= VMX_VMCS_CTRL_PROC_EXEC2_VIRT_INTR_DELIVERY; /* Enable virtual-interrupt delivery. */
2491 }
2492#endif
2493#endif
2494
2495 /* Enable Virtual-APIC page accesses if supported by the CPU. This is essentially where the TPR shadow resides. */
2496 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
2497 * done dynamically. */
2498 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC)
2499 {
2500 Assert(pVM->hm.s.vmx.HCPhysApicAccess);
2501 Assert(!(pVM->hm.s.vmx.HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
2502 val |= VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC; /* Virtualize APIC accesses. */
2503 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, pVM->hm.s.vmx.HCPhysApicAccess);
2504 AssertRCReturn(rc, rc);
2505 }
2506
2507 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP)
2508 val |= VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP; /* Enable RDTSCP support. */
2509
2510 if ( pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_PAUSE_LOOP_EXIT
2511 && pVM->hm.s.vmx.cPleGapTicks
2512 && pVM->hm.s.vmx.cPleWindowTicks)
2513 {
2514 val |= VMX_VMCS_CTRL_PROC_EXEC2_PAUSE_LOOP_EXIT; /* Enable pause-loop exiting. */
2515
2516 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks);
2517 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks);
2518 AssertRCReturn(rc, rc);
2519 }
2520
2521 if ((val & zap) != val)
2522 {
2523 LogRel(("hmR0VmxSetupProcCtls: Invalid secondary processor-based VM-execution controls combo! "
2524 "cpu=%#RX64 val=%#RX64 zap=%#RX64\n", pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.disallowed0, val, zap));
2525 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
2526 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2527 }
2528
2529 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, val);
2530 AssertRCReturn(rc, rc);
2531
2532 pVCpu->hm.s.vmx.u32ProcCtls2 = val;
2533 }
2534 else if (RT_UNLIKELY(pVM->hm.s.vmx.fUnrestrictedGuest))
2535 {
2536 LogRel(("hmR0VmxSetupProcCtls: Unrestricted Guest set as true when secondary processor-based VM-execution controls not "
2537 "available\n"));
2538 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
2539 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2540 }
2541
2542 return VINF_SUCCESS;
2543}
2544
2545
2546/**
2547 * Sets up miscellaneous (everything other than Pin & Processor-based
2548 * VM-execution) control fields in the VMCS.
2549 *
2550 * @returns VBox status code.
2551 * @param pVM The cross context VM structure.
2552 * @param pVCpu The cross context virtual CPU structure.
2553 */
2554static int hmR0VmxSetupMiscCtls(PVM pVM, PVMCPU pVCpu)
2555{
2556 NOREF(pVM);
2557 AssertPtr(pVM);
2558 AssertPtr(pVCpu);
2559
2560 int rc = VERR_GENERAL_FAILURE;
2561
2562 /* All fields are zero-initialized during allocation; but don't remove the commented block below. */
2563#if 0
2564 /* All CR3 accesses cause VM-exits. Later we optimize CR3 accesses (see hmR0VmxLoadGuestCR3AndCR4())*/
2565 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_CR3_TARGET_COUNT, 0);
2566 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, 0);
2567
2568 /*
2569 * Set MASK & MATCH to 0. VMX checks if GuestPFErrCode & MASK == MATCH. If equal (in our case it always is)
2570 * 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.
2571 * We thus use the exception bitmap to control it rather than use both.
2572 */
2573 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, 0);
2574 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, 0);
2575
2576 /** @todo Explore possibility of using IO-bitmaps. */
2577 /* All IO & IOIO instructions cause VM-exits. */
2578 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_IO_BITMAP_A_FULL, 0);
2579 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_IO_BITMAP_B_FULL, 0);
2580
2581 /* Initialize the MSR-bitmap area. */
2582 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, 0);
2583 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, 0);
2584 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, 0);
2585 AssertRCReturn(rc, rc);
2586#endif
2587
2588 /* Setup MSR auto-load/store area. */
2589 Assert(pVCpu->hm.s.vmx.HCPhysGuestMsr);
2590 Assert(!(pVCpu->hm.s.vmx.HCPhysGuestMsr & 0xf)); /* Lower 4 bits MBZ. */
2591 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, pVCpu->hm.s.vmx.HCPhysGuestMsr);
2592 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, pVCpu->hm.s.vmx.HCPhysGuestMsr);
2593 AssertRCReturn(rc, rc);
2594
2595 Assert(pVCpu->hm.s.vmx.HCPhysHostMsr);
2596 Assert(!(pVCpu->hm.s.vmx.HCPhysHostMsr & 0xf)); /* Lower 4 bits MBZ. */
2597 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, pVCpu->hm.s.vmx.HCPhysHostMsr);
2598 AssertRCReturn(rc, rc);
2599
2600 /* Set VMCS link pointer. Reserved for future use, must be -1. Intel spec. 24.4 "Guest-State Area". */
2601 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, UINT64_C(0xffffffffffffffff));
2602 AssertRCReturn(rc, rc);
2603
2604 /* All fields are zero-initialized during allocation; but don't remove the commented block below. */
2605#if 0
2606 /* Setup debug controls */
2607 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, 0); /** @todo We don't support IA32_DEBUGCTL MSR. Should we? */
2608 rc |= VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, 0);
2609 AssertRCReturn(rc, rc);
2610#endif
2611
2612 return rc;
2613}
2614
2615
2616/**
2617 * Sets up the initial exception bitmap in the VMCS based on static conditions.
2618 *
2619 * @returns VBox status code.
2620 * @param pVM The cross context VM structure.
2621 * @param pVCpu The cross context virtual CPU structure.
2622 */
2623static int hmR0VmxInitXcptBitmap(PVM pVM, PVMCPU pVCpu)
2624{
2625 AssertPtr(pVM);
2626 AssertPtr(pVCpu);
2627
2628 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
2629
2630 uint32_t u32XcptBitmap = pVCpu->hm.s.fGIMTrapXcptUD ? RT_BIT(X86_XCPT_UD) : 0;
2631
2632 /* Must always intercept #AC to prevent the guest from hanging the CPU. */
2633 u32XcptBitmap |= RT_BIT_32(X86_XCPT_AC);
2634
2635 /* Because we need to maintain the DR6 state even when intercepting DRx reads
2636 and writes, and because recursive #DBs can cause the CPU hang, we must always
2637 intercept #DB. */
2638 u32XcptBitmap |= RT_BIT_32(X86_XCPT_DB);
2639
2640 /* Without Nested Paging, #PF must cause a VM-exit so we can sync our shadow page tables. */
2641 if (!pVM->hm.s.fNestedPaging)
2642 u32XcptBitmap |= RT_BIT(X86_XCPT_PF);
2643
2644 pVCpu->hm.s.vmx.u32XcptBitmap = u32XcptBitmap;
2645 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
2646 AssertRCReturn(rc, rc);
2647 return rc;
2648}
2649
2650
2651/**
2652 * Sets up the initial guest-state mask. The guest-state mask is consulted
2653 * before reading guest-state fields from the VMCS as VMREADs can be expensive
2654 * for the nested virtualization case (as it would cause a VM-exit).
2655 *
2656 * @param pVCpu The cross context virtual CPU structure.
2657 */
2658static int hmR0VmxInitUpdatedGuestStateMask(PVMCPU pVCpu)
2659{
2660 /* Initially the guest-state is up-to-date as there is nothing in the VMCS. */
2661 HMVMXCPU_GST_RESET_TO(pVCpu, HMVMX_UPDATED_GUEST_ALL);
2662 return VINF_SUCCESS;
2663}
2664
2665
2666/**
2667 * Does per-VM VT-x initialization.
2668 *
2669 * @returns VBox status code.
2670 * @param pVM The cross context VM structure.
2671 */
2672VMMR0DECL(int) VMXR0InitVM(PVM pVM)
2673{
2674 LogFlowFunc(("pVM=%p\n", pVM));
2675
2676 int rc = hmR0VmxStructsAlloc(pVM);
2677 if (RT_FAILURE(rc))
2678 {
2679 LogRel(("VMXR0InitVM: hmR0VmxStructsAlloc failed! rc=%Rrc\n", rc));
2680 return rc;
2681 }
2682
2683 return VINF_SUCCESS;
2684}
2685
2686
2687/**
2688 * Does per-VM VT-x termination.
2689 *
2690 * @returns VBox status code.
2691 * @param pVM The cross context VM structure.
2692 */
2693VMMR0DECL(int) VMXR0TermVM(PVM pVM)
2694{
2695 LogFlowFunc(("pVM=%p\n", pVM));
2696
2697#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2698 if (pVM->hm.s.vmx.hMemObjScratch != NIL_RTR0MEMOBJ)
2699 ASMMemZero32(pVM->hm.s.vmx.pvScratch, PAGE_SIZE);
2700#endif
2701 hmR0VmxStructsFree(pVM);
2702 return VINF_SUCCESS;
2703}
2704
2705
2706/**
2707 * Sets up the VM for execution under VT-x.
2708 * This function is only called once per-VM during initialization.
2709 *
2710 * @returns VBox status code.
2711 * @param pVM The cross context VM structure.
2712 */
2713VMMR0DECL(int) VMXR0SetupVM(PVM pVM)
2714{
2715 AssertPtrReturn(pVM, VERR_INVALID_PARAMETER);
2716 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2717
2718 LogFlowFunc(("pVM=%p\n", pVM));
2719
2720 /*
2721 * Without UnrestrictedGuest, pRealModeTSS and pNonPagingModeEPTPageTable *must* always be allocated.
2722 * We no longer support the highly unlikely case of UnrestrictedGuest without pRealModeTSS. See hmR3InitFinalizeR0Intel().
2723 */
2724 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
2725 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
2726 || !pVM->hm.s.vmx.pRealModeTSS))
2727 {
2728 LogRel(("VMXR0SetupVM: Invalid real-on-v86 state.\n"));
2729 return VERR_INTERNAL_ERROR;
2730 }
2731
2732 /* Initialize these always, see hmR3InitFinalizeR0().*/
2733 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NONE;
2734 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_NONE;
2735
2736 /* Setup the tagged-TLB flush handlers. */
2737 int rc = hmR0VmxSetupTaggedTlb(pVM);
2738 if (RT_FAILURE(rc))
2739 {
2740 LogRel(("VMXR0SetupVM: hmR0VmxSetupTaggedTlb failed! rc=%Rrc\n", rc));
2741 return rc;
2742 }
2743
2744 /* Check if we can use the VMCS controls for swapping the EFER MSR. */
2745 Assert(!pVM->hm.s.vmx.fSupportsVmcsEfer);
2746#if HC_ARCH_BITS == 64
2747 if ( (pVM->hm.s.vmx.Msrs.VmxEntry.n.allowed1 & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR)
2748 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR)
2749 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR))
2750 {
2751 pVM->hm.s.vmx.fSupportsVmcsEfer = true;
2752 }
2753#endif
2754
2755 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
2756 RTCCUINTREG uHostCR4 = ASMGetCR4();
2757 if (RT_UNLIKELY(!(uHostCR4 & X86_CR4_VMXE)))
2758 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
2759
2760 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2761 {
2762 PVMCPU pVCpu = &pVM->aCpus[i];
2763 AssertPtr(pVCpu);
2764 AssertPtr(pVCpu->hm.s.vmx.pvVmcs);
2765
2766 /* Log the VCPU pointers, useful for debugging SMP VMs. */
2767 Log4(("VMXR0SetupVM: pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
2768
2769 /* Initialize the VM-exit history array with end-of-array markers (UINT16_MAX). */
2770 Assert(!pVCpu->hm.s.idxExitHistoryFree);
2771 HMCPU_EXIT_HISTORY_RESET(pVCpu);
2772
2773 /* Set revision dword at the beginning of the VMCS structure. */
2774 *(uint32_t *)pVCpu->hm.s.vmx.pvVmcs = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.Msrs.u64BasicInfo);
2775
2776 /* Initialize our VMCS region in memory, set the VMCS launch state to "clear". */
2777 rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2778 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVmcs failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2779 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2780
2781 /* Load this VMCS as the current VMCS. */
2782 rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2783 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXActivateVmcs failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2784 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2785
2786 rc = hmR0VmxSetupPinCtls(pVM, pVCpu);
2787 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupPinCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2788 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2789
2790 rc = hmR0VmxSetupProcCtls(pVM, pVCpu);
2791 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupProcCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2792 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2793
2794 rc = hmR0VmxSetupMiscCtls(pVM, pVCpu);
2795 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupMiscCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2796 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2797
2798 rc = hmR0VmxInitXcptBitmap(pVM, pVCpu);
2799 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitXcptBitmap failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2800 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2801
2802 rc = hmR0VmxInitUpdatedGuestStateMask(pVCpu);
2803 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitUpdatedGuestStateMask failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2804 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2805
2806#if HC_ARCH_BITS == 32
2807 rc = hmR0VmxInitVmcsReadCache(pVM, pVCpu);
2808 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitVmcsReadCache failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2809 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2810#endif
2811
2812 /* Re-sync the CPU's internal data into our VMCS memory region & reset the launch state to "clear". */
2813 rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2814 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVmcs(2) failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2815 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2816
2817 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
2818
2819 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc);
2820 }
2821
2822 return VINF_SUCCESS;
2823}
2824
2825
2826/**
2827 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
2828 * the VMCS.
2829 *
2830 * @returns VBox status code.
2831 * @param pVM The cross context VM structure.
2832 * @param pVCpu The cross context virtual CPU structure.
2833 */
2834DECLINLINE(int) hmR0VmxSaveHostControlRegs(PVM pVM, PVMCPU pVCpu)
2835{
2836 NOREF(pVM); NOREF(pVCpu);
2837
2838 RTCCUINTREG uReg = ASMGetCR0();
2839 int rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR0, uReg);
2840 AssertRCReturn(rc, rc);
2841
2842 uReg = ASMGetCR3();
2843 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR3, uReg);
2844 AssertRCReturn(rc, rc);
2845
2846 uReg = ASMGetCR4();
2847 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR4, uReg);
2848 AssertRCReturn(rc, rc);
2849 return rc;
2850}
2851
2852
2853#if HC_ARCH_BITS == 64
2854/**
2855 * Macro for adjusting host segment selectors to satisfy VT-x's VM-entry
2856 * requirements. See hmR0VmxSaveHostSegmentRegs().
2857 */
2858# define VMXLOCAL_ADJUST_HOST_SEG(seg, selValue) \
2859 if ((selValue) & (X86_SEL_RPL | X86_SEL_LDT)) \
2860 { \
2861 bool fValidSelector = true; \
2862 if ((selValue) & X86_SEL_LDT) \
2863 { \
2864 uint32_t uAttr = ASMGetSegAttr((selValue)); \
2865 fValidSelector = RT_BOOL(uAttr != UINT32_MAX && (uAttr & X86_DESC_P)); \
2866 } \
2867 if (fValidSelector) \
2868 { \
2869 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##seg; \
2870 pVCpu->hm.s.vmx.RestoreHost.uHostSel##seg = (selValue); \
2871 } \
2872 (selValue) = 0; \
2873 }
2874#endif
2875
2876
2877/**
2878 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
2879 * the host-state area in the VMCS.
2880 *
2881 * @returns VBox status code.
2882 * @param pVM The cross context VM structure.
2883 * @param pVCpu The cross context virtual CPU structure.
2884 */
2885DECLINLINE(int) hmR0VmxSaveHostSegmentRegs(PVM pVM, PVMCPU pVCpu)
2886{
2887 int rc = VERR_INTERNAL_ERROR_5;
2888
2889#if HC_ARCH_BITS == 64
2890 /*
2891 * If we've executed guest code using VT-x, the host-state bits will be messed up. We
2892 * should -not- save the messed up state without restoring the original host-state. See @bugref{7240}.
2893 */
2894 AssertMsgReturn(!(pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED),
2895 ("Re-saving host-state after executing guest code without leaving VT-x!\n"), VERR_WRONG_ORDER);
2896#endif
2897
2898 /*
2899 * Host DS, ES, FS and GS segment registers.
2900 */
2901#if HC_ARCH_BITS == 64
2902 RTSEL uSelDS = ASMGetDS();
2903 RTSEL uSelES = ASMGetES();
2904 RTSEL uSelFS = ASMGetFS();
2905 RTSEL uSelGS = ASMGetGS();
2906#else
2907 RTSEL uSelDS = 0;
2908 RTSEL uSelES = 0;
2909 RTSEL uSelFS = 0;
2910 RTSEL uSelGS = 0;
2911#endif
2912
2913 /* Recalculate which host-state bits need to be manually restored. */
2914 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
2915
2916 /*
2917 * Host CS and SS segment registers.
2918 */
2919 RTSEL uSelCS = ASMGetCS();
2920 RTSEL uSelSS = ASMGetSS();
2921
2922 /*
2923 * Host TR segment register.
2924 */
2925 RTSEL uSelTR = ASMGetTR();
2926
2927#if HC_ARCH_BITS == 64
2928 /*
2929 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to gain VM-entry and restore them
2930 * before we get preempted. See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
2931 */
2932 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
2933 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
2934 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
2935 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
2936# undef VMXLOCAL_ADJUST_HOST_SEG
2937#endif
2938
2939 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
2940 Assert(!(uSelCS & X86_SEL_RPL)); Assert(!(uSelCS & X86_SEL_LDT));
2941 Assert(!(uSelSS & X86_SEL_RPL)); Assert(!(uSelSS & X86_SEL_LDT));
2942 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
2943 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
2944 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
2945 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
2946 Assert(!(uSelTR & X86_SEL_RPL)); Assert(!(uSelTR & X86_SEL_LDT));
2947 Assert(uSelCS);
2948 Assert(uSelTR);
2949
2950 /* Assertion is right but we would not have updated u32ExitCtls yet. */
2951#if 0
2952 if (!(pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE))
2953 Assert(uSelSS != 0);
2954#endif
2955
2956 /* Write these host selector fields into the host-state area in the VMCS. */
2957 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_CS_SEL, uSelCS);
2958 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_SS_SEL, uSelSS);
2959#if HC_ARCH_BITS == 64
2960 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_DS_SEL, uSelDS);
2961 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_ES_SEL, uSelES);
2962 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_FS_SEL, uSelFS);
2963 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_GS_SEL, uSelGS);
2964#else
2965 NOREF(uSelDS);
2966 NOREF(uSelES);
2967 NOREF(uSelFS);
2968 NOREF(uSelGS);
2969#endif
2970 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_TR_SEL, uSelTR);
2971 AssertRCReturn(rc, rc);
2972
2973 /*
2974 * Host GDTR and IDTR.
2975 */
2976 RTGDTR Gdtr;
2977 RTIDTR Idtr;
2978 RT_ZERO(Gdtr);
2979 RT_ZERO(Idtr);
2980 ASMGetGDTR(&Gdtr);
2981 ASMGetIDTR(&Idtr);
2982 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_GDTR_BASE, Gdtr.pGdt);
2983 rc |= VMXWriteVmcsHstN(VMX_VMCS_HOST_IDTR_BASE, Idtr.pIdt);
2984 AssertRCReturn(rc, rc);
2985
2986#if HC_ARCH_BITS == 64
2987 /*
2988 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps them to the
2989 * maximum limit (0xffff) on every VM-exit.
2990 */
2991 if (Gdtr.cbGdt != 0xffff)
2992 {
2993 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
2994 AssertCompile(sizeof(Gdtr) == sizeof(X86XDTR64));
2995 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
2996 }
2997
2998 /*
2999 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT"
3000 * and Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit as 0xfff, VT-x
3001 * bloating the limit to 0xffff shouldn't cause any different CPU behavior. However, several hosts either insists
3002 * on 0xfff being the limit (Windows Patch Guard) or uses the limit for other purposes (darwin puts the CPU ID in there
3003 * but botches sidt alignment in at least one consumer). So, we're only allowing IDTR.LIMIT to be left at 0xffff on
3004 * hosts where we are pretty sure it won't cause trouble.
3005 */
3006# if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
3007 if (Idtr.cbIdt < 0x0fff)
3008# else
3009 if (Idtr.cbIdt != 0xffff)
3010# endif
3011 {
3012 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
3013 AssertCompile(sizeof(Idtr) == sizeof(X86XDTR64));
3014 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostIdtr, &Idtr, sizeof(X86XDTR64));
3015 }
3016#endif
3017
3018 /*
3019 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI and RPL bits
3020 * is effectively what the CPU does for "scaling by 8". TI is always 0 and RPL should be too in most cases.
3021 */
3022 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= Gdtr.cbGdt,
3023 ("hmR0VmxSaveHostSegmentRegs: TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, Gdtr.cbGdt),
3024 VERR_VMX_INVALID_HOST_STATE);
3025
3026 PCX86DESCHC pDesc = (PCX86DESCHC)(Gdtr.pGdt + (uSelTR & X86_SEL_MASK));
3027#if HC_ARCH_BITS == 64
3028 uintptr_t uTRBase = X86DESC64_BASE(pDesc);
3029
3030 /*
3031 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on all VM-exits.
3032 * The type is the same for 64-bit busy TSS[1]. The limit needs manual restoration if the host has something else.
3033 * Task switching is not supported in 64-bit mode[2], but the limit still matters as IOPM is supported in 64-bit mode.
3034 * Restoring the limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
3035 *
3036 * [1] See Intel spec. 3.5 "System Descriptor Types".
3037 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
3038 */
3039 Assert(pDesc->System.u4Type == 11);
3040 if ( pDesc->System.u16LimitLow != 0x67
3041 || pDesc->System.u4LimitHigh)
3042 {
3043 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
3044 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
3045 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
3046 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
3047 pVCpu->hm.s.vmx.RestoreHost.uHostSelTR = uSelTR;
3048
3049 /* Store the GDTR here as we need it while restoring TR. */
3050 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
3051 }
3052#else
3053 NOREF(pVM);
3054 uintptr_t uTRBase = X86DESC_BASE(pDesc);
3055#endif
3056 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_TR_BASE, uTRBase);
3057 AssertRCReturn(rc, rc);
3058
3059 /*
3060 * Host FS base and GS base.
3061 */
3062#if HC_ARCH_BITS == 64
3063 uint64_t u64FSBase = ASMRdMsr(MSR_K8_FS_BASE);
3064 uint64_t u64GSBase = ASMRdMsr(MSR_K8_GS_BASE);
3065 rc = VMXWriteVmcs64(VMX_VMCS_HOST_FS_BASE, u64FSBase);
3066 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_GS_BASE, u64GSBase);
3067 AssertRCReturn(rc, rc);
3068
3069 /* Store the base if we have to restore FS or GS manually as we need to restore the base as well. */
3070 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_FS)
3071 pVCpu->hm.s.vmx.RestoreHost.uHostFSBase = u64FSBase;
3072 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_GS)
3073 pVCpu->hm.s.vmx.RestoreHost.uHostGSBase = u64GSBase;
3074#endif
3075 return rc;
3076}
3077
3078
3079/**
3080 * Saves certain host MSRs in the VM-Exit MSR-load area and some in the
3081 * host-state area of the VMCS. Theses MSRs will be automatically restored on
3082 * the host after every successful VM-exit.
3083 *
3084 * @returns VBox status code.
3085 * @param pVM The cross context VM structure.
3086 * @param pVCpu The cross context virtual CPU structure.
3087 *
3088 * @remarks No-long-jump zone!!!
3089 */
3090DECLINLINE(int) hmR0VmxSaveHostMsrs(PVM pVM, PVMCPU pVCpu)
3091{
3092 NOREF(pVM);
3093
3094 AssertPtr(pVCpu);
3095 AssertPtr(pVCpu->hm.s.vmx.pvHostMsr);
3096
3097 int rc = VINF_SUCCESS;
3098#if HC_ARCH_BITS == 64
3099 if (pVM->hm.s.fAllow64BitGuests)
3100 hmR0VmxLazySaveHostMsrs(pVCpu);
3101#endif
3102
3103 /*
3104 * Host Sysenter MSRs.
3105 */
3106 rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS));
3107#if HC_ARCH_BITS == 32
3108 rc |= VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP));
3109 rc |= VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP));
3110#else
3111 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP));
3112 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP));
3113#endif
3114 AssertRCReturn(rc, rc);
3115
3116 /*
3117 * Host EFER MSR.
3118 * If the CPU supports the newer VMCS controls for managing EFER, use it.
3119 * Otherwise it's done as part of auto-load/store MSR area in the VMCS, see hmR0VmxLoadGuestMsrs().
3120 */
3121 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
3122 {
3123 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, pVM->hm.s.vmx.u64HostEfer);
3124 AssertRCReturn(rc, rc);
3125 }
3126
3127 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
3128 * hmR0VmxLoadGuestExitCtls() !! */
3129
3130 return rc;
3131}
3132
3133
3134/**
3135 * Figures out if we need to swap the EFER MSR which is particularly expensive.
3136 *
3137 * We check all relevant bits. For now, that's everything besides LMA/LME, as
3138 * these two bits are handled by VM-entry, see hmR0VmxLoadGuestExitCtls() and
3139 * hmR0VMxLoadGuestEntryCtls().
3140 *
3141 * @returns true if we need to load guest EFER, false otherwise.
3142 * @param pVCpu The cross context virtual CPU structure.
3143 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3144 * out-of-sync. Make sure to update the required fields
3145 * before using them.
3146 *
3147 * @remarks Requires EFER, CR4.
3148 * @remarks No-long-jump zone!!!
3149 */
3150static bool hmR0VmxShouldSwapEferMsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3151{
3152#ifdef HMVMX_ALWAYS_SWAP_EFER
3153 return true;
3154#endif
3155
3156#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
3157 /* For 32-bit hosts running 64-bit guests, we always swap EFER in the world-switcher. Nothing to do here. */
3158 if (CPUMIsGuestInLongMode(pVCpu))
3159 return false;
3160#endif
3161
3162 PVM pVM = pVCpu->CTX_SUFF(pVM);
3163 uint64_t u64HostEfer = pVM->hm.s.vmx.u64HostEfer;
3164 uint64_t u64GuestEfer = pMixedCtx->msrEFER;
3165
3166 /*
3167 * For 64-bit guests, if EFER.SCE bit differs, we need to swap to ensure that the
3168 * guest's SYSCALL behaviour isn't screwed. See @bugref{7386}.
3169 */
3170 if ( CPUMIsGuestInLongMode(pVCpu)
3171 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
3172 {
3173 return true;
3174 }
3175
3176 /*
3177 * If the guest uses PAE and EFER.NXE bit differs, we need to swap EFER as it
3178 * affects guest paging. 64-bit paging implies CR4.PAE as well.
3179 * See Intel spec. 4.5 "IA-32e Paging" and Intel spec. 4.1.1 "Three Paging Modes".
3180 */
3181 if ( (pMixedCtx->cr4 & X86_CR4_PAE)
3182 && (pMixedCtx->cr0 & X86_CR0_PG)
3183 && (u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
3184 {
3185 /* Assert that host is PAE capable. */
3186 Assert(pVM->hm.s.cpuid.u32AMDFeatureEDX & X86_CPUID_EXT_FEATURE_EDX_NX);
3187 return true;
3188 }
3189
3190 /** @todo Check the latest Intel spec. for any other bits,
3191 * like SMEP/SMAP? */
3192 return false;
3193}
3194
3195
3196/**
3197 * Sets up VM-entry controls in the VMCS. These controls can affect things done
3198 * on VM-exit; e.g. "load debug controls", see Intel spec. 24.8.1 "VM-entry
3199 * controls".
3200 *
3201 * @returns VBox status code.
3202 * @param pVCpu The cross context virtual CPU structure.
3203 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3204 * out-of-sync. Make sure to update the required fields
3205 * before using them.
3206 *
3207 * @remarks Requires EFER.
3208 * @remarks No-long-jump zone!!!
3209 */
3210DECLINLINE(int) hmR0VmxLoadGuestEntryCtls(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3211{
3212 int rc = VINF_SUCCESS;
3213 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_ENTRY_CTLS))
3214 {
3215 PVM pVM = pVCpu->CTX_SUFF(pVM);
3216 uint32_t val = pVM->hm.s.vmx.Msrs.VmxEntry.n.disallowed0; /* Bits set here must be set in the VMCS. */
3217 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxEntry.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3218
3219 /* Load debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x capable CPUs only supports the 1-setting of this bit. */
3220 val |= VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG;
3221
3222 /* Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry. */
3223 if (CPUMIsGuestInLongModeEx(pMixedCtx))
3224 {
3225 val |= VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST;
3226 Log4(("Load[%RU32]: VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST\n", pVCpu->idCpu));
3227 }
3228 else
3229 Assert(!(val & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST));
3230
3231 /* If the CPU supports the newer VMCS controls for managing guest/host EFER, use it. */
3232 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
3233 && hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
3234 {
3235 val |= VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR;
3236 Log4(("Load[%RU32]: VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR\n", pVCpu->idCpu));
3237 }
3238
3239 /*
3240 * The following should -not- be set (since we're not in SMM mode):
3241 * - VMX_VMCS_CTRL_ENTRY_ENTRY_SMM
3242 * - VMX_VMCS_CTRL_ENTRY_DEACTIVATE_DUALMON
3243 */
3244
3245 /** @todo VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PERF_MSR,
3246 * VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PAT_MSR. */
3247
3248 if ((val & zap) != val)
3249 {
3250 LogRel(("hmR0VmxLoadGuestEntryCtls: Invalid VM-entry controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
3251 pVM->hm.s.vmx.Msrs.VmxEntry.n.disallowed0, val, zap));
3252 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
3253 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3254 }
3255
3256 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, val);
3257 AssertRCReturn(rc, rc);
3258
3259 pVCpu->hm.s.vmx.u32EntryCtls = val;
3260 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_ENTRY_CTLS);
3261 }
3262 return rc;
3263}
3264
3265
3266/**
3267 * Sets up the VM-exit controls in the VMCS.
3268 *
3269 * @returns VBox status code.
3270 * @param pVCpu The cross context virtual CPU structure.
3271 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3272 * out-of-sync. Make sure to update the required fields
3273 * before using them.
3274 *
3275 * @remarks Requires EFER.
3276 */
3277DECLINLINE(int) hmR0VmxLoadGuestExitCtls(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3278{
3279 NOREF(pMixedCtx);
3280
3281 int rc = VINF_SUCCESS;
3282 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_EXIT_CTLS))
3283 {
3284 PVM pVM = pVCpu->CTX_SUFF(pVM);
3285 uint32_t val = pVM->hm.s.vmx.Msrs.VmxExit.n.disallowed0; /* Bits set here must be set in the VMCS. */
3286 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3287
3288 /* Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only supported the 1-setting of this bit. */
3289 val |= VMX_VMCS_CTRL_EXIT_SAVE_DEBUG;
3290
3291 /*
3292 * Set the host long mode active (EFER.LMA) bit (which Intel calls "Host address-space size") if necessary.
3293 * On VM-exit, VT-x sets both the host EFER.LMA and EFER.LME bit to this value. See assertion in hmR0VmxSaveHostMsrs().
3294 */
3295#if HC_ARCH_BITS == 64
3296 val |= VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE;
3297 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE\n", pVCpu->idCpu));
3298#else
3299 if (CPUMIsGuestInLongModeEx(pMixedCtx))
3300 {
3301 /* The switcher returns to long mode, EFER is managed by the switcher. */
3302 val |= VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE;
3303 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE\n", pVCpu->idCpu));
3304 }
3305 else
3306 Assert(!(val & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE));
3307#endif
3308
3309 /* If the newer VMCS fields for managing EFER exists, use it. */
3310 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
3311 && hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
3312 {
3313 val |= VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR
3314 | VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR;
3315 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR, VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR\n", pVCpu->idCpu));
3316 }
3317
3318 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
3319 Assert(!(val & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT));
3320
3321 /** @todo VMX_VMCS_CTRL_EXIT_LOAD_PERF_MSR,
3322 * VMX_VMCS_CTRL_EXIT_SAVE_GUEST_PAT_MSR,
3323 * VMX_VMCS_CTRL_EXIT_LOAD_HOST_PAT_MSR. */
3324
3325 if ( pVM->hm.s.vmx.fUsePreemptTimer
3326 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_SAVE_VMX_PREEMPT_TIMER))
3327 val |= VMX_VMCS_CTRL_EXIT_SAVE_VMX_PREEMPT_TIMER;
3328
3329 if ((val & zap) != val)
3330 {
3331 LogRel(("hmR0VmxSetupProcCtls: Invalid VM-exit controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
3332 pVM->hm.s.vmx.Msrs.VmxExit.n.disallowed0, val, zap));
3333 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
3334 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3335 }
3336
3337 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, val);
3338 AssertRCReturn(rc, rc);
3339
3340 pVCpu->hm.s.vmx.u32ExitCtls = val;
3341 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_EXIT_CTLS);
3342 }
3343 return rc;
3344}
3345
3346
3347/**
3348 * Sets the TPR threshold in the VMCS.
3349 *
3350 * @returns VBox status code.
3351 * @param pVCpu The cross context virtual CPU structure.
3352 * @param u32TprThreshold The TPR threshold (task-priority class only).
3353 */
3354DECLINLINE(int) hmR0VmxApicSetTprThreshold(PVMCPU pVCpu, uint32_t u32TprThreshold)
3355{
3356 Assert(!(u32TprThreshold & 0xfffffff0)); /* Bits 31:4 MBZ. */
3357 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW);
3358 return VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
3359}
3360
3361
3362/**
3363 * Loads the guest APIC and related state.
3364 *
3365 * @returns VBox status code.
3366 * @param pVCpu The cross context virtual CPU structure.
3367 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3368 * out-of-sync. Make sure to update the required fields
3369 * before using them.
3370 */
3371DECLINLINE(int) hmR0VmxLoadGuestApicState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3372{
3373 NOREF(pMixedCtx);
3374
3375 int rc = VINF_SUCCESS;
3376 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE))
3377 {
3378 /* Setup TPR shadowing. Also setup TPR patching for 32-bit guests. */
3379 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
3380 {
3381 Assert(pVCpu->hm.s.vmx.HCPhysVirtApic);
3382
3383 bool fPendingIntr = false;
3384 uint8_t u8Tpr = 0;
3385 uint8_t u8PendingIntr = 0;
3386 rc = PDMApicGetTPR(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
3387 AssertRCReturn(rc, rc);
3388
3389 /*
3390 * If there are external interrupts pending but masked by the TPR value, instruct VT-x to cause a VM-exit when
3391 * the guest lowers its TPR below the highest-priority pending interrupt and we can deliver the interrupt.
3392 * If there are no external interrupts pending, set threshold to 0 to not cause a VM-exit. We will eventually deliver
3393 * the interrupt when we VM-exit for other reasons.
3394 */
3395 pVCpu->hm.s.vmx.pbVirtApic[0x80] = u8Tpr; /* Offset 0x80 is TPR in the APIC MMIO range. */
3396 uint32_t u32TprThreshold = 0;
3397 if (fPendingIntr)
3398 {
3399 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR (which is the Task-Priority Class). */
3400 const uint8_t u8PendingPriority = (u8PendingIntr >> 4) & 0xf;
3401 const uint8_t u8TprPriority = (u8Tpr >> 4) & 0xf;
3402 if (u8PendingPriority <= u8TprPriority)
3403 u32TprThreshold = u8PendingPriority;
3404 else
3405 u32TprThreshold = u8TprPriority; /* Required for Vista 64-bit guest, see @bugref{6398}. */
3406 }
3407
3408 rc = hmR0VmxApicSetTprThreshold(pVCpu, u32TprThreshold);
3409 AssertRCReturn(rc, rc);
3410 }
3411
3412 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
3413 }
3414 return rc;
3415}
3416
3417
3418/**
3419 * Gets the guest's interruptibility-state ("interrupt shadow" as AMD calls it).
3420 *
3421 * @returns Guest's interruptibility-state.
3422 * @param pVCpu The cross context virtual CPU structure.
3423 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3424 * out-of-sync. Make sure to update the required fields
3425 * before using them.
3426 *
3427 * @remarks No-long-jump zone!!!
3428 */
3429DECLINLINE(uint32_t) hmR0VmxGetGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3430{
3431 /*
3432 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
3433 */
3434 uint32_t uIntrState = 0;
3435 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
3436 {
3437 /* If inhibition is active, RIP & RFLAGS should've been accessed (i.e. read previously from the VMCS or from ring-3). */
3438 AssertMsg(HMVMXCPU_GST_IS_SET(pVCpu, HMVMX_UPDATED_GUEST_RIP | HMVMX_UPDATED_GUEST_RFLAGS),
3439 ("%#x\n", HMVMXCPU_GST_VALUE(pVCpu)));
3440 if (pMixedCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
3441 {
3442 if (pMixedCtx->eflags.Bits.u1IF)
3443 uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
3444 else
3445 uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS;
3446 }
3447 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
3448 {
3449 /*
3450 * We can clear the inhibit force flag as even if we go back to the recompiler without executing guest code in
3451 * VT-x, the flag's condition to be cleared is met and thus the cleared state is correct.
3452 */
3453 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
3454 }
3455 }
3456
3457 /*
3458 * NMIs to the guest are blocked after an NMI is injected until the guest executes an IRET. We only
3459 * bother with virtual-NMI blocking when we have support for virtual NMIs in the CPU, otherwise
3460 * setting this would block host-NMIs and IRET will not clear the blocking.
3461 *
3462 * See Intel spec. 26.6.1 "Interruptibility state". See @bugref{7445}.
3463 */
3464 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS)
3465 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
3466 {
3467 uIntrState |= VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI;
3468 }
3469
3470 return uIntrState;
3471}
3472
3473
3474/**
3475 * Loads the guest's interruptibility-state into the guest-state area in the
3476 * VMCS.
3477 *
3478 * @returns VBox status code.
3479 * @param pVCpu The cross context virtual CPU structure.
3480 * @param uIntrState The interruptibility-state to set.
3481 */
3482static int hmR0VmxLoadGuestIntrState(PVMCPU pVCpu, uint32_t uIntrState)
3483{
3484 NOREF(pVCpu);
3485 AssertMsg(!(uIntrState & 0xfffffff0), ("%#x\n", uIntrState)); /* Bits 31:4 MBZ. */
3486 Assert((uIntrState & 0x3) != 0x3); /* Block-by-STI and MOV SS cannot be simultaneously set. */
3487 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, uIntrState);
3488 AssertRC(rc);
3489 return rc;
3490}
3491
3492
3493/**
3494 * Loads the exception intercepts required for guest execution in the VMCS.
3495 *
3496 * @returns VBox status code.
3497 * @param pVCpu The cross context virtual CPU structure.
3498 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3499 * out-of-sync. Make sure to update the required fields
3500 * before using them.
3501 */
3502static int hmR0VmxLoadGuestXcptIntercepts(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3503{
3504 NOREF(pMixedCtx);
3505 int rc = VINF_SUCCESS;
3506 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
3507 {
3508 /* The remaining exception intercepts are handled elsewhere, e.g. in hmR0VmxLoadSharedCR0(). */
3509 if (pVCpu->hm.s.fGIMTrapXcptUD)
3510 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_UD);
3511#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
3512 else
3513 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_UD);
3514#endif
3515
3516 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_AC));
3517 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
3518
3519 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
3520 AssertRCReturn(rc, rc);
3521
3522 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
3523 Log4(("Load[%RU32]: VMX_VMCS32_CTRL_EXCEPTION_BITMAP=%#RX64 fContextUseFlags=%#RX32\n", pVCpu->idCpu,
3524 pVCpu->hm.s.vmx.u32XcptBitmap, HMCPU_CF_VALUE(pVCpu)));
3525 }
3526 return rc;
3527}
3528
3529
3530/**
3531 * Loads the guest's RIP into the guest-state area in the VMCS.
3532 *
3533 * @returns VBox status code.
3534 * @param pVCpu The cross context virtual CPU structure.
3535 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3536 * out-of-sync. Make sure to update the required fields
3537 * before using them.
3538 *
3539 * @remarks No-long-jump zone!!!
3540 */
3541static int hmR0VmxLoadGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3542{
3543 int rc = VINF_SUCCESS;
3544 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RIP))
3545 {
3546 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_RIP, pMixedCtx->rip);
3547 AssertRCReturn(rc, rc);
3548
3549 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RIP);
3550 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RIP=%#RX64 fContextUseFlags=%#RX32\n", pVCpu->idCpu, pMixedCtx->rip,
3551 HMCPU_CF_VALUE(pVCpu)));
3552 }
3553 return rc;
3554}
3555
3556
3557/**
3558 * Loads the guest's RSP into the guest-state area in the VMCS.
3559 *
3560 * @returns VBox status code.
3561 * @param pVCpu The cross context virtual CPU structure.
3562 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3563 * out-of-sync. Make sure to update the required fields
3564 * before using them.
3565 *
3566 * @remarks No-long-jump zone!!!
3567 */
3568static int hmR0VmxLoadGuestRsp(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3569{
3570 int rc = VINF_SUCCESS;
3571 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RSP))
3572 {
3573 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_RSP, pMixedCtx->rsp);
3574 AssertRCReturn(rc, rc);
3575
3576 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RSP);
3577 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RSP=%#RX64\n", pVCpu->idCpu, pMixedCtx->rsp));
3578 }
3579 return rc;
3580}
3581
3582
3583/**
3584 * Loads the guest's RFLAGS into the guest-state area in the VMCS.
3585 *
3586 * @returns VBox status code.
3587 * @param pVCpu The cross context virtual CPU structure.
3588 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3589 * out-of-sync. Make sure to update the required fields
3590 * before using them.
3591 *
3592 * @remarks No-long-jump zone!!!
3593 */
3594static int hmR0VmxLoadGuestRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3595{
3596 int rc = VINF_SUCCESS;
3597 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RFLAGS))
3598 {
3599 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
3600 Let us assert it as such and use 32-bit VMWRITE. */
3601 Assert(!(pMixedCtx->rflags.u64 >> 32));
3602 X86EFLAGS Eflags = pMixedCtx->eflags;
3603 /** @todo r=bird: There shall be no need to OR in X86_EFL_1 here, nor
3604 * shall there be any reason for clearing bits 63:22, 15, 5 and 3.
3605 * These will never be cleared/set, unless some other part of the VMM
3606 * code is buggy - in which case we're better of finding and fixing
3607 * those bugs than hiding them. */
3608 Assert(Eflags.u32 & X86_EFL_RA1_MASK);
3609 Assert(!(Eflags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
3610 Eflags.u32 &= VMX_EFLAGS_RESERVED_0; /* Bits 22-31, 15, 5 & 3 MBZ. */
3611 Eflags.u32 |= VMX_EFLAGS_RESERVED_1; /* Bit 1 MB1. */
3612
3613 /*
3614 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so we can restore them on VM-exit.
3615 * Modify the real-mode guest's eflags so that VT-x can run the real-mode guest code under Virtual 8086 mode.
3616 */
3617 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3618 {
3619 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
3620 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
3621 pVCpu->hm.s.vmx.RealMode.Eflags.u32 = Eflags.u32; /* Save the original eflags of the real-mode guest. */
3622 Eflags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
3623 Eflags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
3624 }
3625
3626 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_RFLAGS, Eflags.u32);
3627 AssertRCReturn(rc, rc);
3628
3629 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RFLAGS);
3630 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RFLAGS=%#RX32\n", pVCpu->idCpu, Eflags.u32));
3631 }
3632 return rc;
3633}
3634
3635
3636/**
3637 * Loads the guest RIP, RSP and RFLAGS into the guest-state area in the VMCS.
3638 *
3639 * @returns VBox status code.
3640 * @param pVCpu The cross context virtual CPU structure.
3641 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3642 * out-of-sync. Make sure to update the required fields
3643 * before using them.
3644 *
3645 * @remarks No-long-jump zone!!!
3646 */
3647DECLINLINE(int) hmR0VmxLoadGuestRipRspRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3648{
3649 int rc = hmR0VmxLoadGuestRip(pVCpu, pMixedCtx);
3650 rc |= hmR0VmxLoadGuestRsp(pVCpu, pMixedCtx);
3651 rc |= hmR0VmxLoadGuestRflags(pVCpu, pMixedCtx);
3652 AssertRCReturn(rc, rc);
3653 return rc;
3654}
3655
3656
3657/**
3658 * Loads the guest CR0 control register into the guest-state area in the VMCS.
3659 * CR0 is partially shared with the host and we have to consider the FPU bits.
3660 *
3661 * @returns VBox status code.
3662 * @param pVCpu The cross context virtual CPU structure.
3663 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3664 * out-of-sync. Make sure to update the required fields
3665 * before using them.
3666 *
3667 * @remarks No-long-jump zone!!!
3668 */
3669static int hmR0VmxLoadSharedCR0(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3670{
3671 /*
3672 * Guest CR0.
3673 * Guest FPU.
3674 */
3675 int rc = VINF_SUCCESS;
3676 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
3677 {
3678 Assert(!(pMixedCtx->cr0 >> 32));
3679 uint32_t u32GuestCR0 = pMixedCtx->cr0;
3680 PVM pVM = pVCpu->CTX_SUFF(pVM);
3681
3682 /* The guest's view (read access) of its CR0 is unblemished. */
3683 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_READ_SHADOW, u32GuestCR0);
3684 AssertRCReturn(rc, rc);
3685 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR0_READ_SHADOW=%#RX32\n", pVCpu->idCpu, u32GuestCR0));
3686
3687 /* Setup VT-x's view of the guest CR0. */
3688 /* Minimize VM-exits due to CR3 changes when we have NestedPaging. */
3689 if (pVM->hm.s.fNestedPaging)
3690 {
3691 if (CPUMIsGuestPagingEnabledEx(pMixedCtx))
3692 {
3693 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
3694 pVCpu->hm.s.vmx.u32ProcCtls &= ~( VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
3695 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT);
3696 }
3697 else
3698 {
3699 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
3700 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
3701 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
3702 }
3703
3704 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
3705 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3706 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
3707
3708 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
3709 AssertRCReturn(rc, rc);
3710 }
3711 else
3712 u32GuestCR0 |= X86_CR0_WP; /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
3713
3714 /*
3715 * Guest FPU bits.
3716 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be set on the first
3717 * CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
3718 */
3719 u32GuestCR0 |= X86_CR0_NE;
3720 bool fInterceptNM = false;
3721 if (CPUMIsGuestFPUStateActive(pVCpu))
3722 {
3723 fInterceptNM = false; /* Guest FPU active, no need to VM-exit on #NM. */
3724 /* The guest should still get #NM exceptions when it expects it to, so we should not clear TS & MP bits here.
3725 We're only concerned about -us- not intercepting #NMs when the guest-FPU is active. Not the guest itself! */
3726 }
3727 else
3728 {
3729 fInterceptNM = true; /* Guest FPU inactive, VM-exit on #NM for lazy FPU loading. */
3730 u32GuestCR0 |= X86_CR0_TS /* Guest can task switch quickly and do lazy FPU syncing. */
3731 | X86_CR0_MP; /* FWAIT/WAIT should not ignore CR0.TS and should generate #NM. */
3732 }
3733
3734 /* Catch floating point exceptions if we need to report them to the guest in a different way. */
3735 bool fInterceptMF = false;
3736 if (!(pMixedCtx->cr0 & X86_CR0_NE))
3737 fInterceptMF = true;
3738
3739 /* Finally, intercept all exceptions as we cannot directly inject them in real-mode, see hmR0VmxInjectEventVmcs(). */
3740 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3741 {
3742 Assert(PDMVmmDevHeapIsEnabled(pVM));
3743 Assert(pVM->hm.s.vmx.pRealModeTSS);
3744 pVCpu->hm.s.vmx.u32XcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
3745 fInterceptNM = true;
3746 fInterceptMF = true;
3747 }
3748 else
3749 {
3750 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
3751 pVCpu->hm.s.vmx.u32XcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
3752 }
3753 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
3754
3755 if (fInterceptNM)
3756 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_NM);
3757 else
3758 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_NM);
3759
3760 if (fInterceptMF)
3761 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_MF);
3762 else
3763 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_MF);
3764
3765 /* Additional intercepts for debugging, define these yourself explicitly. */
3766#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
3767 pVCpu->hm.s.vmx.u32XcptBitmap |= 0
3768 | RT_BIT(X86_XCPT_BP)
3769 | RT_BIT(X86_XCPT_DE)
3770 | RT_BIT(X86_XCPT_NM)
3771 | RT_BIT(X86_XCPT_TS)
3772 | RT_BIT(X86_XCPT_UD)
3773 | RT_BIT(X86_XCPT_NP)
3774 | RT_BIT(X86_XCPT_SS)
3775 | RT_BIT(X86_XCPT_GP)
3776 | RT_BIT(X86_XCPT_PF)
3777 | RT_BIT(X86_XCPT_MF)
3778 ;
3779#elif defined(HMVMX_ALWAYS_TRAP_PF)
3780 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_PF);
3781#endif
3782
3783 Assert(pVM->hm.s.fNestedPaging || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_PF)));
3784
3785 /* Set/clear the CR0 specific bits along with their exceptions (PE, PG, CD, NW). */
3786 uint32_t uSetCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
3787 uint32_t uZapCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
3788 if (pVM->hm.s.vmx.fUnrestrictedGuest) /* Exceptions for unrestricted-guests for fixed CR0 bits (PE, PG). */
3789 uSetCR0 &= ~(X86_CR0_PE | X86_CR0_PG);
3790 else
3791 Assert((uSetCR0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
3792
3793 u32GuestCR0 |= uSetCR0;
3794 u32GuestCR0 &= uZapCR0;
3795 u32GuestCR0 &= ~(X86_CR0_CD | X86_CR0_NW); /* Always enable caching. */
3796
3797 /* Write VT-x's view of the guest CR0 into the VMCS. */
3798 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_CR0, u32GuestCR0);
3799 AssertRCReturn(rc, rc);
3800 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR0=%#RX32 (uSetCR0=%#RX32 uZapCR0=%#RX32)\n", pVCpu->idCpu, u32GuestCR0, uSetCR0,
3801 uZapCR0));
3802
3803 /*
3804 * CR0 is shared between host and guest along with a CR0 read shadow. Therefore, certain bits must not be changed
3805 * by the guest because VT-x ignores saving/restoring them (namely CD, ET, NW) and for certain other bits
3806 * we want to be notified immediately of guest CR0 changes (e.g. PG to update our shadow page tables).
3807 */
3808 uint32_t u32CR0Mask = 0;
3809 u32CR0Mask = X86_CR0_PE
3810 | X86_CR0_NE
3811 | X86_CR0_WP
3812 | X86_CR0_PG
3813 | X86_CR0_ET /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.ET */
3814 | X86_CR0_CD /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.CD */
3815 | X86_CR0_NW; /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.NW */
3816
3817 /** @todo Avoid intercepting CR0.PE with unrestricted guests. Fix PGM
3818 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
3819 * and @bugref{6944}. */
3820#if 0
3821 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3822 u32CR0Mask &= ~X86_CR0_PE;
3823#endif
3824 if (pVM->hm.s.fNestedPaging)
3825 u32CR0Mask &= ~X86_CR0_WP;
3826
3827 /* If the guest FPU state is active, don't need to VM-exit on writes to FPU related bits in CR0. */
3828 if (fInterceptNM)
3829 {
3830 u32CR0Mask |= X86_CR0_TS
3831 | X86_CR0_MP;
3832 }
3833
3834 /* Write the CR0 mask into the VMCS and update the VCPU's copy of the current CR0 mask. */
3835 pVCpu->hm.s.vmx.u32CR0Mask = u32CR0Mask;
3836 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_MASK, u32CR0Mask);
3837 AssertRCReturn(rc, rc);
3838 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR0_MASK=%#RX32\n", pVCpu->idCpu, u32CR0Mask));
3839
3840 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR0);
3841 }
3842 return rc;
3843}
3844
3845
3846/**
3847 * Loads the guest control registers (CR3, CR4) into the guest-state area
3848 * in the VMCS.
3849 *
3850 * @returns VBox strict status code.
3851 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
3852 * without unrestricted guest access and the VMMDev is not presently
3853 * mapped (e.g. EFI32).
3854 *
3855 * @param pVCpu The cross context virtual CPU structure.
3856 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3857 * out-of-sync. Make sure to update the required fields
3858 * before using them.
3859 *
3860 * @remarks No-long-jump zone!!!
3861 */
3862static VBOXSTRICTRC hmR0VmxLoadGuestCR3AndCR4(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3863{
3864 int rc = VINF_SUCCESS;
3865 PVM pVM = pVCpu->CTX_SUFF(pVM);
3866
3867 /*
3868 * Guest CR2.
3869 * It's always loaded in the assembler code. Nothing to do here.
3870 */
3871
3872 /*
3873 * Guest CR3.
3874 */
3875 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR3))
3876 {
3877 RTGCPHYS GCPhysGuestCR3 = NIL_RTGCPHYS;
3878 if (pVM->hm.s.fNestedPaging)
3879 {
3880 pVCpu->hm.s.vmx.HCPhysEPTP = PGMGetHyperCR3(pVCpu);
3881
3882 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
3883 Assert(pVCpu->hm.s.vmx.HCPhysEPTP);
3884 Assert(!(pVCpu->hm.s.vmx.HCPhysEPTP & UINT64_C(0xfff0000000000000)));
3885 Assert(!(pVCpu->hm.s.vmx.HCPhysEPTP & 0xfff));
3886
3887 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
3888 pVCpu->hm.s.vmx.HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
3889 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
3890
3891 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
3892 AssertMsg( ((pVCpu->hm.s.vmx.HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
3893 && ((pVCpu->hm.s.vmx.HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
3894 ("EPTP %#RX64\n", pVCpu->hm.s.vmx.HCPhysEPTP));
3895 AssertMsg( !((pVCpu->hm.s.vmx.HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
3896 || (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
3897 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVCpu->hm.s.vmx.HCPhysEPTP));
3898
3899 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVCpu->hm.s.vmx.HCPhysEPTP);
3900 AssertRCReturn(rc, rc);
3901 Log4(("Load[%RU32]: VMX_VMCS64_CTRL_EPTP_FULL=%#RX64\n", pVCpu->idCpu, pVCpu->hm.s.vmx.HCPhysEPTP));
3902
3903 if ( pVM->hm.s.vmx.fUnrestrictedGuest
3904 || CPUMIsGuestPagingEnabledEx(pMixedCtx))
3905 {
3906 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
3907 if (CPUMIsGuestInPAEModeEx(pMixedCtx))
3908 {
3909 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
3910 AssertRCReturn(rc, rc);
3911 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u);
3912 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u);
3913 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u);
3914 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u);
3915 AssertRCReturn(rc, rc);
3916 }
3917
3918 /* The guest's view of its CR3 is unblemished with Nested Paging when the guest is using paging or we
3919 have Unrestricted Execution to handle the guest when it's not using paging. */
3920 GCPhysGuestCR3 = pMixedCtx->cr3;
3921 }
3922 else
3923 {
3924 /*
3925 * The guest is not using paging, but the CPU (VT-x) has to. While the guest thinks it accesses physical memory
3926 * directly, we use our identity-mapped page table to map guest-linear to guest-physical addresses.
3927 * EPT takes care of translating it to host-physical addresses.
3928 */
3929 RTGCPHYS GCPhys;
3930 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
3931
3932 /* We obtain it here every time as the guest could have relocated this PCI region. */
3933 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
3934 if (RT_SUCCESS(rc))
3935 { /* likely */ }
3936 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
3937 {
3938 Log4(("Load[%RU32]: VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n", pVCpu->idCpu));
3939 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
3940 }
3941 else
3942 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
3943
3944 GCPhysGuestCR3 = GCPhys;
3945 }
3946
3947 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR3=%#RGp (GstN)\n", pVCpu->idCpu, GCPhysGuestCR3));
3948 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_CR3, GCPhysGuestCR3);
3949 }
3950 else
3951 {
3952 /* Non-nested paging case, just use the hypervisor's CR3. */
3953 RTHCPHYS HCPhysGuestCR3 = PGMGetHyperCR3(pVCpu);
3954
3955 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR3=%#RHv (HstN)\n", pVCpu->idCpu, HCPhysGuestCR3));
3956 rc = VMXWriteVmcsHstN(VMX_VMCS_GUEST_CR3, HCPhysGuestCR3);
3957 }
3958 AssertRCReturn(rc, rc);
3959
3960 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR3);
3961 }
3962
3963 /*
3964 * Guest CR4.
3965 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
3966 */
3967 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR4))
3968 {
3969 Assert(!(pMixedCtx->cr4 >> 32));
3970 uint32_t u32GuestCR4 = pMixedCtx->cr4;
3971
3972 /* The guest's view of its CR4 is unblemished. */
3973 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_READ_SHADOW, u32GuestCR4);
3974 AssertRCReturn(rc, rc);
3975 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR4_READ_SHADOW=%#RX32\n", pVCpu->idCpu, u32GuestCR4));
3976
3977 /* Setup VT-x's view of the guest CR4. */
3978 /*
3979 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software interrupts to the 8086 program
3980 * interrupt handler. Clear the VME bit (the interrupt redirection bitmap is already all 0, see hmR3InitFinalizeR0())
3981 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
3982 */
3983 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3984 {
3985 Assert(pVM->hm.s.vmx.pRealModeTSS);
3986 Assert(PDMVmmDevHeapIsEnabled(pVM));
3987 u32GuestCR4 &= ~X86_CR4_VME;
3988 }
3989
3990 if (pVM->hm.s.fNestedPaging)
3991 {
3992 if ( !CPUMIsGuestPagingEnabledEx(pMixedCtx)
3993 && !pVM->hm.s.vmx.fUnrestrictedGuest)
3994 {
3995 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
3996 u32GuestCR4 |= X86_CR4_PSE;
3997 /* Our identity mapping is a 32-bit page directory. */
3998 u32GuestCR4 &= ~X86_CR4_PAE;
3999 }
4000 /* else use guest CR4.*/
4001 }
4002 else
4003 {
4004 /*
4005 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
4006 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
4007 */
4008 switch (pVCpu->hm.s.enmShadowMode)
4009 {
4010 case PGMMODE_REAL: /* Real-mode. */
4011 case PGMMODE_PROTECTED: /* Protected mode without paging. */
4012 case PGMMODE_32_BIT: /* 32-bit paging. */
4013 {
4014 u32GuestCR4 &= ~X86_CR4_PAE;
4015 break;
4016 }
4017
4018 case PGMMODE_PAE: /* PAE paging. */
4019 case PGMMODE_PAE_NX: /* PAE paging with NX. */
4020 {
4021 u32GuestCR4 |= X86_CR4_PAE;
4022 break;
4023 }
4024
4025 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
4026 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
4027#ifdef VBOX_ENABLE_64_BITS_GUESTS
4028 break;
4029#endif
4030 default:
4031 AssertFailed();
4032 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
4033 }
4034 }
4035
4036 /* We need to set and clear the CR4 specific bits here (mainly the X86_CR4_VMXE bit). */
4037 uint64_t uSetCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
4038 uint64_t uZapCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
4039 u32GuestCR4 |= uSetCR4;
4040 u32GuestCR4 &= uZapCR4;
4041
4042 /* Write VT-x's view of the guest CR4 into the VMCS. */
4043 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR4=%#RX32 (Set=%#RX32 Zap=%#RX32)\n", pVCpu->idCpu, u32GuestCR4, uSetCR4, uZapCR4));
4044 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_CR4, u32GuestCR4);
4045 AssertRCReturn(rc, rc);
4046
4047 /* Setup CR4 mask. CR4 flags owned by the host, if the guest attempts to change them, that would cause a VM-exit. */
4048 uint32_t u32CR4Mask = X86_CR4_VME
4049 | X86_CR4_PAE
4050 | X86_CR4_PGE
4051 | X86_CR4_PSE
4052 | X86_CR4_VMXE;
4053 if (pVM->cpum.ro.HostFeatures.fXSaveRstor)
4054 u32CR4Mask |= X86_CR4_OSXSAVE;
4055 pVCpu->hm.s.vmx.u32CR4Mask = u32CR4Mask;
4056 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_MASK, u32CR4Mask);
4057 AssertRCReturn(rc, rc);
4058
4059 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
4060 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pMixedCtx->cr4 & X86_CR4_OSXSAVE) && pMixedCtx->aXcr[0] != ASMGetXcr0();
4061
4062 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR4);
4063 }
4064 return rc;
4065}
4066
4067
4068/**
4069 * Loads the guest debug registers into the guest-state area in the VMCS.
4070 *
4071 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
4072 *
4073 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
4074 *
4075 * @returns VBox status code.
4076 * @param pVCpu The cross context virtual CPU structure.
4077 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4078 * out-of-sync. Make sure to update the required fields
4079 * before using them.
4080 *
4081 * @remarks No-long-jump zone!!!
4082 */
4083static int hmR0VmxLoadSharedDebugState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4084{
4085 if (!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_DEBUG))
4086 return VINF_SUCCESS;
4087
4088#ifdef VBOX_STRICT
4089 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
4090 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
4091 {
4092 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
4093 Assert((pMixedCtx->dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0); /* Bits 63:32, 15, 14, 12, 11 are reserved. */
4094 Assert((pMixedCtx->dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK); /* Bit 10 is reserved (RA1). */
4095 }
4096#endif
4097
4098 int rc;
4099 PVM pVM = pVCpu->CTX_SUFF(pVM);
4100 bool fSteppingDB = false;
4101 bool fInterceptMovDRx = false;
4102 if (pVCpu->hm.s.fSingleInstruction)
4103 {
4104 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
4105 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG)
4106 {
4107 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG;
4108 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
4109 AssertRCReturn(rc, rc);
4110 Assert(fSteppingDB == false);
4111 }
4112 else
4113 {
4114 pMixedCtx->eflags.u32 |= X86_EFL_TF;
4115 pVCpu->hm.s.fClearTrapFlag = true;
4116 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
4117 fSteppingDB = true;
4118 }
4119 }
4120
4121 if ( fSteppingDB
4122 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
4123 {
4124 /*
4125 * Use the combined guest and host DRx values found in the hypervisor
4126 * register set because the debugger has breakpoints active or someone
4127 * is single stepping on the host side without a monitor trap flag.
4128 *
4129 * Note! DBGF expects a clean DR6 state before executing guest code.
4130 */
4131#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4132 if ( CPUMIsGuestInLongModeEx(pMixedCtx)
4133 && !CPUMIsHyperDebugStateActivePending(pVCpu))
4134 {
4135 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
4136 Assert(CPUMIsHyperDebugStateActivePending(pVCpu));
4137 Assert(!CPUMIsGuestDebugStateActivePending(pVCpu));
4138 }
4139 else
4140#endif
4141 if (!CPUMIsHyperDebugStateActive(pVCpu))
4142 {
4143 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
4144 Assert(CPUMIsHyperDebugStateActive(pVCpu));
4145 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
4146 }
4147
4148 /* Update DR7. (The other DRx values are handled by CPUM one way or the other.) */
4149 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, (uint32_t)CPUMGetHyperDR7(pVCpu));
4150 AssertRCReturn(rc, rc);
4151
4152 pVCpu->hm.s.fUsingHyperDR7 = true;
4153 fInterceptMovDRx = true;
4154 }
4155 else
4156 {
4157 /*
4158 * If the guest has enabled debug registers, we need to load them prior to
4159 * executing guest code so they'll trigger at the right time.
4160 */
4161 if (pMixedCtx->dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD)) /** @todo Why GD? */
4162 {
4163#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4164 if ( CPUMIsGuestInLongModeEx(pMixedCtx)
4165 && !CPUMIsGuestDebugStateActivePending(pVCpu))
4166 {
4167 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
4168 Assert(CPUMIsGuestDebugStateActivePending(pVCpu));
4169 Assert(!CPUMIsHyperDebugStateActivePending(pVCpu));
4170 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
4171 }
4172 else
4173#endif
4174 if (!CPUMIsGuestDebugStateActive(pVCpu))
4175 {
4176 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
4177 Assert(CPUMIsGuestDebugStateActive(pVCpu));
4178 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
4179 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
4180 }
4181 Assert(!fInterceptMovDRx);
4182 }
4183 /*
4184 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
4185 * must intercept #DB in order to maintain a correct DR6 guest value, and
4186 * because we need to intercept it to prevent nested #DBs from hanging the
4187 * CPU, we end up always having to intercept it. See hmR0VmxInitXcptBitmap.
4188 */
4189#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4190 else if ( !CPUMIsGuestDebugStateActivePending(pVCpu)
4191 && !CPUMIsGuestDebugStateActive(pVCpu))
4192#else
4193 else if (!CPUMIsGuestDebugStateActive(pVCpu))
4194#endif
4195 {
4196 fInterceptMovDRx = true;
4197 }
4198
4199 /* Update guest DR7. */
4200 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, pMixedCtx->dr[7]);
4201 AssertRCReturn(rc, rc);
4202
4203 pVCpu->hm.s.fUsingHyperDR7 = false;
4204 }
4205
4206 /*
4207 * Update the processor-based VM-execution controls regarding intercepting MOV DRx instructions.
4208 */
4209 if (fInterceptMovDRx)
4210 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
4211 else
4212 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
4213 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
4214 AssertRCReturn(rc, rc);
4215
4216 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_DEBUG);
4217 return VINF_SUCCESS;
4218}
4219
4220
4221#ifdef VBOX_STRICT
4222/**
4223 * Strict function to validate segment registers.
4224 *
4225 * @remarks ASSUMES CR0 is up to date.
4226 */
4227static void hmR0VmxValidateSegmentRegs(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
4228{
4229 /* Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers". */
4230 /* NOTE: The reason we check for attribute value 0 and not just the unusable bit here is because hmR0VmxWriteSegmentReg()
4231 * only updates the VMCS' copy of the value with the unusable bit and doesn't change the guest-context value. */
4232 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
4233 && ( !CPUMIsGuestInRealModeEx(pCtx)
4234 && !CPUMIsGuestInV86ModeEx(pCtx)))
4235 {
4236 /* Protected mode checks */
4237 /* CS */
4238 Assert(pCtx->cs.Attr.n.u1Present);
4239 Assert(!(pCtx->cs.Attr.u & 0xf00));
4240 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
4241 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
4242 || !(pCtx->cs.Attr.n.u1Granularity));
4243 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
4244 || (pCtx->cs.Attr.n.u1Granularity));
4245 /* CS cannot be loaded with NULL in protected mode. */
4246 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
4247 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
4248 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
4249 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
4250 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
4251 else
4252 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
4253 /* SS */
4254 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
4255 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
4256 if ( !(pCtx->cr0 & X86_CR0_PE)
4257 || pCtx->cs.Attr.n.u4Type == 3)
4258 {
4259 Assert(!pCtx->ss.Attr.n.u2Dpl);
4260 }
4261 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
4262 {
4263 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
4264 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
4265 Assert(pCtx->ss.Attr.n.u1Present);
4266 Assert(!(pCtx->ss.Attr.u & 0xf00));
4267 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
4268 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
4269 || !(pCtx->ss.Attr.n.u1Granularity));
4270 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
4271 || (pCtx->ss.Attr.n.u1Granularity));
4272 }
4273 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxWriteSegmentReg(). */
4274 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
4275 {
4276 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4277 Assert(pCtx->ds.Attr.n.u1Present);
4278 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
4279 Assert(!(pCtx->ds.Attr.u & 0xf00));
4280 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
4281 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
4282 || !(pCtx->ds.Attr.n.u1Granularity));
4283 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
4284 || (pCtx->ds.Attr.n.u1Granularity));
4285 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4286 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
4287 }
4288 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
4289 {
4290 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4291 Assert(pCtx->es.Attr.n.u1Present);
4292 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
4293 Assert(!(pCtx->es.Attr.u & 0xf00));
4294 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
4295 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
4296 || !(pCtx->es.Attr.n.u1Granularity));
4297 Assert( !(pCtx->es.u32Limit & 0xfff00000)
4298 || (pCtx->es.Attr.n.u1Granularity));
4299 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4300 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
4301 }
4302 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
4303 {
4304 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4305 Assert(pCtx->fs.Attr.n.u1Present);
4306 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
4307 Assert(!(pCtx->fs.Attr.u & 0xf00));
4308 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
4309 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
4310 || !(pCtx->fs.Attr.n.u1Granularity));
4311 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
4312 || (pCtx->fs.Attr.n.u1Granularity));
4313 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4314 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
4315 }
4316 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
4317 {
4318 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4319 Assert(pCtx->gs.Attr.n.u1Present);
4320 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
4321 Assert(!(pCtx->gs.Attr.u & 0xf00));
4322 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
4323 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
4324 || !(pCtx->gs.Attr.n.u1Granularity));
4325 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
4326 || (pCtx->gs.Attr.n.u1Granularity));
4327 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4328 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
4329 }
4330 /* 64-bit capable CPUs. */
4331# if HC_ARCH_BITS == 64
4332 Assert(!(pCtx->cs.u64Base >> 32));
4333 Assert(!pCtx->ss.Attr.u || !(pCtx->ss.u64Base >> 32));
4334 Assert(!pCtx->ds.Attr.u || !(pCtx->ds.u64Base >> 32));
4335 Assert(!pCtx->es.Attr.u || !(pCtx->es.u64Base >> 32));
4336# endif
4337 }
4338 else if ( CPUMIsGuestInV86ModeEx(pCtx)
4339 || ( CPUMIsGuestInRealModeEx(pCtx)
4340 && !pVM->hm.s.vmx.fUnrestrictedGuest))
4341 {
4342 /* Real and v86 mode checks. */
4343 /* hmR0VmxWriteSegmentReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
4344 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
4345 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4346 {
4347 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3; u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
4348 }
4349 else
4350 {
4351 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
4352 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
4353 }
4354
4355 /* CS */
4356 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
4357 Assert(pCtx->cs.u32Limit == 0xffff);
4358 Assert(u32CSAttr == 0xf3);
4359 /* SS */
4360 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
4361 Assert(pCtx->ss.u32Limit == 0xffff);
4362 Assert(u32SSAttr == 0xf3);
4363 /* DS */
4364 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
4365 Assert(pCtx->ds.u32Limit == 0xffff);
4366 Assert(u32DSAttr == 0xf3);
4367 /* ES */
4368 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
4369 Assert(pCtx->es.u32Limit == 0xffff);
4370 Assert(u32ESAttr == 0xf3);
4371 /* FS */
4372 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
4373 Assert(pCtx->fs.u32Limit == 0xffff);
4374 Assert(u32FSAttr == 0xf3);
4375 /* GS */
4376 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
4377 Assert(pCtx->gs.u32Limit == 0xffff);
4378 Assert(u32GSAttr == 0xf3);
4379 /* 64-bit capable CPUs. */
4380# if HC_ARCH_BITS == 64
4381 Assert(!(pCtx->cs.u64Base >> 32));
4382 Assert(!u32SSAttr || !(pCtx->ss.u64Base >> 32));
4383 Assert(!u32DSAttr || !(pCtx->ds.u64Base >> 32));
4384 Assert(!u32ESAttr || !(pCtx->es.u64Base >> 32));
4385# endif
4386 }
4387}
4388#endif /* VBOX_STRICT */
4389
4390
4391/**
4392 * Writes a guest segment register into the guest-state area in the VMCS.
4393 *
4394 * @returns VBox status code.
4395 * @param pVCpu The cross context virtual CPU structure.
4396 * @param idxSel Index of the selector in the VMCS.
4397 * @param idxLimit Index of the segment limit in the VMCS.
4398 * @param idxBase Index of the segment base in the VMCS.
4399 * @param idxAccess Index of the access rights of the segment in the VMCS.
4400 * @param pSelReg Pointer to the segment selector.
4401 *
4402 * @remarks No-long-jump zone!!!
4403 */
4404static int hmR0VmxWriteSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase,
4405 uint32_t idxAccess, PCPUMSELREG pSelReg)
4406{
4407 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); /* 16-bit guest selector field. */
4408 rc |= VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); /* 32-bit guest segment limit field. */
4409 rc |= VMXWriteVmcsGstN(idxBase, pSelReg->u64Base); /* Natural width guest segment base field.*/
4410 AssertRCReturn(rc, rc);
4411
4412 uint32_t u32Access = pSelReg->Attr.u;
4413 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4414 {
4415 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
4416 u32Access = 0xf3;
4417 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
4418 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
4419 }
4420 else
4421 {
4422 /*
4423 * The way to differentiate between whether this is really a null selector or was just a selector loaded with 0 in
4424 * real-mode is using the segment attributes. A selector loaded in real-mode with the value 0 is valid and usable in
4425 * protected-mode and we should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures NULL selectors
4426 * loaded in protected-mode have their attribute as 0.
4427 */
4428 if (!u32Access)
4429 u32Access = X86DESCATTR_UNUSABLE;
4430 }
4431
4432 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
4433 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
4434 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
4435
4436 rc = VMXWriteVmcs32(idxAccess, u32Access); /* 32-bit guest segment access-rights field. */
4437 AssertRCReturn(rc, rc);
4438 return rc;
4439}
4440
4441
4442/**
4443 * Loads the guest segment registers, GDTR, IDTR, LDTR, (TR, FS and GS bases)
4444 * into the guest-state area in the VMCS.
4445 *
4446 * @returns VBox status code.
4447 * @param pVCpu The cross context virtual CPU structure.
4448 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4449 * out-of-sync. Make sure to update the required fields
4450 * before using them.
4451 *
4452 * @remarks ASSUMES pMixedCtx->cr0 is up to date (strict builds validation).
4453 * @remarks No-long-jump zone!!!
4454 */
4455static int hmR0VmxLoadGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4456{
4457 int rc = VERR_INTERNAL_ERROR_5;
4458 PVM pVM = pVCpu->CTX_SUFF(pVM);
4459
4460 /*
4461 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
4462 */
4463 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS))
4464 {
4465 /* Save the segment attributes for real-on-v86 mode hack, so we can restore them on VM-exit. */
4466 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4467 {
4468 pVCpu->hm.s.vmx.RealMode.AttrCS.u = pMixedCtx->cs.Attr.u;
4469 pVCpu->hm.s.vmx.RealMode.AttrSS.u = pMixedCtx->ss.Attr.u;
4470 pVCpu->hm.s.vmx.RealMode.AttrDS.u = pMixedCtx->ds.Attr.u;
4471 pVCpu->hm.s.vmx.RealMode.AttrES.u = pMixedCtx->es.Attr.u;
4472 pVCpu->hm.s.vmx.RealMode.AttrFS.u = pMixedCtx->fs.Attr.u;
4473 pVCpu->hm.s.vmx.RealMode.AttrGS.u = pMixedCtx->gs.Attr.u;
4474 }
4475
4476#ifdef VBOX_WITH_REM
4477 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
4478 {
4479 Assert(pVM->hm.s.vmx.pRealModeTSS);
4480 AssertCompile(PGMMODE_REAL < PGMMODE_PROTECTED);
4481 if ( pVCpu->hm.s.vmx.fWasInRealMode
4482 && PGMGetGuestMode(pVCpu) >= PGMMODE_PROTECTED)
4483 {
4484 /* Signal that the recompiler must flush its code-cache as the guest -may- rewrite code it will later execute
4485 in real-mode (e.g. OpenBSD 4.0) */
4486 REMFlushTBs(pVM);
4487 Log4(("Load[%RU32]: Switch to protected mode detected!\n", pVCpu->idCpu));
4488 pVCpu->hm.s.vmx.fWasInRealMode = false;
4489 }
4490 }
4491#endif
4492 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_CS_SEL, VMX_VMCS32_GUEST_CS_LIMIT, VMX_VMCS_GUEST_CS_BASE,
4493 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS, &pMixedCtx->cs);
4494 AssertRCReturn(rc, rc);
4495 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_SS_SEL, VMX_VMCS32_GUEST_SS_LIMIT, VMX_VMCS_GUEST_SS_BASE,
4496 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS, &pMixedCtx->ss);
4497 AssertRCReturn(rc, rc);
4498 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_DS_SEL, VMX_VMCS32_GUEST_DS_LIMIT, VMX_VMCS_GUEST_DS_BASE,
4499 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS, &pMixedCtx->ds);
4500 AssertRCReturn(rc, rc);
4501 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_ES_SEL, VMX_VMCS32_GUEST_ES_LIMIT, VMX_VMCS_GUEST_ES_BASE,
4502 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS, &pMixedCtx->es);
4503 AssertRCReturn(rc, rc);
4504 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FS_SEL, VMX_VMCS32_GUEST_FS_LIMIT, VMX_VMCS_GUEST_FS_BASE,
4505 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS, &pMixedCtx->fs);
4506 AssertRCReturn(rc, rc);
4507 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_GS_SEL, VMX_VMCS32_GUEST_GS_LIMIT, VMX_VMCS_GUEST_GS_BASE,
4508 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS, &pMixedCtx->gs);
4509 AssertRCReturn(rc, rc);
4510
4511#ifdef VBOX_STRICT
4512 /* Validate. */
4513 hmR0VmxValidateSegmentRegs(pVM, pVCpu, pMixedCtx);
4514#endif
4515
4516 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS);
4517 Log4(("Load[%RU32]: CS=%#RX16 Base=%#RX64 Limit=%#RX32 Attr=%#RX32\n", pVCpu->idCpu, pMixedCtx->cs.Sel,
4518 pMixedCtx->cs.u64Base, pMixedCtx->cs.u32Limit, pMixedCtx->cs.Attr.u));
4519 }
4520
4521 /*
4522 * Guest TR.
4523 */
4524 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_TR))
4525 {
4526 /*
4527 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is achieved
4528 * using the interrupt redirection bitmap (all bits cleared to let the guest handle INT-n's) in the TSS.
4529 * See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
4530 */
4531 uint16_t u16Sel = 0;
4532 uint32_t u32Limit = 0;
4533 uint64_t u64Base = 0;
4534 uint32_t u32AccessRights = 0;
4535
4536 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4537 {
4538 u16Sel = pMixedCtx->tr.Sel;
4539 u32Limit = pMixedCtx->tr.u32Limit;
4540 u64Base = pMixedCtx->tr.u64Base;
4541 u32AccessRights = pMixedCtx->tr.Attr.u;
4542 }
4543 else
4544 {
4545 Assert(pVM->hm.s.vmx.pRealModeTSS);
4546 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMR3CanExecuteGuest() -XXX- what about inner loop changes? */
4547
4548 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
4549 RTGCPHYS GCPhys;
4550 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
4551 AssertRCReturn(rc, rc);
4552
4553 X86DESCATTR DescAttr;
4554 DescAttr.u = 0;
4555 DescAttr.n.u1Present = 1;
4556 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
4557
4558 u16Sel = 0;
4559 u32Limit = HM_VTX_TSS_SIZE;
4560 u64Base = GCPhys; /* in real-mode phys = virt. */
4561 u32AccessRights = DescAttr.u;
4562 }
4563
4564 /* Validate. */
4565 Assert(!(u16Sel & RT_BIT(2)));
4566 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
4567 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
4568 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
4569 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
4570 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
4571 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
4572 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
4573 Assert( (u32Limit & 0xfff) == 0xfff
4574 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
4575 Assert( !(pMixedCtx->tr.u32Limit & 0xfff00000)
4576 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
4577
4578 rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_TR_SEL, u16Sel);
4579 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit);
4580 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_TR_BASE, u64Base);
4581 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights);
4582 AssertRCReturn(rc, rc);
4583
4584 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_TR);
4585 Log4(("Load[%RU32]: VMX_VMCS_GUEST_TR_BASE=%#RX64\n", pVCpu->idCpu, u64Base));
4586 }
4587
4588 /*
4589 * Guest GDTR.
4590 */
4591 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_GDTR))
4592 {
4593 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pMixedCtx->gdtr.cbGdt);
4594 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_GDTR_BASE, pMixedCtx->gdtr.pGdt);
4595 AssertRCReturn(rc, rc);
4596
4597 /* Validate. */
4598 Assert(!(pMixedCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
4599
4600 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_GDTR);
4601 Log4(("Load[%RU32]: VMX_VMCS_GUEST_GDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->gdtr.pGdt));
4602 }
4603
4604 /*
4605 * Guest LDTR.
4606 */
4607 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LDTR))
4608 {
4609 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
4610 uint32_t u32Access = 0;
4611 if (!pMixedCtx->ldtr.Attr.u)
4612 u32Access = X86DESCATTR_UNUSABLE;
4613 else
4614 u32Access = pMixedCtx->ldtr.Attr.u;
4615
4616 rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_LDTR_SEL, pMixedCtx->ldtr.Sel);
4617 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pMixedCtx->ldtr.u32Limit);
4618 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_LDTR_BASE, pMixedCtx->ldtr.u64Base);
4619 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access);
4620 AssertRCReturn(rc, rc);
4621
4622 /* Validate. */
4623 if (!(u32Access & X86DESCATTR_UNUSABLE))
4624 {
4625 Assert(!(pMixedCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
4626 Assert(pMixedCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
4627 Assert(!pMixedCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
4628 Assert(pMixedCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
4629 Assert(!pMixedCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
4630 Assert(!(pMixedCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
4631 Assert( (pMixedCtx->ldtr.u32Limit & 0xfff) == 0xfff
4632 || !pMixedCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
4633 Assert( !(pMixedCtx->ldtr.u32Limit & 0xfff00000)
4634 || pMixedCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
4635 }
4636
4637 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_LDTR);
4638 Log4(("Load[%RU32]: VMX_VMCS_GUEST_LDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->ldtr.u64Base));
4639 }
4640
4641 /*
4642 * Guest IDTR.
4643 */
4644 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_IDTR))
4645 {
4646 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pMixedCtx->idtr.cbIdt);
4647 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_IDTR_BASE, pMixedCtx->idtr.pIdt);
4648 AssertRCReturn(rc, rc);
4649
4650 /* Validate. */
4651 Assert(!(pMixedCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
4652
4653 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_IDTR);
4654 Log4(("Load[%RU32]: VMX_VMCS_GUEST_IDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->idtr.pIdt));
4655 }
4656
4657 return VINF_SUCCESS;
4658}
4659
4660
4661/**
4662 * Loads certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
4663 * areas.
4664 *
4665 * These MSRs will automatically be loaded to the host CPU on every successful
4666 * VM-entry and stored from the host CPU on every successful VM-exit. This also
4667 * creates/updates MSR slots for the host MSRs. The actual host MSR values are
4668 * -not- updated here for performance reasons. See hmR0VmxSaveHostMsrs().
4669 *
4670 * Also loads the sysenter MSRs into the guest-state area in the VMCS.
4671 *
4672 * @returns VBox status code.
4673 * @param pVCpu The cross context virtual CPU structure.
4674 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4675 * out-of-sync. Make sure to update the required fields
4676 * before using them.
4677 *
4678 * @remarks No-long-jump zone!!!
4679 */
4680static int hmR0VmxLoadGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4681{
4682 AssertPtr(pVCpu);
4683 AssertPtr(pVCpu->hm.s.vmx.pvGuestMsr);
4684
4685 /*
4686 * MSRs that we use the auto-load/store MSR area in the VMCS.
4687 */
4688 PVM pVM = pVCpu->CTX_SUFF(pVM);
4689 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS))
4690 {
4691 /* For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(). */
4692#if HC_ARCH_BITS == 32
4693 if (pVM->hm.s.fAllow64BitGuests)
4694 {
4695 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_LSTAR, pMixedCtx->msrLSTAR, false, NULL);
4696 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K6_STAR, pMixedCtx->msrSTAR, false, NULL);
4697 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_SF_MASK, pMixedCtx->msrSFMASK, false, NULL);
4698 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_KERNEL_GS_BASE, pMixedCtx->msrKERNELGSBASE, false, NULL);
4699 AssertRCReturn(rc, rc);
4700# ifdef LOG_ENABLED
4701 PVMXAUTOMSR pMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
4702 for (uint32_t i = 0; i < pVCpu->hm.s.vmx.cMsrs; i++, pMsr++)
4703 {
4704 Log4(("Load[%RU32]: MSR[%RU32]: u32Msr=%#RX32 u64Value=%#RX64\n", pVCpu->idCpu, i, pMsr->u32Msr,
4705 pMsr->u64Value));
4706 }
4707# endif
4708 }
4709#endif
4710 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
4711 }
4712
4713 /*
4714 * Guest Sysenter MSRs.
4715 * These flags are only set when MSR-bitmaps are not supported by the CPU and we cause
4716 * VM-exits on WRMSRs for these MSRs.
4717 */
4718 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR))
4719 {
4720 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pMixedCtx->SysEnter.cs); AssertRCReturn(rc, rc);
4721 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR);
4722 }
4723
4724 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR))
4725 {
4726 int rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, pMixedCtx->SysEnter.eip); AssertRCReturn(rc, rc);
4727 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
4728 }
4729
4730 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR))
4731 {
4732 int rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, pMixedCtx->SysEnter.esp); AssertRCReturn(rc, rc);
4733 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
4734 }
4735
4736 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_EFER_MSR))
4737 {
4738 if (hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
4739 {
4740 /*
4741 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
4742 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
4743 */
4744 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
4745 {
4746 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pMixedCtx->msrEFER);
4747 AssertRCReturn(rc,rc);
4748 Log4(("Load[%RU32]: VMX_VMCS64_GUEST_EFER_FULL=%#RX64\n", pVCpu->idCpu, pMixedCtx->msrEFER));
4749 }
4750 else
4751 {
4752 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K6_EFER, pMixedCtx->msrEFER, false /* fUpdateHostMsr */,
4753 NULL /* pfAddedAndUpdated */);
4754 AssertRCReturn(rc, rc);
4755
4756 /* We need to intercept reads too, see @bugref{7386#c16}. */
4757 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
4758 hmR0VmxSetMsrPermission(pVCpu, MSR_K6_EFER, VMXMSREXIT_INTERCEPT_READ, VMXMSREXIT_INTERCEPT_WRITE);
4759 Log4(("Load[%RU32]: MSR[--]: u32Msr=%#RX32 u64Value=%#RX64 cMsrs=%u\n", pVCpu->idCpu, MSR_K6_EFER,
4760 pMixedCtx->msrEFER, pVCpu->hm.s.vmx.cMsrs));
4761 }
4762 }
4763 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
4764 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, MSR_K6_EFER);
4765 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_EFER_MSR);
4766 }
4767
4768 return VINF_SUCCESS;
4769}
4770
4771
4772/**
4773 * Loads the guest activity state into the guest-state area in the VMCS.
4774 *
4775 * @returns VBox status code.
4776 * @param pVCpu The cross context virtual CPU structure.
4777 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4778 * out-of-sync. Make sure to update the required fields
4779 * before using them.
4780 *
4781 * @remarks No-long-jump zone!!!
4782 */
4783static int hmR0VmxLoadGuestActivityState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4784{
4785 NOREF(pMixedCtx);
4786 /** @todo See if we can make use of other states, e.g.
4787 * VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN or HLT. */
4788 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_ACTIVITY_STATE))
4789 {
4790 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, VMX_VMCS_GUEST_ACTIVITY_ACTIVE);
4791 AssertRCReturn(rc, rc);
4792
4793 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_ACTIVITY_STATE);
4794 }
4795 return VINF_SUCCESS;
4796}
4797
4798
4799/**
4800 * Sets up the appropriate function to run guest code.
4801 *
4802 * @returns VBox status code.
4803 * @param pVCpu The cross context virtual CPU structure.
4804 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4805 * out-of-sync. Make sure to update the required fields
4806 * before using them.
4807 *
4808 * @remarks No-long-jump zone!!!
4809 */
4810static int hmR0VmxSetupVMRunHandler(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4811{
4812 if (CPUMIsGuestInLongModeEx(pMixedCtx))
4813 {
4814#ifndef VBOX_ENABLE_64_BITS_GUESTS
4815 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
4816#endif
4817 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
4818#if HC_ARCH_BITS == 32
4819 /* 32-bit host. We need to switch to 64-bit before running the 64-bit guest. */
4820 if (pVCpu->hm.s.vmx.pfnStartVM != VMXR0SwitcherStartVM64)
4821 {
4822 if (pVCpu->hm.s.vmx.pfnStartVM != NULL) /* Very first entry would have saved host-state already, ignore it. */
4823 {
4824 /* Currently, all mode changes sends us back to ring-3, so these should be set. See @bugref{6944}. */
4825 AssertMsg(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_VMX_EXIT_CTLS
4826 | HM_CHANGED_VMX_ENTRY_CTLS
4827 | HM_CHANGED_GUEST_EFER_MSR), ("flags=%#x\n", HMCPU_CF_VALUE(pVCpu)));
4828 }
4829 pVCpu->hm.s.vmx.pfnStartVM = VMXR0SwitcherStartVM64;
4830 }
4831#else
4832 /* 64-bit host. */
4833 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM64;
4834#endif
4835 }
4836 else
4837 {
4838 /* Guest is not in long mode, use the 32-bit handler. */
4839#if HC_ARCH_BITS == 32
4840 if ( pVCpu->hm.s.vmx.pfnStartVM != VMXR0StartVM32
4841 && pVCpu->hm.s.vmx.pfnStartVM != NULL) /* Very first entry would have saved host-state already, ignore it. */
4842 {
4843 /* Currently, all mode changes sends us back to ring-3, so these should be set. See @bugref{6944}. */
4844 AssertMsg(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_VMX_EXIT_CTLS
4845 | HM_CHANGED_VMX_ENTRY_CTLS
4846 | HM_CHANGED_GUEST_EFER_MSR), ("flags=%#x\n", HMCPU_CF_VALUE(pVCpu)));
4847 }
4848#endif
4849 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4850 }
4851 Assert(pVCpu->hm.s.vmx.pfnStartVM);
4852 return VINF_SUCCESS;
4853}
4854
4855
4856/**
4857 * Wrapper for running the guest code in VT-x.
4858 *
4859 * @returns VBox status code, no informational status codes.
4860 * @param pVM The cross context VM structure.
4861 * @param pVCpu The cross context virtual CPU structure.
4862 * @param pCtx Pointer to the guest-CPU context.
4863 *
4864 * @remarks No-long-jump zone!!!
4865 */
4866DECLINLINE(int) hmR0VmxRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
4867{
4868 /*
4869 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses floating-point operations
4870 * using SSE instructions. Some XMM registers (XMM6-XMM15) are callee-saved and thus the need for this XMM wrapper.
4871 * Refer MSDN docs. "Configuring Programs for 64-bit / x64 Software Conventions / Register Usage" for details.
4872 */
4873 bool const fResumeVM = RT_BOOL(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_LAUNCHED);
4874 /** @todo Add stats for resume vs launch. */
4875#ifdef VBOX_WITH_KERNEL_USING_XMM
4876 int rc = HMR0VMXStartVMWrapXMM(fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu, pVCpu->hm.s.vmx.pfnStartVM);
4877#else
4878 int rc = pVCpu->hm.s.vmx.pfnStartVM(fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu);
4879#endif
4880 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
4881 return rc;
4882}
4883
4884
4885/**
4886 * Reports world-switch error and dumps some useful debug info.
4887 *
4888 * @param pVM The cross context VM structure.
4889 * @param pVCpu The cross context virtual CPU structure.
4890 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
4891 * @param pCtx Pointer to the guest-CPU context.
4892 * @param pVmxTransient Pointer to the VMX transient structure (only
4893 * exitReason updated).
4894 */
4895static void hmR0VmxReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, int rcVMRun, PCPUMCTX pCtx, PVMXTRANSIENT pVmxTransient)
4896{
4897 Assert(pVM);
4898 Assert(pVCpu);
4899 Assert(pCtx);
4900 Assert(pVmxTransient);
4901 HMVMX_ASSERT_PREEMPT_SAFE();
4902
4903 Log4(("VM-entry failure: %Rrc\n", rcVMRun));
4904 switch (rcVMRun)
4905 {
4906 case VERR_VMX_INVALID_VMXON_PTR:
4907 AssertFailed();
4908 break;
4909 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
4910 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
4911 {
4912 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
4913 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
4914 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
4915 AssertRC(rc);
4916
4917 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
4918 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
4919 Cannot do it here as we may have been long preempted. */
4920
4921#ifdef VBOX_STRICT
4922 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
4923 pVmxTransient->uExitReason));
4924 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQualification));
4925 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
4926 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
4927 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
4928 else
4929 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
4930 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
4931 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
4932
4933 /* VMX control bits. */
4934 uint32_t u32Val;
4935 uint64_t u64Val;
4936 RTHCUINTREG uHCReg;
4937 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val); AssertRC(rc);
4938 Log4(("VMX_VMCS32_CTRL_PIN_EXEC %#RX32\n", u32Val));
4939 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val); AssertRC(rc);
4940 Log4(("VMX_VMCS32_CTRL_PROC_EXEC %#RX32\n", u32Val));
4941 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val); AssertRC(rc);
4942 Log4(("VMX_VMCS32_CTRL_PROC_EXEC2 %#RX32\n", u32Val));
4943 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val); AssertRC(rc);
4944 Log4(("VMX_VMCS32_CTRL_ENTRY %#RX32\n", u32Val));
4945 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val); AssertRC(rc);
4946 Log4(("VMX_VMCS32_CTRL_EXIT %#RX32\n", u32Val));
4947 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_CR3_TARGET_COUNT, &u32Val); AssertRC(rc);
4948 Log4(("VMX_VMCS32_CTRL_CR3_TARGET_COUNT %#RX32\n", u32Val));
4949 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32Val); AssertRC(rc);
4950 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", u32Val));
4951 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &u32Val); AssertRC(rc);
4952 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", u32Val));
4953 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &u32Val); AssertRC(rc);
4954 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %u\n", u32Val));
4955 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, &u32Val); AssertRC(rc);
4956 Log4(("VMX_VMCS32_CTRL_TPR_THRESHOLD %u\n", u32Val));
4957 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &u32Val); AssertRC(rc);
4958 Log4(("VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT %u (guest MSRs)\n", u32Val));
4959 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &u32Val); AssertRC(rc);
4960 Log4(("VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT %u (host MSRs)\n", u32Val));
4961 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &u32Val); AssertRC(rc);
4962 Log4(("VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT %u (guest MSRs)\n", u32Val));
4963 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val); AssertRC(rc);
4964 Log4(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP %#RX32\n", u32Val));
4965 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, &u32Val); AssertRC(rc);
4966 Log4(("VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK %#RX32\n", u32Val));
4967 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, &u32Val); AssertRC(rc);
4968 Log4(("VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH %#RX32\n", u32Val));
4969 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
4970 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
4971 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
4972 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
4973 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
4974 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
4975 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
4976 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
4977 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
4978 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
4979
4980 /* Guest bits. */
4981 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RIP, &u64Val); AssertRC(rc);
4982 Log4(("Old Guest Rip %#RX64 New %#RX64\n", pCtx->rip, u64Val));
4983 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RSP, &u64Val); AssertRC(rc);
4984 Log4(("Old Guest Rsp %#RX64 New %#RX64\n", pCtx->rsp, u64Val));
4985 rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &u32Val); AssertRC(rc);
4986 Log4(("Old Guest Rflags %#RX32 New %#RX32\n", pCtx->eflags.u32, u32Val));
4987 rc = VMXReadVmcs32(VMX_VMCS16_VPID, &u32Val); AssertRC(rc);
4988 Log4(("VMX_VMCS16_VPID %u\n", u32Val));
4989
4990 /* Host bits. */
4991 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR0, &uHCReg); AssertRC(rc);
4992 Log4(("Host CR0 %#RHr\n", uHCReg));
4993 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR3, &uHCReg); AssertRC(rc);
4994 Log4(("Host CR3 %#RHr\n", uHCReg));
4995 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR4, &uHCReg); AssertRC(rc);
4996 Log4(("Host CR4 %#RHr\n", uHCReg));
4997
4998 RTGDTR HostGdtr;
4999 PCX86DESCHC pDesc;
5000 ASMGetGDTR(&HostGdtr);
5001 rc = VMXReadVmcs32(VMX_VMCS16_HOST_CS_SEL, &u32Val); AssertRC(rc);
5002 Log4(("Host CS %#08x\n", u32Val));
5003 if (u32Val < HostGdtr.cbGdt)
5004 {
5005 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5006 HMR0DumpDescriptor(pDesc, u32Val, "CS: ");
5007 }
5008
5009 rc = VMXReadVmcs32(VMX_VMCS16_HOST_DS_SEL, &u32Val); AssertRC(rc);
5010 Log4(("Host DS %#08x\n", u32Val));
5011 if (u32Val < HostGdtr.cbGdt)
5012 {
5013 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5014 HMR0DumpDescriptor(pDesc, u32Val, "DS: ");
5015 }
5016
5017 rc = VMXReadVmcs32(VMX_VMCS16_HOST_ES_SEL, &u32Val); AssertRC(rc);
5018 Log4(("Host ES %#08x\n", u32Val));
5019 if (u32Val < HostGdtr.cbGdt)
5020 {
5021 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5022 HMR0DumpDescriptor(pDesc, u32Val, "ES: ");
5023 }
5024
5025 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FS_SEL, &u32Val); AssertRC(rc);
5026 Log4(("Host FS %#08x\n", u32Val));
5027 if (u32Val < HostGdtr.cbGdt)
5028 {
5029 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5030 HMR0DumpDescriptor(pDesc, u32Val, "FS: ");
5031 }
5032
5033 rc = VMXReadVmcs32(VMX_VMCS16_HOST_GS_SEL, &u32Val); AssertRC(rc);
5034 Log4(("Host GS %#08x\n", u32Val));
5035 if (u32Val < HostGdtr.cbGdt)
5036 {
5037 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5038 HMR0DumpDescriptor(pDesc, u32Val, "GS: ");
5039 }
5040
5041 rc = VMXReadVmcs32(VMX_VMCS16_HOST_SS_SEL, &u32Val); AssertRC(rc);
5042 Log4(("Host SS %#08x\n", u32Val));
5043 if (u32Val < HostGdtr.cbGdt)
5044 {
5045 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5046 HMR0DumpDescriptor(pDesc, u32Val, "SS: ");
5047 }
5048
5049 rc = VMXReadVmcs32(VMX_VMCS16_HOST_TR_SEL, &u32Val); AssertRC(rc);
5050 Log4(("Host TR %#08x\n", u32Val));
5051 if (u32Val < HostGdtr.cbGdt)
5052 {
5053 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5054 HMR0DumpDescriptor(pDesc, u32Val, "TR: ");
5055 }
5056
5057 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_TR_BASE, &uHCReg); AssertRC(rc);
5058 Log4(("Host TR Base %#RHv\n", uHCReg));
5059 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_GDTR_BASE, &uHCReg); AssertRC(rc);
5060 Log4(("Host GDTR Base %#RHv\n", uHCReg));
5061 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_IDTR_BASE, &uHCReg); AssertRC(rc);
5062 Log4(("Host IDTR Base %#RHv\n", uHCReg));
5063 rc = VMXReadVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, &u32Val); AssertRC(rc);
5064 Log4(("Host SYSENTER CS %#08x\n", u32Val));
5065 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_SYSENTER_EIP, &uHCReg); AssertRC(rc);
5066 Log4(("Host SYSENTER EIP %#RHv\n", uHCReg));
5067 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_SYSENTER_ESP, &uHCReg); AssertRC(rc);
5068 Log4(("Host SYSENTER ESP %#RHv\n", uHCReg));
5069 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_RSP, &uHCReg); AssertRC(rc);
5070 Log4(("Host RSP %#RHv\n", uHCReg));
5071 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_RIP, &uHCReg); AssertRC(rc);
5072 Log4(("Host RIP %#RHv\n", uHCReg));
5073# if HC_ARCH_BITS == 64
5074 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
5075 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
5076 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
5077 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
5078 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
5079 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
5080# endif
5081#endif /* VBOX_STRICT */
5082 break;
5083 }
5084
5085 default:
5086 /* Impossible */
5087 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
5088 break;
5089 }
5090 NOREF(pVM); NOREF(pCtx);
5091}
5092
5093
5094#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
5095#ifndef VMX_USE_CACHED_VMCS_ACCESSES
5096# error "VMX_USE_CACHED_VMCS_ACCESSES not defined when it should be!"
5097#endif
5098#ifdef VBOX_STRICT
5099static bool hmR0VmxIsValidWriteField(uint32_t idxField)
5100{
5101 switch (idxField)
5102 {
5103 case VMX_VMCS_GUEST_RIP:
5104 case VMX_VMCS_GUEST_RSP:
5105 case VMX_VMCS_GUEST_SYSENTER_EIP:
5106 case VMX_VMCS_GUEST_SYSENTER_ESP:
5107 case VMX_VMCS_GUEST_GDTR_BASE:
5108 case VMX_VMCS_GUEST_IDTR_BASE:
5109 case VMX_VMCS_GUEST_CS_BASE:
5110 case VMX_VMCS_GUEST_DS_BASE:
5111 case VMX_VMCS_GUEST_ES_BASE:
5112 case VMX_VMCS_GUEST_FS_BASE:
5113 case VMX_VMCS_GUEST_GS_BASE:
5114 case VMX_VMCS_GUEST_SS_BASE:
5115 case VMX_VMCS_GUEST_LDTR_BASE:
5116 case VMX_VMCS_GUEST_TR_BASE:
5117 case VMX_VMCS_GUEST_CR3:
5118 return true;
5119 }
5120 return false;
5121}
5122
5123static bool hmR0VmxIsValidReadField(uint32_t idxField)
5124{
5125 switch (idxField)
5126 {
5127 /* Read-only fields. */
5128 case VMX_VMCS_RO_EXIT_QUALIFICATION:
5129 return true;
5130 }
5131 /* Remaining readable fields should also be writable. */
5132 return hmR0VmxIsValidWriteField(idxField);
5133}
5134#endif /* VBOX_STRICT */
5135
5136
5137/**
5138 * Executes the specified handler in 64-bit mode.
5139 *
5140 * @returns VBox status code (no informational status codes).
5141 * @param pVM The cross context VM structure.
5142 * @param pVCpu The cross context virtual CPU structure.
5143 * @param pCtx Pointer to the guest CPU context.
5144 * @param enmOp The operation to perform.
5145 * @param cParams Number of parameters.
5146 * @param paParam Array of 32-bit parameters.
5147 */
5148VMMR0DECL(int) VMXR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, HM64ON32OP enmOp,
5149 uint32_t cParams, uint32_t *paParam)
5150{
5151 NOREF(pCtx);
5152
5153 AssertReturn(pVM->hm.s.pfnHost32ToGuest64R0, VERR_HM_NO_32_TO_64_SWITCHER);
5154 Assert(enmOp > HM64ON32OP_INVALID && enmOp < HM64ON32OP_END);
5155 Assert(pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Write.aField));
5156 Assert(pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Read.aField));
5157
5158#ifdef VBOX_STRICT
5159 for (uint32_t i = 0; i < pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries; i++)
5160 Assert(hmR0VmxIsValidWriteField(pVCpu->hm.s.vmx.VMCSCache.Write.aField[i]));
5161
5162 for (uint32_t i = 0; i <pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries; i++)
5163 Assert(hmR0VmxIsValidReadField(pVCpu->hm.s.vmx.VMCSCache.Read.aField[i]));
5164#endif
5165
5166 /* Disable interrupts. */
5167 RTCCUINTREG fOldEFlags = ASMIntDisableFlags();
5168
5169#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
5170 RTCPUID idHostCpu = RTMpCpuId();
5171 CPUMR0SetLApic(pVCpu, idHostCpu);
5172#endif
5173
5174 PHMGLOBALCPUINFO pCpu = HMR0GetCurrentCpu();
5175 RTHCPHYS HCPhysCpuPage = pCpu->HCPhysMemObj;
5176
5177 /* Clear VMCS. Marking it inactive, clearing implementation-specific data and writing VMCS data back to memory. */
5178 VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
5179
5180 /* Leave VMX Root Mode. */
5181 VMXDisable();
5182
5183 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
5184
5185 CPUMSetHyperESP(pVCpu, VMMGetStackRC(pVCpu));
5186 CPUMSetHyperEIP(pVCpu, enmOp);
5187 for (int i = (int)cParams - 1; i >= 0; i--)
5188 CPUMPushHyper(pVCpu, paParam[i]);
5189
5190 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatWorldSwitch3264, z);
5191
5192 /* Call the switcher. */
5193 int rc = pVM->hm.s.pfnHost32ToGuest64R0(pVM, RT_OFFSETOF(VM, aCpus[pVCpu->idCpu].cpum) - RT_OFFSETOF(VM, cpum));
5194 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatWorldSwitch3264, z);
5195
5196 /** @todo replace with hmR0VmxEnterRootMode() and hmR0VmxLeaveRootMode(). */
5197 /* Make sure the VMX instructions don't cause #UD faults. */
5198 SUPR0ChangeCR4(X86_CR4_VMXE, ~0);
5199
5200 /* Re-enter VMX Root Mode */
5201 int rc2 = VMXEnable(HCPhysCpuPage);
5202 if (RT_FAILURE(rc2))
5203 {
5204 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
5205 ASMSetFlags(fOldEFlags);
5206 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
5207 return rc2;
5208 }
5209
5210 rc2 = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
5211 AssertRC(rc2);
5212 Assert(!(ASMGetFlags() & X86_EFL_IF));
5213 ASMSetFlags(fOldEFlags);
5214 return rc;
5215}
5216
5217
5218/**
5219 * Prepares for and executes VMLAUNCH (64-bit guests) for 32-bit hosts
5220 * supporting 64-bit guests.
5221 *
5222 * @returns VBox status code.
5223 * @param fResume Whether to VMLAUNCH or VMRESUME.
5224 * @param pCtx Pointer to the guest-CPU context.
5225 * @param pCache Pointer to the VMCS cache.
5226 * @param pVM The cross context VM structure.
5227 * @param pVCpu The cross context virtual CPU structure.
5228 */
5229DECLASM(int) VMXR0SwitcherStartVM64(RTHCUINT fResume, PCPUMCTX pCtx, PVMCSCACHE pCache, PVM pVM, PVMCPU pVCpu)
5230{
5231 NOREF(fResume);
5232
5233 PHMGLOBALCPUINFO pCpu = HMR0GetCurrentCpu();
5234 RTHCPHYS HCPhysCpuPage = pCpu->HCPhysMemObj;
5235
5236#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5237 pCache->uPos = 1;
5238 pCache->interPD = PGMGetInterPaeCR3(pVM);
5239 pCache->pSwitcher = (uint64_t)pVM->hm.s.pfnHost32ToGuest64R0;
5240#endif
5241
5242#if defined(DEBUG) && defined(VMX_USE_CACHED_VMCS_ACCESSES)
5243 pCache->TestIn.HCPhysCpuPage = 0;
5244 pCache->TestIn.HCPhysVmcs = 0;
5245 pCache->TestIn.pCache = 0;
5246 pCache->TestOut.HCPhysVmcs = 0;
5247 pCache->TestOut.pCache = 0;
5248 pCache->TestOut.pCtx = 0;
5249 pCache->TestOut.eflags = 0;
5250#else
5251 NOREF(pCache);
5252#endif
5253
5254 uint32_t aParam[10];
5255 aParam[0] = (uint32_t)(HCPhysCpuPage); /* Param 1: VMXON physical address - Lo. */
5256 aParam[1] = (uint32_t)(HCPhysCpuPage >> 32); /* Param 1: VMXON physical address - Hi. */
5257 aParam[2] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs); /* Param 2: VMCS physical address - Lo. */
5258 aParam[3] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs >> 32); /* Param 2: VMCS physical address - Hi. */
5259 aParam[4] = VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache);
5260 aParam[5] = 0;
5261 aParam[6] = VM_RC_ADDR(pVM, pVM);
5262 aParam[7] = 0;
5263 aParam[8] = VM_RC_ADDR(pVM, pVCpu);
5264 aParam[9] = 0;
5265
5266#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5267 pCtx->dr[4] = pVM->hm.s.vmx.pScratchPhys + 16 + 8;
5268 *(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) = 1;
5269#endif
5270 int rc = VMXR0Execute64BitsHandler(pVM, pVCpu, pCtx, HM64ON32OP_VMXRCStartVM64, RT_ELEMENTS(aParam), &aParam[0]);
5271
5272#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5273 Assert(*(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) == 5);
5274 Assert(pCtx->dr[4] == 10);
5275 *(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) = 0xff;
5276#endif
5277
5278#if defined(DEBUG) && defined(VMX_USE_CACHED_VMCS_ACCESSES)
5279 AssertMsg(pCache->TestIn.HCPhysCpuPage == HCPhysCpuPage, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysCpuPage, HCPhysCpuPage));
5280 AssertMsg(pCache->TestIn.HCPhysVmcs == pVCpu->hm.s.vmx.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
5281 pVCpu->hm.s.vmx.HCPhysVmcs));
5282 AssertMsg(pCache->TestIn.HCPhysVmcs == pCache->TestOut.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
5283 pCache->TestOut.HCPhysVmcs));
5284 AssertMsg(pCache->TestIn.pCache == pCache->TestOut.pCache, ("%RGv vs %RGv\n", pCache->TestIn.pCache,
5285 pCache->TestOut.pCache));
5286 AssertMsg(pCache->TestIn.pCache == VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache),
5287 ("%RGv vs %RGv\n", pCache->TestIn.pCache, VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache)));
5288 AssertMsg(pCache->TestIn.pCtx == pCache->TestOut.pCtx, ("%RGv vs %RGv\n", pCache->TestIn.pCtx,
5289 pCache->TestOut.pCtx));
5290 Assert(!(pCache->TestOut.eflags & X86_EFL_IF));
5291#endif
5292 return rc;
5293}
5294
5295
5296/**
5297 * Initialize the VMCS-Read cache.
5298 *
5299 * The VMCS cache is used for 32-bit hosts running 64-bit guests (except 32-bit
5300 * Darwin which runs with 64-bit paging in 32-bit mode) for 64-bit fields that
5301 * cannot be accessed in 32-bit mode. Some 64-bit fields -can- be accessed
5302 * (those that have a 32-bit FULL & HIGH part).
5303 *
5304 * @returns VBox status code.
5305 * @param pVM The cross context VM structure.
5306 * @param pVCpu The cross context virtual CPU structure.
5307 */
5308static int hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu)
5309{
5310#define VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, idxField) \
5311{ \
5312 Assert(pCache->Read.aField[idxField##_CACHE_IDX] == 0); \
5313 pCache->Read.aField[idxField##_CACHE_IDX] = idxField; \
5314 pCache->Read.aFieldVal[idxField##_CACHE_IDX] = 0; \
5315 ++cReadFields; \
5316}
5317
5318 AssertPtr(pVM);
5319 AssertPtr(pVCpu);
5320 PVMCSCACHE pCache = &pVCpu->hm.s.vmx.VMCSCache;
5321 uint32_t cReadFields = 0;
5322
5323 /*
5324 * Don't remove the #if 0'd fields in this code. They're listed here for consistency
5325 * and serve to indicate exceptions to the rules.
5326 */
5327
5328 /* Guest-natural selector base fields. */
5329#if 0
5330 /* These are 32-bit in practice. See Intel spec. 2.5 "Control Registers". */
5331 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR0);
5332 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR4);
5333#endif
5334 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_ES_BASE);
5335 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CS_BASE);
5336 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SS_BASE);
5337 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_DS_BASE);
5338 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_FS_BASE);
5339 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_GS_BASE);
5340 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_LDTR_BASE);
5341 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_TR_BASE);
5342 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_GDTR_BASE);
5343 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_IDTR_BASE);
5344 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_RSP);
5345 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_RIP);
5346#if 0
5347 /* Unused natural width guest-state fields. */
5348 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS);
5349 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR3); /* Handled in Nested Paging case */
5350#endif
5351 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SYSENTER_ESP);
5352 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SYSENTER_EIP);
5353
5354 /* 64-bit guest-state fields; unused as we use two 32-bit VMREADs for these 64-bit fields (using "FULL" and "HIGH" fields). */
5355#if 0
5356 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL);
5357 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_DEBUGCTL_FULL);
5358 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PAT_FULL);
5359 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_EFER_FULL);
5360 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL);
5361 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE0_FULL);
5362 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE1_FULL);
5363 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE2_FULL);
5364 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE3_FULL);
5365#endif
5366
5367 /* Natural width guest-state fields. */
5368 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_RO_EXIT_QUALIFICATION);
5369#if 0
5370 /* Currently unused field. */
5371 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_RO_EXIT_GUEST_LINEAR_ADDR);
5372#endif
5373
5374 if (pVM->hm.s.fNestedPaging)
5375 {
5376 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR3);
5377 AssertMsg(cReadFields == VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields,
5378 VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX));
5379 pCache->Read.cValidEntries = VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX;
5380 }
5381 else
5382 {
5383 AssertMsg(cReadFields == VMX_VMCS_MAX_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields, VMX_VMCS_MAX_CACHE_IDX));
5384 pCache->Read.cValidEntries = VMX_VMCS_MAX_CACHE_IDX;
5385 }
5386
5387#undef VMXLOCAL_INIT_READ_CACHE_FIELD
5388 return VINF_SUCCESS;
5389}
5390
5391
5392/**
5393 * Writes a field into the VMCS. This can either directly invoke a VMWRITE or
5394 * queue up the VMWRITE by using the VMCS write cache (on 32-bit hosts, except
5395 * darwin, running 64-bit guests).
5396 *
5397 * @returns VBox status code.
5398 * @param pVCpu The cross context virtual CPU structure.
5399 * @param idxField The VMCS field encoding.
5400 * @param u64Val 16, 32 or 64-bit value.
5401 */
5402VMMR0DECL(int) VMXWriteVmcs64Ex(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
5403{
5404 int rc;
5405 switch (idxField)
5406 {
5407 /*
5408 * These fields consists of a "FULL" and a "HIGH" part which can be written to individually.
5409 */
5410 /* 64-bit Control fields. */
5411 case VMX_VMCS64_CTRL_IO_BITMAP_A_FULL:
5412 case VMX_VMCS64_CTRL_IO_BITMAP_B_FULL:
5413 case VMX_VMCS64_CTRL_MSR_BITMAP_FULL:
5414 case VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL:
5415 case VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL:
5416 case VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL:
5417 case VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL:
5418 case VMX_VMCS64_CTRL_TSC_OFFSET_FULL:
5419 case VMX_VMCS64_CTRL_VAPIC_PAGEADDR_FULL:
5420 case VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL:
5421 case VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL:
5422 case VMX_VMCS64_CTRL_EPTP_FULL:
5423 case VMX_VMCS64_CTRL_EPTP_LIST_FULL:
5424 /* 64-bit Guest-state fields. */
5425 case VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL:
5426 case VMX_VMCS64_GUEST_DEBUGCTL_FULL:
5427 case VMX_VMCS64_GUEST_PAT_FULL:
5428 case VMX_VMCS64_GUEST_EFER_FULL:
5429 case VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL:
5430 case VMX_VMCS64_GUEST_PDPTE0_FULL:
5431 case VMX_VMCS64_GUEST_PDPTE1_FULL:
5432 case VMX_VMCS64_GUEST_PDPTE2_FULL:
5433 case VMX_VMCS64_GUEST_PDPTE3_FULL:
5434 /* 64-bit Host-state fields. */
5435 case VMX_VMCS64_HOST_PAT_FULL:
5436 case VMX_VMCS64_HOST_EFER_FULL:
5437 case VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL:
5438 {
5439 rc = VMXWriteVmcs32(idxField, u64Val);
5440 rc |= VMXWriteVmcs32(idxField + 1, (uint32_t)(u64Val >> 32));
5441 break;
5442 }
5443
5444 /*
5445 * These fields do not have high and low parts. Queue up the VMWRITE by using the VMCS write-cache (for 64-bit
5446 * values). When we switch the host to 64-bit mode for running 64-bit guests, these VMWRITEs get executed then.
5447 */
5448 /* Natural-width Guest-state fields. */
5449 case VMX_VMCS_GUEST_CR3:
5450 case VMX_VMCS_GUEST_ES_BASE:
5451 case VMX_VMCS_GUEST_CS_BASE:
5452 case VMX_VMCS_GUEST_SS_BASE:
5453 case VMX_VMCS_GUEST_DS_BASE:
5454 case VMX_VMCS_GUEST_FS_BASE:
5455 case VMX_VMCS_GUEST_GS_BASE:
5456 case VMX_VMCS_GUEST_LDTR_BASE:
5457 case VMX_VMCS_GUEST_TR_BASE:
5458 case VMX_VMCS_GUEST_GDTR_BASE:
5459 case VMX_VMCS_GUEST_IDTR_BASE:
5460 case VMX_VMCS_GUEST_RSP:
5461 case VMX_VMCS_GUEST_RIP:
5462 case VMX_VMCS_GUEST_SYSENTER_ESP:
5463 case VMX_VMCS_GUEST_SYSENTER_EIP:
5464 {
5465 if (!(u64Val >> 32))
5466 {
5467 /* If this field is 64-bit, VT-x will zero out the top bits. */
5468 rc = VMXWriteVmcs32(idxField, (uint32_t)u64Val);
5469 }
5470 else
5471 {
5472 /* Assert that only the 32->64 switcher case should ever come here. */
5473 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests);
5474 rc = VMXWriteCachedVmcsEx(pVCpu, idxField, u64Val);
5475 }
5476 break;
5477 }
5478
5479 default:
5480 {
5481 AssertMsgFailed(("VMXWriteVmcs64Ex: Invalid field %#RX32 (pVCpu=%p u64Val=%#RX64)\n", idxField, pVCpu, u64Val));
5482 rc = VERR_INVALID_PARAMETER;
5483 break;
5484 }
5485 }
5486 AssertRCReturn(rc, rc);
5487 return rc;
5488}
5489
5490
5491/**
5492 * Queue up a VMWRITE by using the VMCS write cache.
5493 * This is only used on 32-bit hosts (except darwin) for 64-bit guests.
5494 *
5495 * @param pVCpu The cross context virtual CPU structure.
5496 * @param idxField The VMCS field encoding.
5497 * @param u64Val 16, 32 or 64-bit value.
5498 */
5499VMMR0DECL(int) VMXWriteCachedVmcsEx(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
5500{
5501 AssertPtr(pVCpu);
5502 PVMCSCACHE pCache = &pVCpu->hm.s.vmx.VMCSCache;
5503
5504 AssertMsgReturn(pCache->Write.cValidEntries < VMCSCACHE_MAX_ENTRY - 1,
5505 ("entries=%u\n", pCache->Write.cValidEntries), VERR_ACCESS_DENIED);
5506
5507 /* Make sure there are no duplicates. */
5508 for (uint32_t i = 0; i < pCache->Write.cValidEntries; i++)
5509 {
5510 if (pCache->Write.aField[i] == idxField)
5511 {
5512 pCache->Write.aFieldVal[i] = u64Val;
5513 return VINF_SUCCESS;
5514 }
5515 }
5516
5517 pCache->Write.aField[pCache->Write.cValidEntries] = idxField;
5518 pCache->Write.aFieldVal[pCache->Write.cValidEntries] = u64Val;
5519 pCache->Write.cValidEntries++;
5520 return VINF_SUCCESS;
5521}
5522#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) */
5523
5524
5525/**
5526 * Sets up the usage of TSC-offsetting and updates the VMCS.
5527 *
5528 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
5529 * VMX preemption timer.
5530 *
5531 * @returns VBox status code.
5532 * @param pVM The cross context VM structure.
5533 * @param pVCpu The cross context virtual CPU structure.
5534 *
5535 * @remarks No-long-jump zone!!!
5536 */
5537static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVM pVM, PVMCPU pVCpu)
5538{
5539 int rc;
5540 bool fOffsettedTsc;
5541 bool fParavirtTsc;
5542 if (pVM->hm.s.vmx.fUsePreemptTimer)
5543 {
5544 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset,
5545 &fOffsettedTsc, &fParavirtTsc);
5546
5547 /* Make sure the returned values have sane upper and lower boundaries. */
5548 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
5549 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
5550 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
5551 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
5552
5553 uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
5554 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_PREEMPT_TIMER_VALUE, cPreemptionTickCount); AssertRC(rc);
5555 }
5556 else
5557 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset, &fParavirtTsc);
5558
5559 /** @todo later optimize this to be done elsewhere and not before every
5560 * VM-entry. */
5561 if (fParavirtTsc)
5562 {
5563 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
5564 information before every VM-entry, hence disable it for performance sake. */
5565#if 0
5566 rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
5567 AssertRC(rc);
5568#endif
5569 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
5570 }
5571
5572 if (fOffsettedTsc && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
5573 {
5574 /* Note: VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT takes precedence over TSC_OFFSET, applies to RDTSCP too. */
5575 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, pVCpu->hm.s.vmx.u64TSCOffset); AssertRC(rc);
5576
5577 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
5578 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
5579 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
5580 }
5581 else
5582 {
5583 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
5584 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
5585 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
5586 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
5587 }
5588}
5589
5590
5591/**
5592 * Determines if an exception is a contributory exception.
5593 *
5594 * Contributory exceptions are ones which can cause double-faults unless the
5595 * original exception was a benign exception. Page-fault is intentionally not
5596 * included here as it's a conditional contributory exception.
5597 *
5598 * @returns true if the exception is contributory, false otherwise.
5599 * @param uVector The exception vector.
5600 */
5601DECLINLINE(bool) hmR0VmxIsContributoryXcpt(const uint32_t uVector)
5602{
5603 switch (uVector)
5604 {
5605 case X86_XCPT_GP:
5606 case X86_XCPT_SS:
5607 case X86_XCPT_NP:
5608 case X86_XCPT_TS:
5609 case X86_XCPT_DE:
5610 return true;
5611 default:
5612 break;
5613 }
5614 return false;
5615}
5616
5617
5618/**
5619 * Sets an event as a pending event to be injected into the guest.
5620 *
5621 * @param pVCpu The cross context virtual CPU structure.
5622 * @param u32IntInfo The VM-entry interruption-information field.
5623 * @param cbInstr The VM-entry instruction length in bytes (for software
5624 * interrupts, exceptions and privileged software
5625 * exceptions).
5626 * @param u32ErrCode The VM-entry exception error code.
5627 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
5628 * page-fault.
5629 *
5630 * @remarks Statistics counter assumes this is a guest event being injected or
5631 * re-injected into the guest, i.e. 'StatInjectPendingReflect' is
5632 * always incremented.
5633 */
5634DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
5635 RTGCUINTPTR GCPtrFaultAddress)
5636{
5637 Assert(!pVCpu->hm.s.Event.fPending);
5638 pVCpu->hm.s.Event.fPending = true;
5639 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
5640 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
5641 pVCpu->hm.s.Event.cbInstr = cbInstr;
5642 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
5643
5644 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
5645}
5646
5647
5648/**
5649 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
5650 *
5651 * @param pVCpu The cross context virtual CPU structure.
5652 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5653 * out-of-sync. Make sure to update the required fields
5654 * before using them.
5655 */
5656DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5657{
5658 NOREF(pMixedCtx);
5659 uint32_t u32IntInfo = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
5660 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
5661 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
5662 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
5663}
5664
5665
5666/**
5667 * Handle a condition that occurred while delivering an event through the guest
5668 * IDT.
5669 *
5670 * @returns Strict VBox status code (i.e. informational status codes too).
5671 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
5672 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
5673 * to continue execution of the guest which will delivery the \#DF.
5674 * @retval VINF_EM_RESET if we detected a triple-fault condition.
5675 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
5676 *
5677 * @param pVCpu The cross context virtual CPU structure.
5678 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5679 * out-of-sync. Make sure to update the required fields
5680 * before using them.
5681 * @param pVmxTransient Pointer to the VMX transient structure.
5682 *
5683 * @remarks No-long-jump zone!!!
5684 */
5685static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
5686{
5687 uint32_t uExitVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
5688
5689 int rc2 = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient); AssertRCReturn(rc2, rc2);
5690 rc2 = hmR0VmxReadExitIntInfoVmcs(pVmxTransient); AssertRCReturn(rc2, rc2);
5691
5692 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
5693 if (VMX_IDT_VECTORING_INFO_VALID(pVmxTransient->uIdtVectoringInfo))
5694 {
5695 uint32_t uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
5696 uint32_t uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
5697
5698 typedef enum
5699 {
5700 VMXREFLECTXCPT_XCPT, /* Reflect the exception to the guest or for further evaluation by VMM. */
5701 VMXREFLECTXCPT_DF, /* Reflect the exception as a double-fault to the guest. */
5702 VMXREFLECTXCPT_TF, /* Indicate a triple faulted state to the VMM. */
5703 VMXREFLECTXCPT_HANG, /* Indicate bad VM trying to deadlock the CPU. */
5704 VMXREFLECTXCPT_NONE /* Nothing to reflect. */
5705 } VMXREFLECTXCPT;
5706
5707 /* See Intel spec. 30.7.1.1 "Reflecting Exceptions to Guest Software". */
5708 VMXREFLECTXCPT enmReflect = VMXREFLECTXCPT_NONE;
5709 if (VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo))
5710 {
5711 if (uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT)
5712 {
5713 enmReflect = VMXREFLECTXCPT_XCPT;
5714#ifdef VBOX_STRICT
5715 if ( hmR0VmxIsContributoryXcpt(uIdtVector)
5716 && uExitVector == X86_XCPT_PF)
5717 {
5718 Log4(("IDT: vcpu[%RU32] Contributory #PF uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
5719 }
5720#endif
5721 if ( uExitVector == X86_XCPT_PF
5722 && uIdtVector == X86_XCPT_PF)
5723 {
5724 pVmxTransient->fVectoringDoublePF = true;
5725 Log4(("IDT: vcpu[%RU32] Vectoring Double #PF uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
5726 }
5727 else if ( uExitVector == X86_XCPT_AC
5728 && uIdtVector == X86_XCPT_AC)
5729 {
5730 enmReflect = VMXREFLECTXCPT_HANG;
5731 Log4(("IDT: Nested #AC - Bad guest\n"));
5732 }
5733 else if ( (pVCpu->hm.s.vmx.u32XcptBitmap & HMVMX_CONTRIBUTORY_XCPT_MASK)
5734 && hmR0VmxIsContributoryXcpt(uExitVector)
5735 && ( hmR0VmxIsContributoryXcpt(uIdtVector)
5736 || uIdtVector == X86_XCPT_PF))
5737 {
5738 enmReflect = VMXREFLECTXCPT_DF;
5739 }
5740 else if (uIdtVector == X86_XCPT_DF)
5741 enmReflect = VMXREFLECTXCPT_TF;
5742 }
5743 else if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT
5744 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI)
5745 {
5746 /*
5747 * Ignore software interrupts (INT n), software exceptions (#BP, #OF) and
5748 * privileged software exception (#DB from ICEBP) as they reoccur when restarting the instruction.
5749 */
5750 enmReflect = VMXREFLECTXCPT_XCPT;
5751
5752 if (uExitVector == X86_XCPT_PF)
5753 {
5754 pVmxTransient->fVectoringPF = true;
5755 Log4(("IDT: vcpu[%RU32] Vectoring #PF due to Ext-Int/NMI. uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
5756 }
5757 }
5758 }
5759 else if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
5760 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT
5761 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI)
5762 {
5763 /*
5764 * If event delivery caused an EPT violation/misconfig or APIC access VM-exit, then the VM-exit
5765 * interruption-information will not be valid as it's not an exception and we end up here. In such cases,
5766 * it is sufficient to reflect the original exception to the guest after handling the VM-exit.
5767 */
5768 enmReflect = VMXREFLECTXCPT_XCPT;
5769 }
5770
5771 /*
5772 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig etc.) occurred
5773 * while delivering the NMI, we need to clear the block-by-NMI field in the guest interruptibility-state before
5774 * re-delivering the NMI after handling the VM-exit. Otherwise the subsequent VM-entry would fail.
5775 *
5776 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception". See @bugref{7445}.
5777 */
5778 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
5779 && enmReflect == VMXREFLECTXCPT_XCPT
5780 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
5781 && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
5782 {
5783 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
5784 }
5785
5786 switch (enmReflect)
5787 {
5788 case VMXREFLECTXCPT_XCPT:
5789 {
5790 Assert( uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT
5791 && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
5792 && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT);
5793
5794 uint32_t u32ErrCode = 0;
5795 if (VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo))
5796 {
5797 rc2 = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
5798 AssertRCReturn(rc2, rc2);
5799 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
5800 }
5801
5802 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF. See hmR0VmxExitXcptPF(). */
5803 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
5804 0 /* cbInstr */, u32ErrCode, pMixedCtx->cr2);
5805 rcStrict = VINF_SUCCESS;
5806 Log4(("IDT: vcpu[%RU32] Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->idCpu,
5807 pVCpu->hm.s.Event.u64IntInfo, pVCpu->hm.s.Event.u32ErrCode));
5808
5809 break;
5810 }
5811
5812 case VMXREFLECTXCPT_DF:
5813 {
5814 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
5815 rcStrict = VINF_HM_DOUBLE_FAULT;
5816 Log4(("IDT: vcpu[%RU32] Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->idCpu,
5817 pVCpu->hm.s.Event.u64IntInfo, uIdtVector, uExitVector));
5818
5819 break;
5820 }
5821
5822 case VMXREFLECTXCPT_TF:
5823 {
5824 rcStrict = VINF_EM_RESET;
5825 Log4(("IDT: vcpu[%RU32] Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", pVCpu->idCpu, uIdtVector,
5826 uExitVector));
5827 break;
5828 }
5829
5830 case VMXREFLECTXCPT_HANG:
5831 {
5832 rcStrict = VERR_EM_GUEST_CPU_HANG;
5833 break;
5834 }
5835
5836 default:
5837 Assert(rcStrict == VINF_SUCCESS);
5838 break;
5839 }
5840 }
5841 else if ( VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo)
5842 && VMX_EXIT_INTERRUPTION_INFO_NMI_UNBLOCK_IRET(pVmxTransient->uExitIntInfo)
5843 && uExitVector != X86_XCPT_DF
5844 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
5845 {
5846 /*
5847 * Execution of IRET caused this fault when NMI blocking was in effect (i.e we're in the guest NMI handler).
5848 * We need to set the block-by-NMI field so that NMIs remain blocked until the IRET execution is restarted.
5849 * See Intel spec. 30.7.1.2 "Resuming guest software after handling an exception".
5850 */
5851 if (!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
5852 {
5853 Log4(("hmR0VmxCheckExitDueToEventDelivery: vcpu[%RU32] Setting VMCPU_FF_BLOCK_NMIS. Valid=%RTbool uExitReason=%u\n",
5854 pVCpu->idCpu, VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo), pVmxTransient->uExitReason));
5855 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
5856 }
5857 }
5858
5859 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
5860 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
5861 return rcStrict;
5862}
5863
5864
5865/**
5866 * Saves the guest's CR0 register from the VMCS into the guest-CPU context.
5867 *
5868 * @returns VBox status code.
5869 * @param pVCpu The cross context virtual CPU structure.
5870 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5871 * out-of-sync. Make sure to update the required fields
5872 * before using them.
5873 *
5874 * @remarks No-long-jump zone!!!
5875 */
5876static int hmR0VmxSaveGuestCR0(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5877{
5878 NOREF(pMixedCtx);
5879
5880 /*
5881 * While in the middle of saving guest-CR0, we could get preempted and re-invoked from the preemption hook,
5882 * see hmR0VmxLeave(). Safer to just make this code non-preemptible.
5883 */
5884 VMMRZCallRing3Disable(pVCpu);
5885 HM_DISABLE_PREEMPT();
5886
5887 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0))
5888 {
5889 uint32_t uVal = 0;
5890 uint32_t uShadow = 0;
5891 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &uVal);
5892 rc |= VMXReadVmcs32(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uShadow);
5893 AssertRCReturn(rc, rc);
5894
5895 uVal = (uShadow & pVCpu->hm.s.vmx.u32CR0Mask) | (uVal & ~pVCpu->hm.s.vmx.u32CR0Mask);
5896 CPUMSetGuestCR0(pVCpu, uVal);
5897 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0);
5898 }
5899
5900 HM_RESTORE_PREEMPT();
5901 VMMRZCallRing3Enable(pVCpu);
5902 return VINF_SUCCESS;
5903}
5904
5905
5906/**
5907 * Saves the guest's CR4 register from the VMCS into the guest-CPU context.
5908 *
5909 * @returns VBox status code.
5910 * @param pVCpu The cross context virtual CPU structure.
5911 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5912 * out-of-sync. Make sure to update the required fields
5913 * before using them.
5914 *
5915 * @remarks No-long-jump zone!!!
5916 */
5917static int hmR0VmxSaveGuestCR4(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5918{
5919 NOREF(pMixedCtx);
5920
5921 int rc = VINF_SUCCESS;
5922 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4))
5923 {
5924 uint32_t uVal = 0;
5925 uint32_t uShadow = 0;
5926 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &uVal);
5927 rc |= VMXReadVmcs32(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uShadow);
5928 AssertRCReturn(rc, rc);
5929
5930 uVal = (uShadow & pVCpu->hm.s.vmx.u32CR4Mask) | (uVal & ~pVCpu->hm.s.vmx.u32CR4Mask);
5931 CPUMSetGuestCR4(pVCpu, uVal);
5932 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4);
5933 }
5934 return rc;
5935}
5936
5937
5938/**
5939 * Saves the guest's RIP register from the VMCS into the guest-CPU context.
5940 *
5941 * @returns VBox status code.
5942 * @param pVCpu The cross context virtual CPU structure.
5943 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5944 * out-of-sync. Make sure to update the required fields
5945 * before using them.
5946 *
5947 * @remarks No-long-jump zone!!!
5948 */
5949static int hmR0VmxSaveGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5950{
5951 int rc = VINF_SUCCESS;
5952 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP))
5953 {
5954 uint64_t u64Val = 0;
5955 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RIP, &u64Val);
5956 AssertRCReturn(rc, rc);
5957
5958 pMixedCtx->rip = u64Val;
5959 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP);
5960 }
5961 return rc;
5962}
5963
5964
5965/**
5966 * Saves the guest's RSP register from the VMCS into the guest-CPU context.
5967 *
5968 * @returns VBox status code.
5969 * @param pVCpu The cross context virtual CPU structure.
5970 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5971 * out-of-sync. Make sure to update the required fields
5972 * before using them.
5973 *
5974 * @remarks No-long-jump zone!!!
5975 */
5976static int hmR0VmxSaveGuestRsp(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5977{
5978 int rc = VINF_SUCCESS;
5979 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RSP))
5980 {
5981 uint64_t u64Val = 0;
5982 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RSP, &u64Val);
5983 AssertRCReturn(rc, rc);
5984
5985 pMixedCtx->rsp = u64Val;
5986 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RSP);
5987 }
5988 return rc;
5989}
5990
5991
5992/**
5993 * Saves the guest's RFLAGS from the VMCS into the guest-CPU context.
5994 *
5995 * @returns VBox status code.
5996 * @param pVCpu The cross context virtual CPU structure.
5997 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
5998 * out-of-sync. Make sure to update the required fields
5999 * before using them.
6000 *
6001 * @remarks No-long-jump zone!!!
6002 */
6003static int hmR0VmxSaveGuestRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6004{
6005 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS))
6006 {
6007 uint32_t uVal = 0;
6008 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &uVal);
6009 AssertRCReturn(rc, rc);
6010
6011 pMixedCtx->eflags.u32 = uVal;
6012 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active) /* Undo our real-on-v86-mode changes to eflags if necessary. */
6013 {
6014 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6015 Log4(("Saving real-mode EFLAGS VT-x view=%#RX32\n", pMixedCtx->eflags.u32));
6016
6017 pMixedCtx->eflags.Bits.u1VM = 0;
6018 pMixedCtx->eflags.Bits.u2IOPL = pVCpu->hm.s.vmx.RealMode.Eflags.Bits.u2IOPL;
6019 }
6020
6021 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS);
6022 }
6023 return VINF_SUCCESS;
6024}
6025
6026
6027/**
6028 * Wrapper for saving the guest's RIP, RSP and RFLAGS from the VMCS into the
6029 * guest-CPU context.
6030 */
6031DECLINLINE(int) hmR0VmxSaveGuestRipRspRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6032{
6033 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6034 rc |= hmR0VmxSaveGuestRsp(pVCpu, pMixedCtx);
6035 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
6036 return rc;
6037}
6038
6039
6040/**
6041 * Saves the guest's interruptibility-state ("interrupt shadow" as AMD calls it)
6042 * from the guest-state area in the VMCS.
6043 *
6044 * @param pVCpu The cross context virtual CPU structure.
6045 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6046 * out-of-sync. Make sure to update the required fields
6047 * before using them.
6048 *
6049 * @remarks No-long-jump zone!!!
6050 */
6051static void hmR0VmxSaveGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6052{
6053 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_INTR_STATE))
6054 {
6055 uint32_t uIntrState = 0;
6056 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
6057 AssertRC(rc);
6058
6059 if (!uIntrState)
6060 {
6061 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
6062 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
6063
6064 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6065 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
6066 }
6067 else
6068 {
6069 if (uIntrState & ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS
6070 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI))
6071 {
6072 rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6073 AssertRC(rc);
6074 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx); /* for hmR0VmxGetGuestIntrState(). */
6075 AssertRC(rc);
6076
6077 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
6078 Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
6079 }
6080 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
6081 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
6082
6083 if (uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI)
6084 {
6085 if (!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6086 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
6087 }
6088 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6089 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
6090 }
6091
6092 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_INTR_STATE);
6093 }
6094}
6095
6096
6097/**
6098 * Saves the guest's activity state.
6099 *
6100 * @returns VBox status code.
6101 * @param pVCpu The cross context virtual CPU structure.
6102 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6103 * out-of-sync. Make sure to update the required fields
6104 * before using them.
6105 *
6106 * @remarks No-long-jump zone!!!
6107 */
6108static int hmR0VmxSaveGuestActivityState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6109{
6110 NOREF(pMixedCtx);
6111 /* Nothing to do for now until we make use of different guest-CPU activity state. Just update the flag. */
6112 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_ACTIVITY_STATE);
6113 return VINF_SUCCESS;
6114}
6115
6116
6117/**
6118 * Saves the guest SYSENTER MSRs (SYSENTER_CS, SYSENTER_EIP, SYSENTER_ESP) from
6119 * the current VMCS into the guest-CPU context.
6120 *
6121 * @returns VBox status code.
6122 * @param pVCpu The cross context virtual CPU structure.
6123 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6124 * out-of-sync. Make sure to update the required fields
6125 * before using them.
6126 *
6127 * @remarks No-long-jump zone!!!
6128 */
6129static int hmR0VmxSaveGuestSysenterMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6130{
6131 int rc = VINF_SUCCESS;
6132 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR))
6133 {
6134 uint32_t u32Val = 0;
6135 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRCReturn(rc, rc);
6136 pMixedCtx->SysEnter.cs = u32Val;
6137 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR);
6138 }
6139
6140 uint64_t u64Val = 0;
6141 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR))
6142 {
6143 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, &u64Val); AssertRCReturn(rc, rc);
6144 pMixedCtx->SysEnter.eip = u64Val;
6145 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR);
6146 }
6147 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR))
6148 {
6149 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, &u64Val); AssertRCReturn(rc, rc);
6150 pMixedCtx->SysEnter.esp = u64Val;
6151 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR);
6152 }
6153 return rc;
6154}
6155
6156
6157/**
6158 * Saves the set of guest MSRs (that we restore lazily while leaving VT-x) from
6159 * the CPU back into the guest-CPU context.
6160 *
6161 * @returns VBox status code.
6162 * @param pVCpu The cross context virtual CPU structure.
6163 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6164 * out-of-sync. Make sure to update the required fields
6165 * before using them.
6166 *
6167 * @remarks No-long-jump zone!!!
6168 */
6169static int hmR0VmxSaveGuestLazyMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6170{
6171#if HC_ARCH_BITS == 64
6172 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
6173 {
6174 /* Since this can be called from our preemption hook it's safer to make the guest-MSRs update non-preemptible. */
6175 VMMRZCallRing3Disable(pVCpu);
6176 HM_DISABLE_PREEMPT();
6177
6178 /* Doing the check here ensures we don't overwrite already-saved guest MSRs from a preemption hook. */
6179 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS))
6180 {
6181 hmR0VmxLazySaveGuestMsrs(pVCpu, pMixedCtx);
6182 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS);
6183 }
6184
6185 HM_RESTORE_PREEMPT();
6186 VMMRZCallRing3Enable(pVCpu);
6187 }
6188 else
6189 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS);
6190#else
6191 NOREF(pMixedCtx);
6192 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS);
6193#endif
6194
6195 return VINF_SUCCESS;
6196}
6197
6198
6199/**
6200 * Saves the auto load/store'd guest MSRs from the current VMCS into
6201 * the guest-CPU context.
6202 *
6203 * @returns VBox status code.
6204 * @param pVCpu The cross context virtual CPU structure.
6205 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6206 * out-of-sync. Make sure to update the required fields
6207 * before using them.
6208 *
6209 * @remarks No-long-jump zone!!!
6210 */
6211static int hmR0VmxSaveGuestAutoLoadStoreMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6212{
6213 if (HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS))
6214 return VINF_SUCCESS;
6215
6216 PVMXAUTOMSR pMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
6217 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
6218 Log4(("hmR0VmxSaveGuestAutoLoadStoreMsrs: cMsrs=%u\n", cMsrs));
6219 for (uint32_t i = 0; i < cMsrs; i++, pMsr++)
6220 {
6221 switch (pMsr->u32Msr)
6222 {
6223 case MSR_K8_TSC_AUX: CPUMR0SetGuestTscAux(pVCpu, pMsr->u64Value); break;
6224 case MSR_K8_LSTAR: pMixedCtx->msrLSTAR = pMsr->u64Value; break;
6225 case MSR_K6_STAR: pMixedCtx->msrSTAR = pMsr->u64Value; break;
6226 case MSR_K8_SF_MASK: pMixedCtx->msrSFMASK = pMsr->u64Value; break;
6227 case MSR_K8_KERNEL_GS_BASE: pMixedCtx->msrKERNELGSBASE = pMsr->u64Value; break;
6228 case MSR_K6_EFER: /* Nothing to do here since we intercept writes, see hmR0VmxLoadGuestMsrs(). */
6229 break;
6230
6231 default:
6232 {
6233 AssertMsgFailed(("Unexpected MSR in auto-load/store area. uMsr=%#RX32 cMsrs=%u\n", pMsr->u32Msr, cMsrs));
6234 pVCpu->hm.s.u32HMError = pMsr->u32Msr;
6235 return VERR_HM_UNEXPECTED_LD_ST_MSR;
6236 }
6237 }
6238 }
6239
6240 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS);
6241 return VINF_SUCCESS;
6242}
6243
6244
6245/**
6246 * Saves the guest control registers from the current VMCS into the guest-CPU
6247 * context.
6248 *
6249 * @returns VBox status code.
6250 * @param pVCpu The cross context virtual CPU structure.
6251 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6252 * out-of-sync. Make sure to update the required fields
6253 * before using them.
6254 *
6255 * @remarks No-long-jump zone!!!
6256 */
6257static int hmR0VmxSaveGuestControlRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6258{
6259 /* Guest CR0. Guest FPU. */
6260 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6261 AssertRCReturn(rc, rc);
6262
6263 /* Guest CR4. */
6264 rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
6265 AssertRCReturn(rc, rc);
6266
6267 /* Guest CR2 - updated always during the world-switch or in #PF. */
6268 /* Guest CR3. Only changes with Nested Paging. This must be done -after- saving CR0 and CR4 from the guest! */
6269 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR3))
6270 {
6271 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
6272 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4));
6273
6274 PVM pVM = pVCpu->CTX_SUFF(pVM);
6275 if ( pVM->hm.s.vmx.fUnrestrictedGuest
6276 || ( pVM->hm.s.fNestedPaging
6277 && CPUMIsGuestPagingEnabledEx(pMixedCtx)))
6278 {
6279 uint64_t u64Val = 0;
6280 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_CR3, &u64Val);
6281 if (pMixedCtx->cr3 != u64Val)
6282 {
6283 CPUMSetGuestCR3(pVCpu, u64Val);
6284 if (VMMRZCallRing3IsEnabled(pVCpu))
6285 {
6286 PGMUpdateCR3(pVCpu, u64Val);
6287 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6288 }
6289 else
6290 {
6291 /* Set the force flag to inform PGM about it when necessary. It is cleared by PGMUpdateCR3().*/
6292 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
6293 }
6294 }
6295
6296 /* If the guest is in PAE mode, sync back the PDPE's into the guest state. */
6297 if (CPUMIsGuestInPAEModeEx(pMixedCtx)) /* Reads CR0, CR4 and EFER MSR (EFER is always up-to-date). */
6298 {
6299 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u);
6300 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u);
6301 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u);
6302 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u);
6303 AssertRCReturn(rc, rc);
6304
6305 if (VMMRZCallRing3IsEnabled(pVCpu))
6306 {
6307 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6308 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6309 }
6310 else
6311 {
6312 /* Set the force flag to inform PGM about it when necessary. It is cleared by PGMGstUpdatePaePdpes(). */
6313 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
6314 }
6315 }
6316 }
6317
6318 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR3);
6319 }
6320
6321 /*
6322 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
6323 * -> VMMRZCallRing3Disable() -> hmR0VmxSaveGuestState() -> Set VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
6324 * -> continue with VM-exit handling -> hmR0VmxSaveGuestControlRegs() and here we are.
6325 *
6326 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
6327 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
6328 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
6329 * -NOT- check if HMVMX_UPDATED_GUEST_CR3 is already set or not!
6330 *
6331 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
6332 */
6333 if (VMMRZCallRing3IsEnabled(pVCpu))
6334 {
6335 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
6336 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
6337
6338 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
6339 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6340
6341 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6342 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6343 }
6344
6345 return rc;
6346}
6347
6348
6349/**
6350 * Reads a guest segment register from the current VMCS into the guest-CPU
6351 * context.
6352 *
6353 * @returns VBox status code.
6354 * @param pVCpu The cross context virtual CPU structure.
6355 * @param idxSel Index of the selector in the VMCS.
6356 * @param idxLimit Index of the segment limit in the VMCS.
6357 * @param idxBase Index of the segment base in the VMCS.
6358 * @param idxAccess Index of the access rights of the segment in the VMCS.
6359 * @param pSelReg Pointer to the segment selector.
6360 *
6361 * @remarks No-long-jump zone!!!
6362 * @remarks Never call this function directly!!! Use the VMXLOCAL_READ_SEG()
6363 * macro as that takes care of whether to read from the VMCS cache or
6364 * not.
6365 */
6366DECLINLINE(int) hmR0VmxReadSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase, uint32_t idxAccess,
6367 PCPUMSELREG pSelReg)
6368{
6369 NOREF(pVCpu);
6370
6371 uint32_t u32Val = 0;
6372 int rc = VMXReadVmcs32(idxSel, &u32Val);
6373 AssertRCReturn(rc, rc);
6374 pSelReg->Sel = (uint16_t)u32Val;
6375 pSelReg->ValidSel = (uint16_t)u32Val;
6376 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
6377
6378 rc = VMXReadVmcs32(idxLimit, &u32Val);
6379 AssertRCReturn(rc, rc);
6380 pSelReg->u32Limit = u32Val;
6381
6382 uint64_t u64Val = 0;
6383 rc = VMXReadVmcsGstNByIdxVal(idxBase, &u64Val);
6384 AssertRCReturn(rc, rc);
6385 pSelReg->u64Base = u64Val;
6386
6387 rc = VMXReadVmcs32(idxAccess, &u32Val);
6388 AssertRCReturn(rc, rc);
6389 pSelReg->Attr.u = u32Val;
6390
6391 /*
6392 * If VT-x marks the segment as unusable, most other bits remain undefined:
6393 * - For CS the L, D and G bits have meaning.
6394 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
6395 * - For the remaining data segments no bits are defined.
6396 *
6397 * The present bit and the unusable bit has been observed to be set at the
6398 * same time (the selector was supposed to be invalid as we started executing
6399 * a V8086 interrupt in ring-0).
6400 *
6401 * What should be important for the rest of the VBox code, is that the P bit is
6402 * cleared. Some of the other VBox code recognizes the unusable bit, but
6403 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
6404 * safe side here, we'll strip off P and other bits we don't care about. If
6405 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
6406 *
6407 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
6408 */
6409 if (pSelReg->Attr.u & X86DESCATTR_UNUSABLE)
6410 {
6411 Assert(idxSel != VMX_VMCS16_GUEST_TR_SEL); /* TR is the only selector that can never be unusable. */
6412
6413 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
6414 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
6415 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
6416
6417 Log4(("hmR0VmxReadSegmentReg: Unusable idxSel=%#x attr=%#x -> %#x\n", idxSel, u32Val, pSelReg->Attr.u));
6418#ifdef DEBUG_bird
6419 AssertMsg((u32Val & ~X86DESCATTR_P) == pSelReg->Attr.u,
6420 ("%#x: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
6421 idxSel, u32Val, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
6422#endif
6423 }
6424 return VINF_SUCCESS;
6425}
6426
6427
6428#ifdef VMX_USE_CACHED_VMCS_ACCESSES
6429# define VMXLOCAL_READ_SEG(Sel, CtxSel) \
6430 hmR0VmxReadSegmentReg(pVCpu, VMX_VMCS16_GUEST_##Sel##_SEL, VMX_VMCS32_GUEST_##Sel##_LIMIT, \
6431 VMX_VMCS_GUEST_##Sel##_BASE_CACHE_IDX, VMX_VMCS32_GUEST_##Sel##_ACCESS_RIGHTS, &pMixedCtx->CtxSel)
6432#else
6433# define VMXLOCAL_READ_SEG(Sel, CtxSel) \
6434 hmR0VmxReadSegmentReg(pVCpu, VMX_VMCS16_GUEST_##Sel##_SEL, VMX_VMCS32_GUEST_##Sel##_LIMIT, \
6435 VMX_VMCS_GUEST_##Sel##_BASE, VMX_VMCS32_GUEST_##Sel##_ACCESS_RIGHTS, &pMixedCtx->CtxSel)
6436#endif
6437
6438
6439/**
6440 * Saves the guest segment registers from the current VMCS into the guest-CPU
6441 * context.
6442 *
6443 * @returns VBox status code.
6444 * @param pVCpu The cross context virtual CPU structure.
6445 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6446 * out-of-sync. Make sure to update the required fields
6447 * before using them.
6448 *
6449 * @remarks No-long-jump zone!!!
6450 */
6451static int hmR0VmxSaveGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6452{
6453 /* Guest segment registers. */
6454 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SEGMENT_REGS))
6455 {
6456 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6457 AssertRCReturn(rc, rc);
6458
6459 rc = VMXLOCAL_READ_SEG(CS, cs);
6460 rc |= VMXLOCAL_READ_SEG(SS, ss);
6461 rc |= VMXLOCAL_READ_SEG(DS, ds);
6462 rc |= VMXLOCAL_READ_SEG(ES, es);
6463 rc |= VMXLOCAL_READ_SEG(FS, fs);
6464 rc |= VMXLOCAL_READ_SEG(GS, gs);
6465 AssertRCReturn(rc, rc);
6466
6467 /* Restore segment attributes for real-on-v86 mode hack. */
6468 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
6469 {
6470 pMixedCtx->cs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrCS.u;
6471 pMixedCtx->ss.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrSS.u;
6472 pMixedCtx->ds.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrDS.u;
6473 pMixedCtx->es.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrES.u;
6474 pMixedCtx->fs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrFS.u;
6475 pMixedCtx->gs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrGS.u;
6476 }
6477 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SEGMENT_REGS);
6478 }
6479
6480 return VINF_SUCCESS;
6481}
6482
6483
6484/**
6485 * Saves the guest descriptor table registers and task register from the current
6486 * VMCS into the guest-CPU context.
6487 *
6488 * @returns VBox status code.
6489 * @param pVCpu The cross context virtual CPU structure.
6490 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6491 * out-of-sync. Make sure to update the required fields
6492 * before using them.
6493 *
6494 * @remarks No-long-jump zone!!!
6495 */
6496static int hmR0VmxSaveGuestTableRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6497{
6498 int rc = VINF_SUCCESS;
6499
6500 /* Guest LDTR. */
6501 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LDTR))
6502 {
6503 rc = VMXLOCAL_READ_SEG(LDTR, ldtr);
6504 AssertRCReturn(rc, rc);
6505 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LDTR);
6506 }
6507
6508 /* Guest GDTR. */
6509 uint64_t u64Val = 0;
6510 uint32_t u32Val = 0;
6511 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_GDTR))
6512 {
6513 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
6514 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRCReturn(rc, rc);
6515 pMixedCtx->gdtr.pGdt = u64Val;
6516 pMixedCtx->gdtr.cbGdt = u32Val;
6517 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_GDTR);
6518 }
6519
6520 /* Guest IDTR. */
6521 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_IDTR))
6522 {
6523 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
6524 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRCReturn(rc, rc);
6525 pMixedCtx->idtr.pIdt = u64Val;
6526 pMixedCtx->idtr.cbIdt = u32Val;
6527 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_IDTR);
6528 }
6529
6530 /* Guest TR. */
6531 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_TR))
6532 {
6533 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6534 AssertRCReturn(rc, rc);
6535
6536 /* For real-mode emulation using virtual-8086 mode we have the fake TSS (pRealModeTSS) in TR, don't save the fake one. */
6537 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
6538 {
6539 rc = VMXLOCAL_READ_SEG(TR, tr);
6540 AssertRCReturn(rc, rc);
6541 }
6542 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_TR);
6543 }
6544 return rc;
6545}
6546
6547#undef VMXLOCAL_READ_SEG
6548
6549
6550/**
6551 * Saves the guest debug-register DR7 from the current VMCS into the guest-CPU
6552 * context.
6553 *
6554 * @returns VBox status code.
6555 * @param pVCpu The cross context virtual CPU structure.
6556 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6557 * out-of-sync. Make sure to update the required fields
6558 * before using them.
6559 *
6560 * @remarks No-long-jump zone!!!
6561 */
6562static int hmR0VmxSaveGuestDR7(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6563{
6564 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_DEBUG))
6565 {
6566 if (!pVCpu->hm.s.fUsingHyperDR7)
6567 {
6568 /* Upper 32-bits are always zero. See Intel spec. 2.7.3 "Loading and Storing Debug Registers". */
6569 uint32_t u32Val;
6570 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_DR7, &u32Val); AssertRCReturn(rc, rc);
6571 pMixedCtx->dr[7] = u32Val;
6572 }
6573
6574 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_DEBUG);
6575 }
6576 return VINF_SUCCESS;
6577}
6578
6579
6580/**
6581 * Saves the guest APIC state from the current VMCS into the guest-CPU context.
6582 *
6583 * @returns VBox status code.
6584 * @param pVCpu The cross context virtual CPU structure.
6585 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6586 * out-of-sync. Make sure to update the required fields
6587 * before using them.
6588 *
6589 * @remarks No-long-jump zone!!!
6590 */
6591static int hmR0VmxSaveGuestApicState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6592{
6593 NOREF(pMixedCtx);
6594
6595 /* Updating TPR is already done in hmR0VmxPostRunGuest(). Just update the flag. */
6596 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_APIC_STATE);
6597 return VINF_SUCCESS;
6598}
6599
6600
6601/**
6602 * Saves the entire guest state from the currently active VMCS into the
6603 * guest-CPU context.
6604 *
6605 * This essentially VMREADs all guest-data.
6606 *
6607 * @returns VBox status code.
6608 * @param pVCpu The cross context virtual CPU structure.
6609 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6610 * out-of-sync. Make sure to update the required fields
6611 * before using them.
6612 */
6613static int hmR0VmxSaveGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6614{
6615 Assert(pVCpu);
6616 Assert(pMixedCtx);
6617
6618 if (HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL)
6619 return VINF_SUCCESS;
6620
6621 /* Though we can longjmp to ring-3 due to log-flushes here and get recalled
6622 again on the ring-3 callback path, there is no real need to. */
6623 if (VMMRZCallRing3IsEnabled(pVCpu))
6624 VMMR0LogFlushDisable(pVCpu);
6625 else
6626 Assert(VMMR0IsLogFlushDisabled(pVCpu));
6627 Log4Func(("vcpu[%RU32]\n", pVCpu->idCpu));
6628
6629 int rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
6630 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestRipRspRflags failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6631
6632 rc = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
6633 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestControlRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6634
6635 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
6636 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSegmentRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6637
6638 rc = hmR0VmxSaveGuestTableRegs(pVCpu, pMixedCtx);
6639 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestTableRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6640
6641 rc = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
6642 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestDR7 failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6643
6644 rc = hmR0VmxSaveGuestSysenterMsrs(pVCpu, pMixedCtx);
6645 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSysenterMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6646
6647 rc = hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
6648 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestLazyMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6649
6650 rc = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
6651 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestAutoLoadStoreMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6652
6653 rc = hmR0VmxSaveGuestActivityState(pVCpu, pMixedCtx);
6654 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestActivityState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6655
6656 rc = hmR0VmxSaveGuestApicState(pVCpu, pMixedCtx);
6657 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestApicState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6658
6659 AssertMsg(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL,
6660 ("Missed guest state bits while saving state; missing %RX32 (got %RX32, want %RX32) - check log for any previous errors!\n",
6661 HMVMX_UPDATED_GUEST_ALL ^ HMVMXCPU_GST_VALUE(pVCpu), HMVMXCPU_GST_VALUE(pVCpu), HMVMX_UPDATED_GUEST_ALL));
6662
6663 if (VMMRZCallRing3IsEnabled(pVCpu))
6664 VMMR0LogFlushEnable(pVCpu);
6665
6666 return VINF_SUCCESS;
6667}
6668
6669
6670/**
6671 * Saves basic guest registers needed for IEM instruction execution.
6672 *
6673 * @returns VBox status code (OR-able).
6674 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
6675 * @param pMixedCtx Pointer to the CPU context of the guest.
6676 * @param fMemory Whether the instruction being executed operates on
6677 * memory or not. Only CR0 is synced up if clear.
6678 * @param fNeedRsp Need RSP (any instruction working on GPRs or stack).
6679 */
6680static int hmR0VmxSaveGuestRegsForIemExec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fMemory, bool fNeedRsp)
6681{
6682 /*
6683 * We assume all general purpose registers other than RSP are available.
6684 *
6685 * RIP is a must, as it will be incremented or otherwise changed.
6686 *
6687 * RFLAGS are always required to figure the CPL.
6688 *
6689 * RSP isn't always required, however it's a GPR, so frequently required.
6690 *
6691 * SS and CS are the only segment register needed if IEM doesn't do memory
6692 * access (CPL + 16/32/64-bit mode), but we can only get all segment registers.
6693 *
6694 * CR0 is always required by IEM for the CPL, while CR3 and CR4 will only
6695 * be required for memory accesses.
6696 *
6697 * Note! Before IEM dispatches an exception, it will call us to sync in everything.
6698 */
6699 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6700 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
6701 if (fNeedRsp)
6702 rc |= hmR0VmxSaveGuestRsp(pVCpu, pMixedCtx);
6703 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
6704 if (!fMemory)
6705 rc |= hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6706 else
6707 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
6708 AssertRCReturn(rc, rc);
6709 return rc;
6710}
6711
6712
6713/**
6714 * Ensures that we've got a complete basic guest-context.
6715 *
6716 * This excludes the FPU, SSE, AVX, and similar extended state. The interface
6717 * is for the interpreter.
6718 *
6719 * @returns VBox status code.
6720 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
6721 * @param pMixedCtx Pointer to the guest-CPU context which may have data
6722 * needing to be synced in.
6723 * @thread EMT(pVCpu)
6724 */
6725VMMR0_INT_DECL(int) HMR0EnsureCompleteBasicContext(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6726{
6727 /* Note! Since this is only applicable to VT-x, the implementation is placed
6728 in the VT-x part of the sources instead of the generic stuff. */
6729 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported)
6730 return hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
6731 return VINF_SUCCESS;
6732}
6733
6734
6735/**
6736 * Check per-VM and per-VCPU force flag actions that require us to go back to
6737 * ring-3 for one reason or another.
6738 *
6739 * @returns Strict VBox status code (i.e. informational status codes too)
6740 * @retval VINF_SUCCESS if we don't have any actions that require going back to
6741 * ring-3.
6742 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
6743 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
6744 * interrupts)
6745 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
6746 * all EMTs to be in ring-3.
6747 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
6748 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
6749 * to the EM loop.
6750 *
6751 * @param pVM The cross context VM structure.
6752 * @param pVCpu The cross context virtual CPU structure.
6753 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6754 * out-of-sync. Make sure to update the required fields
6755 * before using them.
6756 * @param fStepping Running in hmR0VmxRunGuestCodeStep().
6757 */
6758static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fStepping)
6759{
6760 Assert(VMMRZCallRing3IsEnabled(pVCpu));
6761
6762 /*
6763 * Anything pending? Should be more likely than not if we're doing a good job.
6764 */
6765 if ( !fStepping
6766 ? !VM_FF_IS_PENDING(pVM, VM_FF_HP_R0_PRE_HM_MASK)
6767 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
6768 : !VM_FF_IS_PENDING(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
6769 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
6770 return VINF_SUCCESS;
6771
6772 /* We need the control registers now, make sure the guest-CPU context is updated. */
6773 int rc3 = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
6774 AssertRCReturn(rc3, rc3);
6775
6776 /* Pending HM CR3 sync. */
6777 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
6778 {
6779 int rc2 = PGMUpdateCR3(pVCpu, pMixedCtx->cr3);
6780 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
6781 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
6782 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6783 }
6784
6785 /* Pending HM PAE PDPEs. */
6786 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
6787 {
6788 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6789 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6790 }
6791
6792 /* Pending PGM C3 sync. */
6793 if (VMCPU_FF_IS_PENDING(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
6794 {
6795 VBOXSTRICTRC rcStrict2 = PGMSyncCR3(pVCpu, pMixedCtx->cr0, pMixedCtx->cr3, pMixedCtx->cr4,
6796 VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
6797 if (rcStrict2 != VINF_SUCCESS)
6798 {
6799 AssertRC(VBOXSTRICTRC_VAL(rcStrict2));
6800 Log4(("hmR0VmxCheckForceFlags: PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict2)));
6801 return rcStrict2;
6802 }
6803 }
6804
6805 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
6806 if ( VM_FF_IS_PENDING(pVM, VM_FF_HM_TO_R3_MASK)
6807 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
6808 {
6809 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
6810 int rc2 = RT_UNLIKELY(VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_NO_MEMORY : VINF_EM_RAW_TO_R3;
6811 Log4(("hmR0VmxCheckForceFlags: HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc2));
6812 return rc2;
6813 }
6814
6815 /* Pending VM request packets, such as hardware interrupts. */
6816 if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST)
6817 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
6818 {
6819 Log4(("hmR0VmxCheckForceFlags: Pending VM request forcing us back to ring-3\n"));
6820 return VINF_EM_PENDING_REQUEST;
6821 }
6822
6823 /* Pending PGM pool flushes. */
6824 if (VM_FF_IS_PENDING(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
6825 {
6826 Log4(("hmR0VmxCheckForceFlags: PGM pool flush pending forcing us back to ring-3\n"));
6827 return VINF_PGM_POOL_FLUSH_PENDING;
6828 }
6829
6830 /* Pending DMA requests. */
6831 if (VM_FF_IS_PENDING(pVM, VM_FF_PDM_DMA))
6832 {
6833 Log4(("hmR0VmxCheckForceFlags: Pending DMA request forcing us back to ring-3\n"));
6834 return VINF_EM_RAW_TO_R3;
6835 }
6836
6837 return VINF_SUCCESS;
6838}
6839
6840
6841/**
6842 * Converts any TRPM trap into a pending HM event. This is typically used when
6843 * entering from ring-3 (not longjmp returns).
6844 *
6845 * @param pVCpu The cross context virtual CPU structure.
6846 */
6847static void hmR0VmxTrpmTrapToPendingEvent(PVMCPU pVCpu)
6848{
6849 Assert(TRPMHasTrap(pVCpu));
6850 Assert(!pVCpu->hm.s.Event.fPending);
6851
6852 uint8_t uVector;
6853 TRPMEVENT enmTrpmEvent;
6854 RTGCUINT uErrCode;
6855 RTGCUINTPTR GCPtrFaultAddress;
6856 uint8_t cbInstr;
6857
6858 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
6859 AssertRC(rc);
6860
6861 /* Refer Intel spec. 24.8.3 "VM-entry Controls for Event Injection" for the format of u32IntInfo. */
6862 uint32_t u32IntInfo = uVector | VMX_EXIT_INTERRUPTION_INFO_VALID;
6863 if (enmTrpmEvent == TRPM_TRAP)
6864 {
6865 switch (uVector)
6866 {
6867 case X86_XCPT_NMI:
6868 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6869 break;
6870
6871 case X86_XCPT_BP:
6872 case X86_XCPT_OF:
6873 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6874 break;
6875
6876 case X86_XCPT_PF:
6877 case X86_XCPT_DF:
6878 case X86_XCPT_TS:
6879 case X86_XCPT_NP:
6880 case X86_XCPT_SS:
6881 case X86_XCPT_GP:
6882 case X86_XCPT_AC:
6883 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
6884 /* no break! */
6885 default:
6886 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6887 break;
6888 }
6889 }
6890 else if (enmTrpmEvent == TRPM_HARDWARE_INT)
6891 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6892 else if (enmTrpmEvent == TRPM_SOFTWARE_INT)
6893 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
6894 else
6895 AssertMsgFailed(("Invalid TRPM event type %d\n", enmTrpmEvent));
6896
6897 rc = TRPMResetTrap(pVCpu);
6898 AssertRC(rc);
6899 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
6900 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
6901
6902 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
6903 STAM_COUNTER_DEC(&pVCpu->hm.s.StatInjectPendingReflect);
6904}
6905
6906
6907/**
6908 * Converts the pending HM event into a TRPM trap.
6909 *
6910 * @param pVCpu The cross context virtual CPU structure.
6911 */
6912static void hmR0VmxPendingEventToTrpmTrap(PVMCPU pVCpu)
6913{
6914 Assert(pVCpu->hm.s.Event.fPending);
6915
6916 uint32_t uVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
6917 uint32_t uVector = VMX_IDT_VECTORING_INFO_VECTOR(pVCpu->hm.s.Event.u64IntInfo);
6918 bool fErrorCodeValid = VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVCpu->hm.s.Event.u64IntInfo);
6919 uint32_t uErrorCode = pVCpu->hm.s.Event.u32ErrCode;
6920
6921 /* If a trap was already pending, we did something wrong! */
6922 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
6923
6924 TRPMEVENT enmTrapType;
6925 switch (uVectorType)
6926 {
6927 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
6928 enmTrapType = TRPM_HARDWARE_INT;
6929 break;
6930
6931 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
6932 enmTrapType = TRPM_SOFTWARE_INT;
6933 break;
6934
6935 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
6936 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
6937 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT: /* #BP and #OF */
6938 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
6939 enmTrapType = TRPM_TRAP;
6940 break;
6941
6942 default:
6943 AssertMsgFailed(("Invalid trap type %#x\n", uVectorType));
6944 enmTrapType = TRPM_32BIT_HACK;
6945 break;
6946 }
6947
6948 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
6949
6950 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
6951 AssertRC(rc);
6952
6953 if (fErrorCodeValid)
6954 TRPMSetErrorCode(pVCpu, uErrorCode);
6955
6956 if ( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
6957 && uVector == X86_XCPT_PF)
6958 {
6959 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
6960 }
6961 else if ( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
6962 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
6963 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
6964 {
6965 AssertMsg( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
6966 || (uVector == X86_XCPT_BP || uVector == X86_XCPT_OF),
6967 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
6968 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
6969 }
6970
6971 /* Clear any pending events from the VMCS. */
6972 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
6973 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, 0); AssertRC(rc);
6974
6975 /* We're now done converting the pending event. */
6976 pVCpu->hm.s.Event.fPending = false;
6977}
6978
6979
6980/**
6981 * Does the necessary state syncing before returning to ring-3 for any reason
6982 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
6983 *
6984 * @returns VBox status code.
6985 * @param pVM The cross context VM structure.
6986 * @param pVCpu The cross context virtual CPU structure.
6987 * @param pMixedCtx Pointer to the guest-CPU context. The data may
6988 * be out-of-sync. Make sure to update the required
6989 * fields before using them.
6990 * @param fSaveGuestState Whether to save the guest state or not.
6991 *
6992 * @remarks No-long-jmp zone!!!
6993 */
6994static int hmR0VmxLeave(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fSaveGuestState)
6995{
6996 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
6997 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
6998
6999 RTCPUID idCpu = RTMpCpuId();
7000 Log4Func(("HostCpuId=%u\n", idCpu));
7001
7002 /*
7003 * !!! IMPORTANT !!!
7004 * If you modify code here, check whether hmR0VmxCallRing3Callback() needs to be updated too.
7005 */
7006
7007 /* Save the guest state if necessary. */
7008 if ( fSaveGuestState
7009 && HMVMXCPU_GST_VALUE(pVCpu) != HMVMX_UPDATED_GUEST_ALL)
7010 {
7011 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
7012 AssertRCReturn(rc, rc);
7013 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
7014 }
7015
7016 /* Restore host FPU state if necessary and resync on next R0 reentry .*/
7017 if (CPUMIsGuestFPUStateActive(pVCpu))
7018 {
7019 /* We shouldn't reload CR0 without saving it first. */
7020 if (!fSaveGuestState)
7021 {
7022 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7023 AssertRCReturn(rc, rc);
7024 }
7025 CPUMR0SaveGuestFPU(pVM, pVCpu, pMixedCtx);
7026 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
7027 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
7028 }
7029
7030 /* Restore host debug registers if necessary and resync on next R0 reentry. */
7031#ifdef VBOX_STRICT
7032 if (CPUMIsHyperDebugStateActive(pVCpu))
7033 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT);
7034#endif
7035 if (CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */))
7036 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
7037 Assert(!CPUMIsGuestDebugStateActive(pVCpu) && !CPUMIsGuestDebugStateActivePending(pVCpu));
7038 Assert(!CPUMIsHyperDebugStateActive(pVCpu) && !CPUMIsHyperDebugStateActivePending(pVCpu));
7039
7040#if HC_ARCH_BITS == 64
7041 /* Restore host-state bits that VT-x only restores partially. */
7042 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7043 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7044 {
7045 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
7046 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7047 }
7048 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7049#endif
7050
7051#if HC_ARCH_BITS == 64
7052 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7053 if ( pVM->hm.s.fAllow64BitGuests
7054 && pVCpu->hm.s.vmx.fLazyMsrs)
7055 {
7056 /* We shouldn't reload the guest MSRs without saving it first. */
7057 if (!fSaveGuestState)
7058 {
7059 int rc = hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
7060 AssertRCReturn(rc, rc);
7061 }
7062 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS));
7063 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7064 Assert(!pVCpu->hm.s.vmx.fLazyMsrs);
7065 }
7066#endif
7067
7068 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7069 pVCpu->hm.s.vmx.fUpdatedHostMsrs = false;
7070
7071 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
7072 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatLoadGuestState);
7073 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExit1);
7074 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExit2);
7075 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
7076 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
7077 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
7078 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7079
7080 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7081
7082 /** @todo This partially defeats the purpose of having preemption hooks.
7083 * The problem is, deregistering the hooks should be moved to a place that
7084 * lasts until the EMT is about to be destroyed not everytime while leaving HM
7085 * context.
7086 */
7087 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_ACTIVE)
7088 {
7089 int rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
7090 AssertRCReturn(rc, rc);
7091
7092 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
7093 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
7094 }
7095 Assert(!(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_LAUNCHED));
7096 NOREF(idCpu);
7097
7098 return VINF_SUCCESS;
7099}
7100
7101
7102/**
7103 * Leaves the VT-x session.
7104 *
7105 * @returns VBox status code.
7106 * @param pVM The cross context VM structure.
7107 * @param pVCpu The cross context virtual CPU structure.
7108 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7109 * out-of-sync. Make sure to update the required fields
7110 * before using them.
7111 *
7112 * @remarks No-long-jmp zone!!!
7113 */
7114DECLINLINE(int) hmR0VmxLeaveSession(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7115{
7116 HM_DISABLE_PREEMPT();
7117 HMVMX_ASSERT_CPU_SAFE();
7118 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7119 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7120
7121 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
7122 and done this from the VMXR0ThreadCtxCallback(). */
7123 if (!pVCpu->hm.s.fLeaveDone)
7124 {
7125 int rc2 = hmR0VmxLeave(pVM, pVCpu, pMixedCtx, true /* fSaveGuestState */);
7126 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
7127 pVCpu->hm.s.fLeaveDone = true;
7128 }
7129 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
7130
7131 /*
7132 * !!! IMPORTANT !!!
7133 * If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
7134 */
7135
7136 /* Deregister hook now that we've left HM context before re-enabling preemption. */
7137 /** @todo Deregistering here means we need to VMCLEAR always
7138 * (longjmp/exit-to-r3) in VT-x which is not efficient. */
7139 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
7140 VMMR0ThreadCtxHookDisable(pVCpu);
7141
7142 /* Leave HM context. This takes care of local init (term). */
7143 int rc = HMR0LeaveCpu(pVCpu);
7144
7145 HM_RESTORE_PREEMPT();
7146 return rc;
7147}
7148
7149
7150/**
7151 * Does the necessary state syncing before doing a longjmp to ring-3.
7152 *
7153 * @returns VBox status code.
7154 * @param pVM The cross context VM structure.
7155 * @param pVCpu The cross context virtual CPU structure.
7156 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7157 * out-of-sync. Make sure to update the required fields
7158 * before using them.
7159 *
7160 * @remarks No-long-jmp zone!!!
7161 */
7162DECLINLINE(int) hmR0VmxLongJmpToRing3(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7163{
7164 return hmR0VmxLeaveSession(pVM, pVCpu, pMixedCtx);
7165}
7166
7167
7168/**
7169 * Take necessary actions before going back to ring-3.
7170 *
7171 * An action requires us to go back to ring-3. This function does the necessary
7172 * steps before we can safely return to ring-3. This is not the same as longjmps
7173 * to ring-3, this is voluntary and prepares the guest so it may continue
7174 * executing outside HM (recompiler/IEM).
7175 *
7176 * @returns VBox status code.
7177 * @param pVM The cross context VM structure.
7178 * @param pVCpu The cross context virtual CPU structure.
7179 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7180 * out-of-sync. Make sure to update the required fields
7181 * before using them.
7182 * @param rcExit The reason for exiting to ring-3. Can be
7183 * VINF_VMM_UNKNOWN_RING3_CALL.
7184 */
7185static int hmR0VmxExitToRing3(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, VBOXSTRICTRC rcExit)
7186{
7187 Assert(pVM);
7188 Assert(pVCpu);
7189 Assert(pMixedCtx);
7190 HMVMX_ASSERT_PREEMPT_SAFE();
7191
7192 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
7193 {
7194 VMXGetActivatedVmcs(&pVCpu->hm.s.vmx.LastError.u64VMCSPhys);
7195 pVCpu->hm.s.vmx.LastError.u32VMCSRevision = *(uint32_t *)pVCpu->hm.s.vmx.pvVmcs;
7196 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
7197 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
7198 }
7199
7200 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
7201 VMMRZCallRing3Disable(pVCpu);
7202 Log4(("hmR0VmxExitToRing3: pVCpu=%p idCpu=%RU32 rcExit=%d\n", pVCpu, pVCpu->idCpu, VBOXSTRICTRC_VAL(rcExit)));
7203
7204 /* We need to do this only while truly exiting the "inner loop" back to ring-3 and -not- for any longjmp to ring3. */
7205 if (pVCpu->hm.s.Event.fPending)
7206 {
7207 hmR0VmxPendingEventToTrpmTrap(pVCpu);
7208 Assert(!pVCpu->hm.s.Event.fPending);
7209 }
7210
7211 /* Clear interrupt-window and NMI-window controls as we re-evaluate it when we return from ring-3. */
7212 hmR0VmxClearIntNmiWindowsVmcs(pVCpu);
7213
7214 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
7215 and if we're injecting an event we should have a TRPM trap pending. */
7216 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
7217#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a tripple fault in progress. */
7218 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
7219#endif
7220
7221 /* Save guest state and restore host state bits. */
7222 int rc = hmR0VmxLeaveSession(pVM, pVCpu, pMixedCtx);
7223 AssertRCReturn(rc, rc);
7224 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7225 /* Thread-context hooks are unregistered at this point!!! */
7226
7227 /* Sync recompiler state. */
7228 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
7229 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
7230 | CPUM_CHANGED_LDTR
7231 | CPUM_CHANGED_GDTR
7232 | CPUM_CHANGED_IDTR
7233 | CPUM_CHANGED_TR
7234 | CPUM_CHANGED_HIDDEN_SEL_REGS);
7235 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
7236 if ( pVM->hm.s.fNestedPaging
7237 && CPUMIsGuestPagingEnabledEx(pMixedCtx))
7238 {
7239 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
7240 }
7241
7242 Assert(!pVCpu->hm.s.fClearTrapFlag);
7243
7244 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
7245 if (rcExit != VINF_EM_RAW_INTERRUPT)
7246 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
7247
7248 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
7249
7250 /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
7251 VMMRZCallRing3RemoveNotification(pVCpu);
7252 VMMRZCallRing3Enable(pVCpu);
7253
7254 return rc;
7255}
7256
7257
7258/**
7259 * VMMRZCallRing3() callback wrapper which saves the guest state before we
7260 * longjump to ring-3 and possibly get preempted.
7261 *
7262 * @returns VBox status code.
7263 * @param pVCpu The cross context virtual CPU structure.
7264 * @param enmOperation The operation causing the ring-3 longjump.
7265 * @param pvUser Opaque pointer to the guest-CPU context. The data
7266 * may be out-of-sync. Make sure to update the required
7267 * fields before using them.
7268 */
7269static DECLCALLBACK(int) hmR0VmxCallRing3Callback(PVMCPU pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
7270{
7271 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
7272 {
7273 /*
7274 * !!! IMPORTANT !!!
7275 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
7276 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
7277 */
7278 VMMRZCallRing3RemoveNotification(pVCpu);
7279 VMMRZCallRing3Disable(pVCpu);
7280 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
7281 RTThreadPreemptDisable(&PreemptState);
7282
7283 PVM pVM = pVCpu->CTX_SUFF(pVM);
7284 if (CPUMIsGuestFPUStateActive(pVCpu))
7285 CPUMR0SaveGuestFPU(pVM, pVCpu, (PCPUMCTX)pvUser);
7286
7287 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
7288
7289#if HC_ARCH_BITS == 64
7290 /* Restore host-state bits that VT-x only restores partially. */
7291 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7292 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7293 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7294 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7295
7296 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7297 if ( pVM->hm.s.fAllow64BitGuests
7298 && pVCpu->hm.s.vmx.fLazyMsrs)
7299 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7300#endif
7301 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7302 pVCpu->hm.s.vmx.fUpdatedHostMsrs = false;
7303 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7304 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_ACTIVE)
7305 {
7306 VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
7307 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
7308 }
7309
7310 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
7311 VMMR0ThreadCtxHookDisable(pVCpu);
7312 HMR0LeaveCpu(pVCpu);
7313 RTThreadPreemptRestore(&PreemptState);
7314 return VINF_SUCCESS;
7315 }
7316
7317 Assert(pVCpu);
7318 Assert(pvUser);
7319 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7320 HMVMX_ASSERT_PREEMPT_SAFE();
7321
7322 VMMRZCallRing3Disable(pVCpu);
7323 Assert(VMMR0IsLogFlushDisabled(pVCpu));
7324
7325 Log4(("hmR0VmxCallRing3Callback->hmR0VmxLongJmpToRing3 pVCpu=%p idCpu=%RU32 enmOperation=%d\n", pVCpu, pVCpu->idCpu,
7326 enmOperation));
7327
7328 int rc = hmR0VmxLongJmpToRing3(pVCpu->CTX_SUFF(pVM), pVCpu, (PCPUMCTX)pvUser);
7329 AssertRCReturn(rc, rc);
7330
7331 VMMRZCallRing3Enable(pVCpu);
7332 return VINF_SUCCESS;
7333}
7334
7335
7336/**
7337 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
7338 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
7339 *
7340 * @param pVCpu The cross context virtual CPU structure.
7341 */
7342DECLINLINE(void) hmR0VmxSetIntWindowExitVmcs(PVMCPU pVCpu)
7343{
7344 if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
7345 {
7346 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
7347 {
7348 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT;
7349 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7350 AssertRC(rc);
7351 Log4(("Setup interrupt-window exiting\n"));
7352 }
7353 } /* else we will deliver interrupts whenever the guest exits next and is in a state to receive events. */
7354}
7355
7356
7357/**
7358 * Clears the interrupt-window exiting control in the VMCS.
7359 *
7360 * @param pVCpu The cross context virtual CPU structure.
7361 */
7362DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMCPU pVCpu)
7363{
7364 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT);
7365 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT;
7366 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7367 AssertRC(rc);
7368 Log4(("Cleared interrupt-window exiting\n"));
7369}
7370
7371
7372/**
7373 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
7374 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
7375 *
7376 * @param pVCpu The cross context virtual CPU structure.
7377 */
7378DECLINLINE(void) hmR0VmxSetNmiWindowExitVmcs(PVMCPU pVCpu)
7379{
7380 if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT))
7381 {
7382 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT))
7383 {
7384 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT;
7385 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7386 AssertRC(rc);
7387 Log4(("Setup NMI-window exiting\n"));
7388 }
7389 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
7390}
7391
7392
7393/**
7394 * Clears the NMI-window exiting control in the VMCS.
7395 *
7396 * @param pVCpu The cross context virtual CPU structure.
7397 */
7398DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMCPU pVCpu)
7399{
7400 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT);
7401 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT;
7402 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7403 AssertRC(rc);
7404 Log4(("Cleared NMI-window exiting\n"));
7405}
7406
7407
7408/**
7409 * Evaluates the event to be delivered to the guest and sets it as the pending
7410 * event.
7411 *
7412 * @returns The VT-x guest-interruptibility state.
7413 * @param pVCpu The cross context virtual CPU structure.
7414 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7415 * out-of-sync. Make sure to update the required fields
7416 * before using them.
7417 */
7418static uint32_t hmR0VmxEvaluatePendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7419{
7420 /* Get the current interruptibility-state of the guest and then figure out what can be injected. */
7421 uint32_t const uIntrState = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx);
7422 bool const fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7423 bool const fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7424 bool const fBlockNmi = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI);
7425
7426 Assert(!fBlockSti || HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS));
7427 Assert(!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
7428 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
7429 Assert(!TRPMHasTrap(pVCpu));
7430
7431#ifdef VBOX_WITH_NEW_APIC
7432 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
7433 APICUpdatePendingInterrupts(pVCpu);
7434#endif
7435
7436 /*
7437 * Toggling of interrupt force-flags here is safe since we update TRPM on premature exits
7438 * to ring-3 before executing guest code, see hmR0VmxExitToRing3(). We must NOT restore these force-flags.
7439 */
7440 /** @todo SMI. SMIs take priority over NMIs. */
7441 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NMI)) /* NMI. NMIs take priority over regular interrupts. */
7442 {
7443 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
7444 if ( !pVCpu->hm.s.Event.fPending
7445 && !fBlockNmi
7446 && !fBlockSti
7447 && !fBlockMovSS)
7448 {
7449 Log4(("Pending NMI vcpu[%RU32]\n", pVCpu->idCpu));
7450 uint32_t u32IntInfo = X86_XCPT_NMI | VMX_EXIT_INTERRUPTION_INFO_VALID;
7451 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7452
7453 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7454 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
7455 }
7456 else
7457 hmR0VmxSetNmiWindowExitVmcs(pVCpu);
7458 }
7459 /*
7460 * Check if the guest can receive external interrupts (PIC/APIC). Once PDMGetInterrupt() returns
7461 * a valid interrupt we must- deliver the interrupt. We can no longer re-request it from the APIC.
7462 */
7463 else if ( VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
7464 && !pVCpu->hm.s.fSingleInstruction)
7465 {
7466 Assert(!DBGFIsStepping(pVCpu));
7467 int rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7468 AssertRC(rc);
7469 bool const fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
7470 if ( !pVCpu->hm.s.Event.fPending
7471 && !fBlockInt
7472 && !fBlockSti
7473 && !fBlockMovSS)
7474 {
7475 uint8_t u8Interrupt;
7476 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
7477 if (RT_SUCCESS(rc))
7478 {
7479 Log4(("Pending interrupt vcpu[%RU32] u8Interrupt=%#x \n", pVCpu->idCpu, u8Interrupt));
7480 uint32_t u32IntInfo = u8Interrupt | VMX_EXIT_INTERRUPTION_INFO_VALID;
7481 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7482
7483 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrfaultAddress */);
7484 }
7485 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
7486 {
7487 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
7488 hmR0VmxApicSetTprThreshold(pVCpu, u8Interrupt >> 4);
7489 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
7490 }
7491 else
7492 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
7493 }
7494 else
7495 hmR0VmxSetIntWindowExitVmcs(pVCpu);
7496 }
7497
7498 return uIntrState;
7499}
7500
7501
7502/**
7503 * Sets a pending-debug exception to be delivered to the guest if the guest is
7504 * single-stepping in the VMCS.
7505 *
7506 * @param pVCpu The cross context virtual CPU structure.
7507 */
7508DECLINLINE(void) hmR0VmxSetPendingDebugXcptVmcs(PVMCPU pVCpu)
7509{
7510 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS)); NOREF(pVCpu);
7511 int rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_BS);
7512 AssertRC(rc);
7513}
7514
7515
7516/**
7517 * Injects any pending events into the guest if the guest is in a state to
7518 * receive them.
7519 *
7520 * @returns Strict VBox status code (i.e. informational status codes too).
7521 * @param pVCpu The cross context virtual CPU structure.
7522 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7523 * out-of-sync. Make sure to update the required fields
7524 * before using them.
7525 * @param uIntrState The VT-x guest-interruptibility state.
7526 * @param fStepping Running in hmR0VmxRunGuestCodeStep() and we should
7527 * return VINF_EM_DBG_STEPPED if the event was
7528 * dispatched directly.
7529 */
7530static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t uIntrState, bool fStepping)
7531{
7532 HMVMX_ASSERT_PREEMPT_SAFE();
7533 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7534
7535 bool fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7536 bool fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7537
7538 Assert(!fBlockSti || HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS));
7539 Assert(!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
7540 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
7541 Assert(!TRPMHasTrap(pVCpu));
7542
7543 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
7544 if (pVCpu->hm.s.Event.fPending)
7545 {
7546 /*
7547 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
7548 * pending even while injecting an event and in this case, we want a VM-exit as soon as
7549 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
7550 *
7551 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
7552 */
7553 uint32_t const uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
7554#ifdef VBOX_STRICT
7555 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
7556 {
7557 bool const fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
7558 Assert(!fBlockInt);
7559 Assert(!fBlockSti);
7560 Assert(!fBlockMovSS);
7561 }
7562 else if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
7563 {
7564 bool const fBlockNmi = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI);
7565 Assert(!fBlockSti);
7566 Assert(!fBlockMovSS);
7567 Assert(!fBlockNmi);
7568 }
7569#endif
7570 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#x\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
7571 (uint8_t)uIntType));
7572 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, pVCpu->hm.s.Event.u64IntInfo, pVCpu->hm.s.Event.cbInstr,
7573 pVCpu->hm.s.Event.u32ErrCode, pVCpu->hm.s.Event.GCPtrFaultAddress,
7574 fStepping, &uIntrState);
7575 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
7576
7577 /* Update the interruptibility-state as it could have been changed by
7578 hmR0VmxInjectEventVmcs() (e.g. real-on-v86 guest injecting software interrupts) */
7579 fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7580 fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7581
7582 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
7583 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
7584 else
7585 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
7586 }
7587
7588 /* Deliver pending debug exception if the guest is single-stepping. Evaluate and set the BS bit. */
7589 if ( fBlockSti
7590 || fBlockMovSS)
7591 {
7592 if (!pVCpu->hm.s.fSingleInstruction)
7593 {
7594 /*
7595 * The pending-debug exceptions field is cleared on all VM-exits except VMX_EXIT_TPR_BELOW_THRESHOLD,
7596 * VMX_EXIT_MTF, VMX_EXIT_APIC_WRITE and VMX_EXIT_VIRTUALIZED_EOI.
7597 * See Intel spec. 27.3.4 "Saving Non-Register State".
7598 */
7599 Assert(!DBGFIsStepping(pVCpu));
7600 int rc2 = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7601 AssertRCReturn(rc2, rc2);
7602 if (pMixedCtx->eflags.Bits.u1TF)
7603 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
7604 }
7605 else if (pMixedCtx->eflags.Bits.u1TF)
7606 {
7607 /*
7608 * We are single-stepping in the hypervisor debugger using EFLAGS.TF. Clear interrupt inhibition as setting the
7609 * BS bit would mean delivering a #DB to the guest upon VM-entry when it shouldn't be.
7610 */
7611 Assert(!(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG));
7612 uIntrState = 0;
7613 }
7614 }
7615
7616 /*
7617 * There's no need to clear the VM-entry interruption-information field here if we're not injecting anything.
7618 * VT-x clears the valid bit on every VM-exit. See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
7619 */
7620 int rc2 = hmR0VmxLoadGuestIntrState(pVCpu, uIntrState);
7621 AssertRC(rc2);
7622
7623 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
7624 NOREF(fBlockMovSS); NOREF(fBlockSti);
7625 return rcStrict;
7626}
7627
7628
7629/**
7630 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
7631 *
7632 * @param pVCpu The cross context virtual CPU structure.
7633 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7634 * out-of-sync. Make sure to update the required fields
7635 * before using them.
7636 */
7637DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7638{
7639 NOREF(pMixedCtx);
7640 uint32_t u32IntInfo = X86_XCPT_UD | VMX_EXIT_INTERRUPTION_INFO_VALID;
7641 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7642}
7643
7644
7645/**
7646 * Injects a double-fault (\#DF) exception into the VM.
7647 *
7648 * @returns Strict VBox status code (i.e. informational status codes too).
7649 * @param pVCpu The cross context virtual CPU structure.
7650 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7651 * out-of-sync. Make sure to update the required fields
7652 * before using them.
7653 * @param fStepping Whether we're running in hmR0VmxRunGuestCodeStep()
7654 * and should return VINF_EM_DBG_STEPPED if the event
7655 * is injected directly (register modified by us, not
7656 * by hardware on VM-entry).
7657 * @param puIntrState Pointer to the current guest interruptibility-state.
7658 * This interruptibility-state will be updated if
7659 * necessary. This cannot not be NULL.
7660 */
7661DECLINLINE(VBOXSTRICTRC) hmR0VmxInjectXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fStepping, uint32_t *puIntrState)
7662{
7663 uint32_t u32IntInfo = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
7664 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7665 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7666 return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */,
7667 fStepping, puIntrState);
7668}
7669
7670
7671/**
7672 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
7673 *
7674 * @param pVCpu The cross context virtual CPU structure.
7675 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7676 * out-of-sync. Make sure to update the required fields
7677 * before using them.
7678 */
7679DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7680{
7681 NOREF(pMixedCtx);
7682 uint32_t u32IntInfo = X86_XCPT_DB | VMX_EXIT_INTERRUPTION_INFO_VALID;
7683 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7684 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7685}
7686
7687
7688/**
7689 * Sets an overflow (\#OF) exception as pending-for-injection into the VM.
7690 *
7691 * @param pVCpu The cross context virtual CPU structure.
7692 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7693 * out-of-sync. Make sure to update the required fields
7694 * before using them.
7695 * @param cbInstr The value of RIP that is to be pushed on the guest
7696 * stack.
7697 */
7698DECLINLINE(void) hmR0VmxSetPendingXcptOF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
7699{
7700 NOREF(pMixedCtx);
7701 uint32_t u32IntInfo = X86_XCPT_OF | VMX_EXIT_INTERRUPTION_INFO_VALID;
7702 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7703 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7704}
7705
7706
7707/**
7708 * Injects a general-protection (\#GP) fault into the VM.
7709 *
7710 * @returns Strict VBox status code (i.e. informational status codes too).
7711 * @param pVCpu The cross context virtual CPU structure.
7712 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7713 * out-of-sync. Make sure to update the required fields
7714 * before using them.
7715 * @param fErrorCodeValid Whether the error code is valid (depends on the CPU
7716 * mode, i.e. in real-mode it's not valid).
7717 * @param u32ErrorCode The error code associated with the \#GP.
7718 * @param fStepping Whether we're running in
7719 * hmR0VmxRunGuestCodeStep() and should return
7720 * VINF_EM_DBG_STEPPED if the event is injected
7721 * directly (register modified by us, not by
7722 * hardware on VM-entry).
7723 * @param puIntrState Pointer to the current guest interruptibility-state.
7724 * This interruptibility-state will be updated if
7725 * necessary. This cannot not be NULL.
7726 */
7727DECLINLINE(VBOXSTRICTRC) hmR0VmxInjectXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fErrorCodeValid, uint32_t u32ErrorCode,
7728 bool fStepping, uint32_t *puIntrState)
7729{
7730 uint32_t u32IntInfo = X86_XCPT_GP | VMX_EXIT_INTERRUPTION_INFO_VALID;
7731 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7732 if (fErrorCodeValid)
7733 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7734 return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */,
7735 fStepping, puIntrState);
7736}
7737
7738
7739/**
7740 * Sets a general-protection (\#GP) exception as pending-for-injection into the
7741 * VM.
7742 *
7743 * @param pVCpu The cross context virtual CPU structure.
7744 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7745 * out-of-sync. Make sure to update the required fields
7746 * before using them.
7747 * @param u32ErrorCode The error code associated with the \#GP.
7748 */
7749DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t u32ErrorCode)
7750{
7751 NOREF(pMixedCtx);
7752 uint32_t u32IntInfo = X86_XCPT_GP | VMX_EXIT_INTERRUPTION_INFO_VALID;
7753 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7754 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7755 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */);
7756}
7757
7758
7759/**
7760 * Sets a software interrupt (INTn) as pending-for-injection into the VM.
7761 *
7762 * @param pVCpu The cross context virtual CPU structure.
7763 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7764 * out-of-sync. Make sure to update the required fields
7765 * before using them.
7766 * @param uVector The software interrupt vector number.
7767 * @param cbInstr The value of RIP that is to be pushed on the guest
7768 * stack.
7769 */
7770DECLINLINE(void) hmR0VmxSetPendingIntN(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint16_t uVector, uint32_t cbInstr)
7771{
7772 NOREF(pMixedCtx);
7773 uint32_t u32IntInfo = uVector | VMX_EXIT_INTERRUPTION_INFO_VALID;
7774 if ( uVector == X86_XCPT_BP
7775 || uVector == X86_XCPT_OF)
7776 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7777 else
7778 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7779 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7780}
7781
7782
7783/**
7784 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
7785 * stack.
7786 *
7787 * @returns Strict VBox status code (i.e. informational status codes too).
7788 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
7789 * @param pVM The cross context VM structure.
7790 * @param pMixedCtx Pointer to the guest-CPU context.
7791 * @param uValue The value to push to the guest stack.
7792 */
7793DECLINLINE(VBOXSTRICTRC) hmR0VmxRealModeGuestStackPush(PVM pVM, PCPUMCTX pMixedCtx, uint16_t uValue)
7794{
7795 /*
7796 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
7797 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
7798 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
7799 */
7800 if (pMixedCtx->sp == 1)
7801 return VINF_EM_RESET;
7802 pMixedCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
7803 int rc = PGMPhysSimpleWriteGCPhys(pVM, pMixedCtx->ss.u64Base + pMixedCtx->sp, &uValue, sizeof(uint16_t));
7804 AssertRC(rc);
7805 return rc;
7806}
7807
7808
7809/**
7810 * Injects an event into the guest upon VM-entry by updating the relevant fields
7811 * in the VM-entry area in the VMCS.
7812 *
7813 * @returns Strict VBox status code (i.e. informational status codes too).
7814 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
7815 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
7816 *
7817 * @param pVCpu The cross context virtual CPU structure.
7818 * @param pMixedCtx Pointer to the guest-CPU context. The data may
7819 * be out-of-sync. Make sure to update the required
7820 * fields before using them.
7821 * @param u64IntInfo The VM-entry interruption-information field.
7822 * @param cbInstr The VM-entry instruction length in bytes (for
7823 * software interrupts, exceptions and privileged
7824 * software exceptions).
7825 * @param u32ErrCode The VM-entry exception error code.
7826 * @param GCPtrFaultAddress The page-fault address for \#PF exceptions.
7827 * @param puIntrState Pointer to the current guest interruptibility-state.
7828 * This interruptibility-state will be updated if
7829 * necessary. This cannot not be NULL.
7830 * @param fStepping Whether we're running in
7831 * hmR0VmxRunGuestCodeStep() and should return
7832 * VINF_EM_DBG_STEPPED if the event is injected
7833 * directly (register modified by us, not by
7834 * hardware on VM-entry).
7835 *
7836 * @remarks Requires CR0!
7837 * @remarks No-long-jump zone!!!
7838 */
7839static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
7840 uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, bool fStepping,
7841 uint32_t *puIntrState)
7842{
7843 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
7844 AssertMsg(u64IntInfo >> 32 == 0, ("%#RX64\n", u64IntInfo));
7845 Assert(puIntrState);
7846 uint32_t u32IntInfo = (uint32_t)u64IntInfo;
7847
7848 uint32_t const uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(u32IntInfo);
7849 uint32_t const uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntInfo);
7850
7851#ifdef VBOX_STRICT
7852 /* Validate the error-code-valid bit for hardware exceptions. */
7853 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT)
7854 {
7855 switch (uVector)
7856 {
7857 case X86_XCPT_PF:
7858 case X86_XCPT_DF:
7859 case X86_XCPT_TS:
7860 case X86_XCPT_NP:
7861 case X86_XCPT_SS:
7862 case X86_XCPT_GP:
7863 case X86_XCPT_AC:
7864 AssertMsg(VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(u32IntInfo),
7865 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
7866 /* fallthru */
7867 default:
7868 break;
7869 }
7870 }
7871#endif
7872
7873 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
7874 Assert( uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
7875 || !(*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS));
7876
7877 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
7878
7879 /* We require CR0 to check if the guest is in real-mode. */
7880 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7881 AssertRCReturn(rc, rc);
7882
7883 /*
7884 * Hardware interrupts & exceptions cannot be delivered through the software interrupt redirection bitmap to the real
7885 * mode task in virtual-8086 mode. We must jump to the interrupt handler in the (real-mode) guest.
7886 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode" for interrupt & exception classes.
7887 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
7888 */
7889 if (CPUMIsGuestInRealModeEx(pMixedCtx))
7890 {
7891 PVM pVM = pVCpu->CTX_SUFF(pVM);
7892 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
7893 {
7894 Assert(PDMVmmDevHeapIsEnabled(pVM));
7895 Assert(pVM->hm.s.vmx.pRealModeTSS);
7896
7897 /* We require RIP, RSP, RFLAGS, CS, IDTR. Save the required ones from the VMCS. */
7898 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
7899 rc |= hmR0VmxSaveGuestTableRegs(pVCpu, pMixedCtx);
7900 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
7901 AssertRCReturn(rc, rc);
7902 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP));
7903
7904 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
7905 size_t const cbIdtEntry = sizeof(X86IDTR16);
7906 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pMixedCtx->idtr.cbIdt)
7907 {
7908 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
7909 if (uVector == X86_XCPT_DF)
7910 return VINF_EM_RESET;
7911
7912 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault. */
7913 if (uVector == X86_XCPT_GP)
7914 return hmR0VmxInjectXcptDF(pVCpu, pMixedCtx, fStepping, puIntrState);
7915
7916 /* If we're injecting an interrupt/exception with no valid IDT entry, inject a general-protection fault. */
7917 /* No error codes for exceptions in real-mode. See Intel spec. 20.1.4 "Interrupt and Exception Handling" */
7918 return hmR0VmxInjectXcptGP(pVCpu, pMixedCtx, false /* fErrCodeValid */, 0 /* u32ErrCode */,
7919 fStepping, puIntrState);
7920 }
7921
7922 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
7923 uint16_t uGuestIp = pMixedCtx->ip;
7924 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT)
7925 {
7926 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
7927 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
7928 uGuestIp = pMixedCtx->ip + (uint16_t)cbInstr;
7929 }
7930 else if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT)
7931 uGuestIp = pMixedCtx->ip + (uint16_t)cbInstr;
7932
7933 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
7934 X86IDTR16 IdtEntry;
7935 RTGCPHYS GCPhysIdtEntry = (RTGCPHYS)pMixedCtx->idtr.pIdt + uVector * cbIdtEntry;
7936 rc = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
7937 AssertRCReturn(rc, rc);
7938
7939 /* Construct the stack frame for the interrupt/exception handler. */
7940 VBOXSTRICTRC rcStrict;
7941 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, pMixedCtx->eflags.u32);
7942 if (rcStrict == VINF_SUCCESS)
7943 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, pMixedCtx->cs.Sel);
7944 if (rcStrict == VINF_SUCCESS)
7945 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, uGuestIp);
7946
7947 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
7948 if (rcStrict == VINF_SUCCESS)
7949 {
7950 pMixedCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
7951 pMixedCtx->rip = IdtEntry.offSel;
7952 pMixedCtx->cs.Sel = IdtEntry.uSel;
7953 pMixedCtx->cs.ValidSel = IdtEntry.uSel;
7954 pMixedCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
7955 if ( uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
7956 && uVector == X86_XCPT_PF)
7957 pMixedCtx->cr2 = GCPtrFaultAddress;
7958
7959 /* If any other guest-state bits are changed here, make sure to update
7960 hmR0VmxPreRunGuestCommitted() when thread-context hooks are used. */
7961 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS
7962 | HM_CHANGED_GUEST_RIP
7963 | HM_CHANGED_GUEST_RFLAGS
7964 | HM_CHANGED_GUEST_RSP);
7965
7966 /* We're clearing interrupts, which means no block-by-STI interrupt-inhibition. */
7967 if (*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
7968 {
7969 Assert( uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
7970 && uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
7971 Log4(("Clearing inhibition due to STI.\n"));
7972 *puIntrState &= ~VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
7973 }
7974 Log4(("Injecting real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
7975 u32IntInfo, u32ErrCode, cbInstr, pMixedCtx->eflags.u, pMixedCtx->cs.Sel, pMixedCtx->eip));
7976
7977 /* The event has been truly dispatched. Mark it as no longer pending so we don't attempt to 'undo'
7978 it, if we are returning to ring-3 before executing guest code. */
7979 pVCpu->hm.s.Event.fPending = false;
7980
7981 /* Make hmR0VmxPreRunGuest return if we're stepping since we've changed cs:rip. */
7982 if (fStepping)
7983 rcStrict = VINF_EM_DBG_STEPPED;
7984 }
7985 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
7986 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
7987 return rcStrict;
7988 }
7989
7990 /*
7991 * For unrestricted execution enabled CPUs running real-mode guests, we must not set the deliver-error-code bit.
7992 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
7993 */
7994 u32IntInfo &= ~VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7995 }
7996
7997 /* Validate. */
7998 Assert(VMX_EXIT_INTERRUPTION_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
7999 Assert(!VMX_EXIT_INTERRUPTION_INFO_NMI_UNBLOCK_IRET(u32IntInfo)); /* Bit 12 MBZ. */
8000 Assert(!(u32IntInfo & 0x7ffff000)); /* Bits 30:12 MBZ. */
8001
8002 /* Inject. */
8003 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8004 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(u32IntInfo))
8005 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8006 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8007
8008 if ( VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
8009 && uVector == X86_XCPT_PF)
8010 pMixedCtx->cr2 = GCPtrFaultAddress;
8011
8012 Log4(("Injecting vcpu[%RU32] u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x pMixedCtx->uCR2=%#RX64\n", pVCpu->idCpu,
8013 u32IntInfo, u32ErrCode, cbInstr, pMixedCtx->cr2));
8014
8015 AssertRCReturn(rc, rc);
8016 return VINF_SUCCESS;
8017}
8018
8019
8020/**
8021 * Clears the interrupt-window exiting control in the VMCS and if necessary
8022 * clears the current event in the VMCS as well.
8023 *
8024 * @returns VBox status code.
8025 * @param pVCpu The cross context virtual CPU structure.
8026 *
8027 * @remarks Use this function only to clear events that have not yet been
8028 * delivered to the guest but are injected in the VMCS!
8029 * @remarks No-long-jump zone!!!
8030 */
8031static void hmR0VmxClearIntNmiWindowsVmcs(PVMCPU pVCpu)
8032{
8033 Log4Func(("vcpu[%d]\n", pVCpu->idCpu));
8034
8035 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT)
8036 hmR0VmxClearIntWindowExitVmcs(pVCpu);
8037
8038 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT)
8039 hmR0VmxClearNmiWindowExitVmcs(pVCpu);
8040}
8041
8042
8043/**
8044 * Enters the VT-x session.
8045 *
8046 * @returns VBox status code.
8047 * @param pVM The cross context VM structure.
8048 * @param pVCpu The cross context virtual CPU structure.
8049 * @param pCpu Pointer to the CPU info struct.
8050 */
8051VMMR0DECL(int) VMXR0Enter(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
8052{
8053 AssertPtr(pVM);
8054 AssertPtr(pVCpu);
8055 Assert(pVM->hm.s.vmx.fSupported);
8056 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8057 NOREF(pCpu); NOREF(pVM);
8058
8059 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8060 Assert(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE));
8061
8062#ifdef VBOX_STRICT
8063 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
8064 RTCCUINTREG uHostCR4 = ASMGetCR4();
8065 if (!(uHostCR4 & X86_CR4_VMXE))
8066 {
8067 LogRel(("VMXR0Enter: X86_CR4_VMXE bit in CR4 is not set!\n"));
8068 return VERR_VMX_X86_CR4_VMXE_CLEARED;
8069 }
8070#endif
8071
8072 /*
8073 * Load the VCPU's VMCS as the current (and active) one.
8074 */
8075 Assert(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_CLEAR);
8076 int rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
8077 if (RT_FAILURE(rc))
8078 return rc;
8079
8080 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
8081 pVCpu->hm.s.fLeaveDone = false;
8082 Log4Func(("Activated Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8083
8084 return VINF_SUCCESS;
8085}
8086
8087
8088/**
8089 * The thread-context callback (only on platforms which support it).
8090 *
8091 * @param enmEvent The thread-context event.
8092 * @param pVCpu The cross context virtual CPU structure.
8093 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
8094 * @thread EMT(pVCpu)
8095 */
8096VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPU pVCpu, bool fGlobalInit)
8097{
8098 NOREF(fGlobalInit);
8099
8100 switch (enmEvent)
8101 {
8102 case RTTHREADCTXEVENT_OUT:
8103 {
8104 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8105 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8106 VMCPU_ASSERT_EMT(pVCpu);
8107
8108 PVM pVM = pVCpu->CTX_SUFF(pVM);
8109 PCPUMCTX pMixedCtx = CPUMQueryGuestCtxPtr(pVCpu);
8110
8111 /* No longjmps (logger flushes, locks) in this fragile context. */
8112 VMMRZCallRing3Disable(pVCpu);
8113 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
8114
8115 /*
8116 * Restore host-state (FPU, debug etc.)
8117 */
8118 if (!pVCpu->hm.s.fLeaveDone)
8119 {
8120 /* Do -not- save guest-state here as we might already be in the middle of saving it (esp. bad if we are
8121 holding the PGM lock while saving the guest state (see hmR0VmxSaveGuestControlRegs()). */
8122 hmR0VmxLeave(pVM, pVCpu, pMixedCtx, false /* fSaveGuestState */);
8123 pVCpu->hm.s.fLeaveDone = true;
8124 }
8125
8126 /* Leave HM context, takes care of local init (term). */
8127 int rc = HMR0LeaveCpu(pVCpu);
8128 AssertRC(rc); NOREF(rc);
8129
8130 /* Restore longjmp state. */
8131 VMMRZCallRing3Enable(pVCpu);
8132 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
8133 break;
8134 }
8135
8136 case RTTHREADCTXEVENT_IN:
8137 {
8138 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8139 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8140 VMCPU_ASSERT_EMT(pVCpu);
8141
8142 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
8143 VMMRZCallRing3Disable(pVCpu);
8144 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
8145
8146 /* Initialize the bare minimum state required for HM. This takes care of
8147 initializing VT-x if necessary (onlined CPUs, local init etc.) */
8148 int rc = HMR0EnterCpu(pVCpu);
8149 AssertRC(rc);
8150 Assert(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE));
8151
8152 /* Load the active VMCS as the current one. */
8153 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_CLEAR)
8154 {
8155 rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
8156 AssertRC(rc); NOREF(rc);
8157 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
8158 Log4Func(("Resumed: Activated Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8159 }
8160 pVCpu->hm.s.fLeaveDone = false;
8161
8162 /* Restore longjmp state. */
8163 VMMRZCallRing3Enable(pVCpu);
8164 break;
8165 }
8166
8167 default:
8168 break;
8169 }
8170}
8171
8172
8173/**
8174 * Saves the host state in the VMCS host-state.
8175 * Sets up the VM-exit MSR-load area.
8176 *
8177 * The CPU state will be loaded from these fields on every successful VM-exit.
8178 *
8179 * @returns VBox status code.
8180 * @param pVM The cross context VM structure.
8181 * @param pVCpu The cross context virtual CPU structure.
8182 *
8183 * @remarks No-long-jump zone!!!
8184 */
8185static int hmR0VmxSaveHostState(PVM pVM, PVMCPU pVCpu)
8186{
8187 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8188
8189 if (!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT))
8190 return VINF_SUCCESS;
8191
8192 int rc = hmR0VmxSaveHostControlRegs(pVM, pVCpu);
8193 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostControlRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8194
8195 rc = hmR0VmxSaveHostSegmentRegs(pVM, pVCpu);
8196 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostSegmentRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8197
8198 rc = hmR0VmxSaveHostMsrs(pVM, pVCpu);
8199 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostMsrs failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8200
8201 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_HOST_CONTEXT);
8202 return rc;
8203}
8204
8205
8206/**
8207 * Saves the host state in the VMCS host-state.
8208 *
8209 * @returns VBox status code.
8210 * @param pVM The cross context VM structure.
8211 * @param pVCpu The cross context virtual CPU structure.
8212 *
8213 * @remarks No-long-jump zone!!!
8214 */
8215VMMR0DECL(int) VMXR0SaveHostState(PVM pVM, PVMCPU pVCpu)
8216{
8217 AssertPtr(pVM);
8218 AssertPtr(pVCpu);
8219
8220 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8221
8222 /* Save the host state here while entering HM context. When thread-context hooks are used, we might get preempted
8223 and have to resave the host state but most of the time we won't be, so do it here before we disable interrupts. */
8224 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8225 return hmR0VmxSaveHostState(pVM, pVCpu);
8226}
8227
8228
8229/**
8230 * Loads the guest state into the VMCS guest-state area.
8231 *
8232 * The will typically be done before VM-entry when the guest-CPU state and the
8233 * VMCS state may potentially be out of sync.
8234 *
8235 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
8236 * VM-entry controls.
8237 * Sets up the appropriate VMX non-root function to execute guest code based on
8238 * the guest CPU mode.
8239 *
8240 * @returns VBox strict status code.
8241 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8242 * without unrestricted guest access and the VMMDev is not presently
8243 * mapped (e.g. EFI32).
8244 *
8245 * @param pVM The cross context VM structure.
8246 * @param pVCpu The cross context virtual CPU structure.
8247 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8248 * out-of-sync. Make sure to update the required fields
8249 * before using them.
8250 *
8251 * @remarks No-long-jump zone!!! (Disables and enables long jmps for itself,
8252 * caller disables then again on successfull return. Confusing.)
8253 */
8254static VBOXSTRICTRC hmR0VmxLoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
8255{
8256 AssertPtr(pVM);
8257 AssertPtr(pVCpu);
8258 AssertPtr(pMixedCtx);
8259 HMVMX_ASSERT_PREEMPT_SAFE();
8260
8261 VMMRZCallRing3Disable(pVCpu);
8262 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8263
8264 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8265
8266 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestState, x);
8267
8268 /* Determine real-on-v86 mode. */
8269 pVCpu->hm.s.vmx.RealMode.fRealOnV86Active = false;
8270 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
8271 && CPUMIsGuestInRealModeEx(pMixedCtx))
8272 {
8273 pVCpu->hm.s.vmx.RealMode.fRealOnV86Active = true;
8274 }
8275
8276 /*
8277 * Load the guest-state into the VMCS.
8278 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
8279 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
8280 */
8281 int rc = hmR0VmxSetupVMRunHandler(pVCpu, pMixedCtx);
8282 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupVMRunHandler! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8283
8284 /* This needs to be done after hmR0VmxSetupVMRunHandler() as changing pfnStartVM may require VM-entry control updates. */
8285 rc = hmR0VmxLoadGuestEntryCtls(pVCpu, pMixedCtx);
8286 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestEntryCtls! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8287
8288 /* This needs to be done after hmR0VmxSetupVMRunHandler() as changing pfnStartVM may require VM-exit control updates. */
8289 rc = hmR0VmxLoadGuestExitCtls(pVCpu, pMixedCtx);
8290 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupExitCtls failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8291
8292 rc = hmR0VmxLoadGuestActivityState(pVCpu, pMixedCtx);
8293 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestActivityState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8294
8295 VBOXSTRICTRC rcStrict = hmR0VmxLoadGuestCR3AndCR4(pVCpu, pMixedCtx);
8296 if (rcStrict == VINF_SUCCESS)
8297 { /* likely */ }
8298 else
8299 {
8300 VMMRZCallRing3Enable(pVCpu);
8301 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
8302 return rcStrict;
8303 }
8304
8305 /* Assumes pMixedCtx->cr0 is up-to-date (strict builds require CR0 for segment register validation checks). */
8306 rc = hmR0VmxLoadGuestSegmentRegs(pVCpu, pMixedCtx);
8307 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestSegmentRegs: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8308
8309 /* This needs to be done after hmR0VmxLoadGuestEntryCtls() and hmR0VmxLoadGuestExitCtls() as it may alter controls if we
8310 determine we don't have to swap EFER after all. */
8311 rc = hmR0VmxLoadGuestMsrs(pVCpu, pMixedCtx);
8312 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadSharedMsrs! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8313
8314 rc = hmR0VmxLoadGuestApicState(pVCpu, pMixedCtx);
8315 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestApicState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8316
8317 rc = hmR0VmxLoadGuestXcptIntercepts(pVCpu, pMixedCtx);
8318 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestXcptIntercepts! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8319
8320 /*
8321 * Loading Rflags here is fine, even though Rflags.TF might depend on guest debug state (which is not loaded here).
8322 * It is re-evaluated and updated if necessary in hmR0VmxLoadSharedState().
8323 */
8324 rc = hmR0VmxLoadGuestRipRspRflags(pVCpu, pMixedCtx);
8325 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestRipRspRflags! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8326
8327 /* Clear any unused and reserved bits. */
8328 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR2);
8329
8330 VMMRZCallRing3Enable(pVCpu);
8331
8332 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
8333 return rc;
8334}
8335
8336
8337/**
8338 * Loads the state shared between the host and guest into the VMCS.
8339 *
8340 * @param pVM The cross context VM structure.
8341 * @param pVCpu The cross context virtual CPU structure.
8342 * @param pCtx Pointer to the guest-CPU context.
8343 *
8344 * @remarks No-long-jump zone!!!
8345 */
8346static void hmR0VmxLoadSharedState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
8347{
8348 NOREF(pVM);
8349
8350 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8351 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8352
8353 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
8354 {
8355 int rc = hmR0VmxLoadSharedCR0(pVCpu, pCtx);
8356 AssertRC(rc);
8357 }
8358
8359 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_DEBUG))
8360 {
8361 int rc = hmR0VmxLoadSharedDebugState(pVCpu, pCtx);
8362 AssertRC(rc);
8363
8364 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
8365 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RFLAGS))
8366 {
8367 rc = hmR0VmxLoadGuestRflags(pVCpu, pCtx);
8368 AssertRC(rc);
8369 }
8370 }
8371
8372 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS))
8373 {
8374#if HC_ARCH_BITS == 64
8375 if (pVM->hm.s.fAllow64BitGuests)
8376 hmR0VmxLazyLoadGuestMsrs(pVCpu, pCtx);
8377#endif
8378 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS);
8379 }
8380
8381 /* Loading CR0, debug state might have changed intercepts, update VMCS. */
8382 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
8383 {
8384 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_AC));
8385 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
8386 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
8387 AssertRC(rc);
8388 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
8389 }
8390
8391 AssertMsg(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE),
8392 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8393}
8394
8395
8396/**
8397 * Worker for loading the guest-state bits in the inner VT-x execution loop.
8398 *
8399 * @returns Strict VBox status code (i.e. informational status codes too).
8400 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8401 * without unrestricted guest access and the VMMDev is not presently
8402 * mapped (e.g. EFI32).
8403 *
8404 * @param pVM The cross context VM structure.
8405 * @param pVCpu The cross context virtual CPU structure.
8406 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8407 * out-of-sync. Make sure to update the required fields
8408 * before using them.
8409 */
8410static VBOXSTRICTRC hmR0VmxLoadGuestStateOptimal(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
8411{
8412 HMVMX_ASSERT_PREEMPT_SAFE();
8413
8414 Log5(("LoadFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8415#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
8416 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
8417#endif
8418
8419 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
8420 if (HMCPU_CF_IS_SET_ONLY(pVCpu, HM_CHANGED_GUEST_RIP))
8421 {
8422 rcStrict = hmR0VmxLoadGuestRip(pVCpu, pMixedCtx);
8423 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8424 { /* likely */}
8425 else
8426 {
8427 AssertLogRelMsgFailedReturn(("hmR0VmxLoadGuestStateOptimal: hmR0VmxLoadGuestRip failed! rc=%Rrc\n",
8428 VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
8429 }
8430 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadMinimal);
8431 }
8432 else if (HMCPU_CF_VALUE(pVCpu))
8433 {
8434 rcStrict = hmR0VmxLoadGuestState(pVM, pVCpu, pMixedCtx);
8435 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8436 { /* likely */}
8437 else
8438 {
8439 AssertLogRelMsg(rcStrict == VINF_EM_RESCHEDULE_REM,
8440 ("hmR0VmxLoadGuestStateOptimal: hmR0VmxLoadGuestState failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8441 return rcStrict;
8442 }
8443 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadFull);
8444 }
8445
8446 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
8447 AssertMsg( !HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_ALL_GUEST)
8448 || HMCPU_CF_IS_PENDING_ONLY(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE),
8449 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8450 return rcStrict;
8451}
8452
8453
8454/**
8455 * Does the preparations before executing guest code in VT-x.
8456 *
8457 * This may cause longjmps to ring-3 and may even result in rescheduling to the
8458 * recompiler/IEM. We must be cautious what we do here regarding committing
8459 * guest-state information into the VMCS assuming we assuredly execute the
8460 * guest in VT-x mode.
8461 *
8462 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
8463 * the common-state (TRPM/forceflags), we must undo those changes so that the
8464 * recompiler/IEM can (and should) use them when it resumes guest execution.
8465 * Otherwise such operations must be done when we can no longer exit to ring-3.
8466 *
8467 * @returns Strict VBox status code (i.e. informational status codes too).
8468 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
8469 * have been disabled.
8470 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
8471 * double-fault into the guest.
8472 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
8473 * dispatched directly.
8474 * @retval VINF_* scheduling changes, we have to go back to ring-3.
8475 *
8476 * @param pVM The cross context VM structure.
8477 * @param pVCpu The cross context virtual CPU structure.
8478 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8479 * out-of-sync. Make sure to update the required fields
8480 * before using them.
8481 * @param pVmxTransient Pointer to the VMX transient structure.
8482 * @param fStepping Set if called from hmR0VmxRunGuestCodeStep(). Makes
8483 * us ignore some of the reasons for returning to
8484 * ring-3, and return VINF_EM_DBG_STEPPED if event
8485 * dispatching took place.
8486 */
8487static VBOXSTRICTRC hmR0VmxPreRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, bool fStepping)
8488{
8489 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8490
8491#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
8492 PGMRZDynMapFlushAutoSet(pVCpu);
8493#endif
8494
8495 /* Check force flag actions that might require us to go back to ring-3. */
8496 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVM, pVCpu, pMixedCtx, fStepping);
8497 if (rcStrict == VINF_SUCCESS)
8498 { /* FFs doesn't get set all the time. */ }
8499 else
8500 return rcStrict;
8501
8502#ifndef IEM_VERIFICATION_MODE_FULL
8503 /* Setup the Virtualized APIC accesses. pMixedCtx->msrApicBase is always up-to-date. It's not part of the VMCS. */
8504 if ( pVCpu->hm.s.vmx.u64MsrApicBase != pMixedCtx->msrApicBase
8505 && (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC))
8506 {
8507 Assert(pVM->hm.s.vmx.HCPhysApicAccess);
8508 RTGCPHYS GCPhysApicBase;
8509 GCPhysApicBase = pMixedCtx->msrApicBase;
8510 GCPhysApicBase &= PAGE_BASE_GC_MASK;
8511
8512 /* Unalias any existing mapping. */
8513 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
8514 AssertRCReturn(rc, rc);
8515
8516 /* Map the HC APIC-access page into the GC space, this also updates the shadow page tables if necessary. */
8517 Log4(("Mapped HC APIC-access page into GC: GCPhysApicBase=%#RGp\n", GCPhysApicBase));
8518 rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
8519 AssertRCReturn(rc, rc);
8520
8521 pVCpu->hm.s.vmx.u64MsrApicBase = pMixedCtx->msrApicBase;
8522 }
8523#endif /* !IEM_VERIFICATION_MODE_FULL */
8524
8525 if (TRPMHasTrap(pVCpu))
8526 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
8527 uint32_t uIntrState = hmR0VmxEvaluatePendingEvent(pVCpu, pMixedCtx);
8528
8529 /*
8530 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus needs to be done with
8531 * longjmps or interrupts + preemption enabled. Event injection might also result in triple-faulting the VM.
8532 */
8533 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx, uIntrState, fStepping);
8534 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8535 { /* likely */ }
8536 else
8537 {
8538 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8539 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8540 return rcStrict;
8541 }
8542
8543 /*
8544 * Load the guest state bits, we can handle longjmps/getting preempted here.
8545 *
8546 * If we are injecting events to a real-on-v86 mode guest, we will have to update
8547 * RIP and some segment registers, i.e. hmR0VmxInjectPendingEvent()->hmR0VmxInjectEventVmcs().
8548 * Hence, this needs to be done -after- injection of events.
8549 */
8550 rcStrict = hmR0VmxLoadGuestStateOptimal(pVM, pVCpu, pMixedCtx);
8551 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8552 { /* likely */ }
8553 else
8554 return rcStrict;
8555
8556 /*
8557 * No longjmps to ring-3 from this point on!!!
8558 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
8559 * This also disables flushing of the R0-logger instance (if any).
8560 */
8561 VMMRZCallRing3Disable(pVCpu);
8562
8563 /*
8564 * We disable interrupts so that we don't miss any interrupts that would flag preemption (IPI/timers etc.)
8565 * when thread-context hooks aren't used and we've been running with preemption disabled for a while.
8566 *
8567 * We need to check for force-flags that could've possible been altered since we last checked them (e.g.
8568 * by PDMGetInterrupt() leaving the PDM critical section, see @bugref{6398}).
8569 *
8570 * We also check a couple of other force-flags as a last opportunity to get the EMT back to ring-3 before
8571 * executing guest code.
8572 */
8573 pVmxTransient->fEFlags = ASMIntDisableFlags();
8574
8575 if ( ( !VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
8576 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
8577 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
8578 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
8579 {
8580 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
8581 {
8582 /* We've injected any pending events. This is really the point of no return (to ring-3). */
8583 pVCpu->hm.s.Event.fPending = false;
8584
8585 return VINF_SUCCESS;
8586 }
8587
8588 STAM_COUNTER_INC(&pVCpu->hm.s.StatPendingHostIrq);
8589 rcStrict = VINF_EM_RAW_INTERRUPT;
8590 }
8591 else
8592 {
8593 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
8594 rcStrict = VINF_EM_RAW_TO_R3;
8595 }
8596
8597 ASMSetFlags(pVmxTransient->fEFlags);
8598 VMMRZCallRing3Enable(pVCpu);
8599
8600 return rcStrict;
8601}
8602
8603
8604/**
8605 * Prepares to run guest code in VT-x and we've committed to doing so. This
8606 * means there is no backing out to ring-3 or anywhere else at this
8607 * point.
8608 *
8609 * @param pVM The cross context VM structure.
8610 * @param pVCpu The cross context virtual CPU structure.
8611 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8612 * out-of-sync. Make sure to update the required fields
8613 * before using them.
8614 * @param pVmxTransient Pointer to the VMX transient structure.
8615 *
8616 * @remarks Called with preemption disabled.
8617 * @remarks No-long-jump zone!!!
8618 */
8619static void hmR0VmxPreRunGuestCommitted(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8620{
8621 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8622 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8623 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8624
8625 /*
8626 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
8627 */
8628 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
8629 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
8630
8631#ifdef HMVMX_ALWAYS_SWAP_FPU_STATE
8632 if (!CPUMIsGuestFPUStateActive(pVCpu))
8633 CPUMR0LoadGuestFPU(pVM, pVCpu, pMixedCtx);
8634 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
8635#endif
8636
8637 if ( pVCpu->hm.s.fPreloadGuestFpu
8638 && !CPUMIsGuestFPUStateActive(pVCpu))
8639 {
8640 CPUMR0LoadGuestFPU(pVM, pVCpu, pMixedCtx);
8641 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
8642 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
8643 }
8644
8645 /*
8646 * Lazy-update of the host MSRs values in the auto-load/store MSR area.
8647 */
8648 if ( !pVCpu->hm.s.vmx.fUpdatedHostMsrs
8649 && pVCpu->hm.s.vmx.cMsrs > 0)
8650 {
8651 hmR0VmxUpdateAutoLoadStoreHostMsrs(pVCpu);
8652 }
8653
8654 /*
8655 * Load the host state bits as we may've been preempted (only happens when
8656 * thread-context hooks are used or when hmR0VmxSetupVMRunHandler() changes pfnStartVM).
8657 */
8658 /** @todo Why should hmR0VmxSetupVMRunHandler() changing pfnStartVM have
8659 * any effect to the host state needing to be saved? */
8660 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT))
8661 {
8662 /* This ASSUMES that pfnStartVM has been set up already. */
8663 int rc = hmR0VmxSaveHostState(pVM, pVCpu);
8664 AssertRC(rc);
8665 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreemptSaveHostState);
8666 }
8667 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT));
8668
8669 /*
8670 * Load the state shared between host and guest (FPU, debug, lazy MSRs).
8671 */
8672 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE))
8673 hmR0VmxLoadSharedState(pVM, pVCpu, pMixedCtx);
8674 AssertMsg(!HMCPU_CF_VALUE(pVCpu), ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8675
8676 /* Store status of the shared guest-host state at the time of VM-entry. */
8677#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
8678 if (CPUMIsGuestInLongModeEx(pMixedCtx))
8679 {
8680 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActivePending(pVCpu);
8681 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActivePending(pVCpu);
8682 }
8683 else
8684#endif
8685 {
8686 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
8687 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
8688 }
8689 pVmxTransient->fWasGuestFPUStateActive = CPUMIsGuestFPUStateActive(pVCpu);
8690
8691 /*
8692 * Cache the TPR-shadow for checking on every VM-exit if it might have changed.
8693 */
8694 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
8695 pVmxTransient->u8GuestTpr = pVCpu->hm.s.vmx.pbVirtApic[0x80];
8696
8697 PHMGLOBALCPUINFO pCpu = HMR0GetCurrentCpu();
8698 RTCPUID idCurrentCpu = pCpu->idCpu;
8699 if ( pVmxTransient->fUpdateTscOffsettingAndPreemptTimer
8700 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
8701 {
8702 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVM, pVCpu);
8703 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = false;
8704 }
8705
8706 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
8707 hmR0VmxFlushTaggedTlb(pVCpu, pCpu); /* Invalidate the appropriate guest entries from the TLB. */
8708 Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
8709 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Update the error reporting info. with the current host CPU. */
8710
8711 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
8712
8713 TMNotifyStartOfExecution(pVCpu); /* Finally, notify TM to resume its clocks as we're about
8714 to start executing. */
8715
8716 /*
8717 * Load the TSC_AUX MSR when we are not intercepting RDTSCP.
8718 */
8719 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP)
8720 {
8721 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
8722 {
8723 bool fMsrUpdated;
8724 int rc2 = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
8725 AssertRC(rc2);
8726 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS));
8727
8728 rc2 = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_TSC_AUX, CPUMR0GetGuestTscAux(pVCpu), true /* fUpdateHostMsr */,
8729 &fMsrUpdated);
8730 AssertRC(rc2);
8731 Assert(fMsrUpdated || pVCpu->hm.s.vmx.fUpdatedHostMsrs);
8732
8733 /* Finally, mark that all host MSR values are updated so we don't redo it without leaving VT-x. See @bugref{6956}. */
8734 pVCpu->hm.s.vmx.fUpdatedHostMsrs = true;
8735 }
8736 else
8737 {
8738 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, MSR_K8_TSC_AUX);
8739 Assert(!pVCpu->hm.s.vmx.cMsrs || pVCpu->hm.s.vmx.fUpdatedHostMsrs);
8740 }
8741 }
8742
8743#ifdef VBOX_STRICT
8744 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu);
8745 hmR0VmxCheckHostEferMsr(pVCpu);
8746 AssertRC(hmR0VmxCheckVmcsCtls(pVCpu));
8747#endif
8748#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
8749 uint32_t uInvalidReason = hmR0VmxCheckGuestState(pVM, pVCpu, pMixedCtx);
8750 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
8751 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
8752#endif
8753}
8754
8755
8756/**
8757 * Performs some essential restoration of state after running guest code in
8758 * VT-x.
8759 *
8760 * @param pVM The cross context VM structure.
8761 * @param pVCpu The cross context virtual CPU structure.
8762 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
8763 * out-of-sync. Make sure to update the required fields
8764 * before using them.
8765 * @param pVmxTransient Pointer to the VMX transient structure.
8766 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
8767 *
8768 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
8769 *
8770 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
8771 * unconditionally when it is safe to do so.
8772 */
8773static void hmR0VmxPostRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, int rcVMRun)
8774{
8775 NOREF(pVM);
8776
8777 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8778
8779 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
8780 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
8781 HMVMXCPU_GST_RESET_TO(pVCpu, 0); /* Exits/longjmps to ring-3 requires saving the guest state. */
8782 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
8783 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
8784 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
8785
8786 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
8787 TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVCpu->hm.s.vmx.u64TSCOffset);
8788
8789 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatExit1, x);
8790 TMNotifyEndOfExecution(pVCpu); /* Notify TM that the guest is no longer running. */
8791 Assert(!ASMIntAreEnabled());
8792 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
8793
8794#ifdef HMVMX_ALWAYS_SWAP_FPU_STATE
8795 if (CPUMIsGuestFPUStateActive(pVCpu))
8796 {
8797 hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
8798 CPUMR0SaveGuestFPU(pVM, pVCpu, pMixedCtx);
8799 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
8800 }
8801#endif
8802
8803#if HC_ARCH_BITS == 64
8804 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Host state messed up by VT-x, we must restore. */
8805#endif
8806 pVCpu->hm.s.vmx.uVmcsState |= HMVMX_VMCS_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
8807#ifdef VBOX_STRICT
8808 hmR0VmxCheckHostEferMsr(pVCpu); /* Verify that VMRUN/VMLAUNCH didn't modify host EFER. */
8809#endif
8810 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
8811 VMMRZCallRing3Enable(pVCpu); /* It is now safe to do longjmps to ring-3!!! */
8812
8813 /* Save the basic VM-exit reason. Refer Intel spec. 24.9.1 "Basic VM-exit Information". */
8814 uint32_t uExitReason;
8815 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8816 rc |= hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
8817 AssertRC(rc);
8818 pVmxTransient->uExitReason = (uint16_t)VMX_EXIT_REASON_BASIC(uExitReason);
8819 pVmxTransient->fVMEntryFailed = VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uEntryIntInfo);
8820
8821 /* Update the VM-exit history array. */
8822 HMCPU_EXIT_HISTORY_ADD(pVCpu, pVmxTransient->uExitReason);
8823
8824 /* If the VMLAUNCH/VMRESUME failed, we can bail out early. This does -not- cover VMX_EXIT_ERR_*. */
8825 if (RT_UNLIKELY(rcVMRun != VINF_SUCCESS))
8826 {
8827 Log4(("VM-entry failure: pVCpu=%p idCpu=%RU32 rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", pVCpu, pVCpu->idCpu, rcVMRun,
8828 pVmxTransient->fVMEntryFailed));
8829 return;
8830 }
8831
8832 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
8833 {
8834 /** @todo We can optimize this by only syncing with our force-flags when
8835 * really needed and keeping the VMCS state as it is for most
8836 * VM-exits. */
8837 /* Update the guest interruptibility-state from the VMCS. */
8838 hmR0VmxSaveGuestIntrState(pVCpu, pMixedCtx);
8839
8840#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
8841 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
8842 AssertRC(rc);
8843#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
8844 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
8845 AssertRC(rc);
8846#endif
8847
8848 /*
8849 * If the TPR was raised by the guest, it wouldn't cause a VM-exit immediately. Instead we sync the TPR lazily whenever
8850 * we eventually get a VM-exit for any reason. This maybe expensive as PDMApicSetTPR() can longjmp to ring-3 and which is
8851 * why it's done here as it's easier and no less efficient to deal with it here than making hmR0VmxSaveGuestState()
8852 * cope with longjmps safely (see VMCPU_FF_HM_UPDATE_CR3 handling).
8853 */
8854 if ( (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
8855 && pVmxTransient->u8GuestTpr != pVCpu->hm.s.vmx.pbVirtApic[0x80])
8856 {
8857 rc = PDMApicSetTPR(pVCpu, pVCpu->hm.s.vmx.pbVirtApic[0x80]);
8858 AssertRC(rc);
8859 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
8860 }
8861 }
8862}
8863
8864
8865/**
8866 * Runs the guest code using VT-x the normal way.
8867 *
8868 * @returns VBox status code.
8869 * @param pVM The cross context VM structure.
8870 * @param pVCpu The cross context virtual CPU structure.
8871 * @param pCtx Pointer to the guest-CPU context.
8872 *
8873 * @note Mostly the same as hmR0VmxRunGuestCodeStep().
8874 */
8875static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
8876{
8877 VMXTRANSIENT VmxTransient;
8878 VmxTransient.fUpdateTscOffsettingAndPreemptTimer = true;
8879 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
8880 uint32_t cLoops = 0;
8881
8882 for (;; cLoops++)
8883 {
8884 Assert(!HMR0SuspendPending());
8885 HMVMX_ASSERT_CPU_SAFE();
8886
8887 /* Preparatory work for running guest code, this may force us to return
8888 to ring-3. This bugger disables interrupts on VINF_SUCCESS! */
8889 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
8890 rcStrict = hmR0VmxPreRunGuest(pVM, pVCpu, pCtx, &VmxTransient, false /* fStepping */);
8891 if (rcStrict != VINF_SUCCESS)
8892 break;
8893
8894 hmR0VmxPreRunGuestCommitted(pVM, pVCpu, pCtx, &VmxTransient);
8895 int rcRun = hmR0VmxRunGuest(pVM, pVCpu, pCtx);
8896 /* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
8897
8898 /* Restore any residual host-state and save any bits shared between host
8899 and guest into the guest-CPU state. Re-enables interrupts! */
8900 hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, VBOXSTRICTRC_TODO(rcStrict));
8901
8902 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
8903 if (RT_SUCCESS(rcRun))
8904 { /* very likely */ }
8905 else
8906 {
8907 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
8908 hmR0VmxReportWorldSwitchError(pVM, pVCpu, rcRun, pCtx, &VmxTransient);
8909 return rcRun;
8910 }
8911
8912 /* Profile the VM-exit. */
8913 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
8914 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
8915 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
8916 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
8917 HMVMX_START_EXIT_DISPATCH_PROF();
8918
8919 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, pCtx, VmxTransient.uExitReason);
8920
8921 /* Handle the VM-exit. */
8922#ifdef HMVMX_USE_FUNCTION_TABLE
8923 rcStrict = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, pCtx, &VmxTransient);
8924#else
8925 rcStrict = hmR0VmxHandleExit(pVCpu, pCtx, &VmxTransient, VmxTransient.uExitReason);
8926#endif
8927 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
8928 if (rcStrict == VINF_SUCCESS)
8929 {
8930 if (cLoops <= pVM->hm.s.cMaxResumeLoops)
8931 continue; /* likely */
8932 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
8933 rcStrict = VINF_EM_RAW_INTERRUPT;
8934 }
8935 break;
8936 }
8937
8938 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
8939 return rcStrict;
8940}
8941
8942
8943
8944/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
8945 * probes.
8946 *
8947 * The following few functions and associated structure contains the bloat
8948 * necessary for providing detailed debug events and dtrace probes as well as
8949 * reliable host side single stepping. This works on the principle of
8950 * "subclassing" the normal execution loop and workers. We replace the loop
8951 * method completely and override selected helpers to add necessary adjustments
8952 * to their core operation.
8953 *
8954 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
8955 * any performance for debug and analysis features.
8956 *
8957 * @{
8958 */
8959
8960typedef struct VMXRUNDBGSTATE
8961{
8962 /** The RIP we started executing at. This is for detecting that we stepped. */
8963 uint64_t uRipStart;
8964 /** The CS we started executing with. */
8965 uint16_t uCsStart;
8966
8967 /** Whether we've actually modified the 1st execution control field. */
8968 bool fModifiedProcCtls : 1;
8969 /** Whether we've actually modified the 2nd execution control field. */
8970 bool fModifiedProcCtls2 : 1;
8971 /** Whether we've actually modified the exception bitmap. */
8972 bool fModifiedXcptBitmap : 1;
8973
8974 /** We desire the modified the CR0 mask to be cleared. */
8975 bool fClearCr0Mask : 1;
8976 /** We desire the modified the CR4 mask to be cleared. */
8977 bool fClearCr4Mask : 1;
8978 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
8979 uint32_t fCpe1Extra;
8980 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
8981 uint32_t fCpe1Unwanted;
8982 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
8983 uint32_t fCpe2Extra;
8984 /** Extra stuff we need in */
8985 uint32_t bmXcptExtra;
8986 /** The sequence number of the Dtrace provider settings the state was
8987 * configured against. */
8988 uint32_t uDtraceSettingsSeqNo;
8989 /** Exits to check (one bit per exit). */
8990 uint32_t bmExitsToCheck[3];
8991
8992 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
8993 uint32_t fProcCtlsInitial;
8994 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
8995 uint32_t fProcCtls2Initial;
8996 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
8997 uint32_t bmXcptInitial;
8998} VMXRUNDBGSTATE;
8999AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
9000typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
9001
9002
9003/**
9004 * Initializes the VMXRUNDBGSTATE structure.
9005 *
9006 * @param pVCpu The cross context virtual CPU structure of the
9007 * calling EMT.
9008 * @param pCtx The CPU register context to go with @a pVCpu.
9009 * @param pDbgState The structure to initialize.
9010 */
9011DECLINLINE(void) hmR0VmxRunDebugStateInit(PVMCPU pVCpu, PCCPUMCTX pCtx, PVMXRUNDBGSTATE pDbgState)
9012{
9013 pDbgState->uRipStart = pCtx->rip;
9014 pDbgState->uCsStart = pCtx->cs.Sel;
9015
9016 pDbgState->fModifiedProcCtls = false;
9017 pDbgState->fModifiedProcCtls2 = false;
9018 pDbgState->fModifiedXcptBitmap = false;
9019 pDbgState->fClearCr0Mask = false;
9020 pDbgState->fClearCr4Mask = false;
9021 pDbgState->fCpe1Extra = 0;
9022 pDbgState->fCpe1Unwanted = 0;
9023 pDbgState->fCpe2Extra = 0;
9024 pDbgState->bmXcptExtra = 0;
9025 pDbgState->fProcCtlsInitial = pVCpu->hm.s.vmx.u32ProcCtls;
9026 pDbgState->fProcCtls2Initial = pVCpu->hm.s.vmx.u32ProcCtls2;
9027 pDbgState->bmXcptInitial = pVCpu->hm.s.vmx.u32XcptBitmap;
9028}
9029
9030
9031/**
9032 * Updates the VMSC fields with changes requested by @a pDbgState.
9033 *
9034 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
9035 * immediately before executing guest code, i.e. when interrupts are disabled.
9036 * We don't check status codes here as we cannot easily assert or return in the
9037 * latter case.
9038 *
9039 * @param pVCpu The cross context virtual CPU structure.
9040 * @param pDbgState The debug state.
9041 */
9042DECLINLINE(void) hmR0VmxPreRunGuestDebugStateApply(PVMCPU pVCpu, PVMXRUNDBGSTATE pDbgState)
9043{
9044 /*
9045 * Ensure desired flags in VMCS control fields are set.
9046 * (Ignoring write failure here, as we're committed and it's just debug extras.)
9047 *
9048 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
9049 * there should be no stale data in pCtx at this point.
9050 */
9051 if ( (pVCpu->hm.s.vmx.u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
9052 || (pVCpu->hm.s.vmx.u32ProcCtls & pDbgState->fCpe1Unwanted))
9053 {
9054 pVCpu->hm.s.vmx.u32ProcCtls |= pDbgState->fCpe1Extra;
9055 pVCpu->hm.s.vmx.u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
9056 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
9057 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVCpu->hm.s.vmx.u32ProcCtls));
9058 pDbgState->fModifiedProcCtls = true;
9059 }
9060
9061 if ((pVCpu->hm.s.vmx.u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
9062 {
9063 pVCpu->hm.s.vmx.u32ProcCtls2 |= pDbgState->fCpe2Extra;
9064 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVCpu->hm.s.vmx.u32ProcCtls2);
9065 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVCpu->hm.s.vmx.u32ProcCtls2));
9066 pDbgState->fModifiedProcCtls2 = true;
9067 }
9068
9069 if ((pVCpu->hm.s.vmx.u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
9070 {
9071 pVCpu->hm.s.vmx.u32XcptBitmap |= pDbgState->bmXcptExtra;
9072 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
9073 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVCpu->hm.s.vmx.u32XcptBitmap));
9074 pDbgState->fModifiedXcptBitmap = true;
9075 }
9076
9077 if (pDbgState->fClearCr0Mask && pVCpu->hm.s.vmx.u32CR0Mask != 0)
9078 {
9079 pVCpu->hm.s.vmx.u32CR0Mask = 0;
9080 VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_MASK, 0);
9081 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS_CTRL_CR0_MASK: 0\n"));
9082 }
9083
9084 if (pDbgState->fClearCr4Mask && pVCpu->hm.s.vmx.u32CR4Mask != 0)
9085 {
9086 pVCpu->hm.s.vmx.u32CR4Mask = 0;
9087 VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_MASK, 0);
9088 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS_CTRL_CR4_MASK: 0\n"));
9089 }
9090}
9091
9092
9093DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugStateRevert(PVMCPU pVCpu, PVMXRUNDBGSTATE pDbgState, VBOXSTRICTRC rcStrict)
9094{
9095 /*
9096 * Restore exit control settings as we may not reenter this function the
9097 * next time around.
9098 */
9099 /* We reload the initial value, trigger what we can of recalculations the
9100 next time around. From the looks of things, that's all that's required atm. */
9101 if (pDbgState->fModifiedProcCtls)
9102 {
9103 if (!(pDbgState->fProcCtlsInitial & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
9104 pDbgState->fProcCtlsInitial |= VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
9105 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
9106 AssertRCReturn(rc2, rc2);
9107 pVCpu->hm.s.vmx.u32ProcCtls = pDbgState->fProcCtlsInitial;
9108 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0 | HM_CHANGED_GUEST_DEBUG);
9109 }
9110
9111 /* We're currently the only ones messing with this one, so just restore the
9112 cached value and reload the field. */
9113 if ( pDbgState->fModifiedProcCtls2
9114 && pVCpu->hm.s.vmx.u32ProcCtls2 != pDbgState->fProcCtls2Initial)
9115 {
9116 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
9117 AssertRCReturn(rc2, rc2);
9118 pVCpu->hm.s.vmx.u32ProcCtls2 = pDbgState->fProcCtls2Initial;
9119 }
9120
9121 /* If we've modified the exception bitmap, we restore it and trigger
9122 reloading and partial recalculation the next time around. */
9123 if (pDbgState->fModifiedXcptBitmap)
9124 {
9125 pVCpu->hm.s.vmx.u32XcptBitmap = pDbgState->bmXcptInitial;
9126 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS | HM_CHANGED_GUEST_CR0);
9127 }
9128
9129 /* We assume hmR0VmxLoadSharedCR0 will recalculate and load the CR0 mask. */
9130 if (pDbgState->fClearCr0Mask)
9131 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9132
9133 /* We assume hmR0VmxLoadGuestCR3AndCR4 will recalculate and load the CR4 mask. */
9134 if (pDbgState->fClearCr4Mask)
9135 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
9136
9137 return rcStrict;
9138}
9139
9140
9141/**
9142 * Configures VM-exit controls for current DBGF and DTrace settings.
9143 *
9144 * This updates @a pDbgState and the VMCS execution control fields to reflect
9145 * the necessary exits demanded by DBGF and DTrace.
9146 *
9147 * @param pVM The cross context VM structure.
9148 * @param pVCpu The cross context virtual CPU structure.
9149 * @param pCtx Pointer to the guest-CPU context.
9150 * @param pDbgState The debug state.
9151 * @param pVmxTransient Pointer to the VMX transient structure. May update
9152 * fUpdateTscOffsettingAndPreemptTimer.
9153 */
9154static void hmR0VmxPreRunGuestDebugStateUpdate(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx,
9155 PVMXRUNDBGSTATE pDbgState, PVMXTRANSIENT pVmxTransient)
9156{
9157 /*
9158 * Take down the dtrace serial number so we can spot changes.
9159 */
9160 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
9161 ASMCompilerBarrier();
9162
9163 /*
9164 * We'll rebuild most of the middle block of data members (holding the
9165 * current settings) as we go along here, so start by clearing it all.
9166 */
9167 pDbgState->bmXcptExtra = 0;
9168 pDbgState->fCpe1Extra = 0;
9169 pDbgState->fCpe1Unwanted = 0;
9170 pDbgState->fCpe2Extra = 0;
9171 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
9172 pDbgState->bmExitsToCheck[i] = 0;
9173
9174 /*
9175 * Software interrupts (INT XXh) - no idea how to trigger these...
9176 */
9177 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
9178 || VBOXVMM_INT_SOFTWARE_ENABLED())
9179 {
9180 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
9181 }
9182
9183 /*
9184 * Exception bitmap and XCPT events+probes.
9185 */
9186 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
9187 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
9188 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
9189
9190 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
9191 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
9192 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
9193 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
9194 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
9195 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
9196 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
9197 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
9198 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
9199 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
9200 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
9201 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
9202 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
9203 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
9204 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
9205 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
9206 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
9207 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
9208
9209 if (pDbgState->bmXcptExtra)
9210 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
9211
9212 /*
9213 * Process events and probes for VM exits, making sure we get the wanted exits.
9214 *
9215 * Note! This is the reverse of waft hmR0VmxHandleExitDtraceEvents does.
9216 * So, when adding/changing/removing please don't forget to update it.
9217 *
9218 * Some of the macros are picking up local variables to save horizontal space,
9219 * (being able to see it in a table is the lesser evil here).
9220 */
9221#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
9222 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
9223 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
9224#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
9225 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9226 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9227 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9228 } else do { } while (0)
9229#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
9230 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9231 { \
9232 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
9233 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9234 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9235 } else do { } while (0)
9236#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
9237 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9238 { \
9239 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
9240 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9241 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9242 } else do { } while (0)
9243#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
9244 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9245 { \
9246 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
9247 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9248 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9249 } else do { } while (0)
9250
9251 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
9252 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
9253 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
9254 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
9255 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
9256
9257 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
9258 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
9259 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
9260 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
9261 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT); /* paranoia */
9262 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
9263 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
9264 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
9265 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT);
9266 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
9267 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_VMCS_CTRL_PROC_EXEC_RDPMC_EXIT);
9268 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
9269 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT);
9270 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
9271 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
9272 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
9273 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
9274 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
9275 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
9276 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
9277 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
9278 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
9279 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
9280 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
9281 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
9282 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
9283 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
9284 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
9285 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
9286 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
9287 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
9288 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
9289 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
9290 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
9291 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
9292 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
9293
9294 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
9295 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
9296 {
9297 int rc2 = hmR0VmxSaveGuestCR0(pVCpu, pCtx);
9298 rc2 |= hmR0VmxSaveGuestCR4(pVCpu, pCtx);
9299 rc2 |= hmR0VmxSaveGuestApicState(pVCpu, pCtx);
9300 AssertRC(rc2);
9301
9302#if 0 /** @todo fix me */
9303 pDbgState->fClearCr0Mask = true;
9304 pDbgState->fClearCr4Mask = true;
9305#endif
9306 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
9307 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT | VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT;
9308 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
9309 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT | VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT;
9310 pDbgState->fCpe1Unwanted |= VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW; /* risky? */
9311 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
9312 require clearing here and in the loop if we start using it. */
9313 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
9314 }
9315 else
9316 {
9317 if (pDbgState->fClearCr0Mask)
9318 {
9319 pDbgState->fClearCr0Mask = false;
9320 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9321 }
9322 if (pDbgState->fClearCr4Mask)
9323 {
9324 pDbgState->fClearCr4Mask = false;
9325 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
9326 }
9327 }
9328 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
9329 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
9330
9331 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
9332 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
9333 {
9334 /** @todo later, need to fix handler as it assumes this won't usually happen. */
9335 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
9336 }
9337 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
9338 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
9339
9340 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS); /* risky clearing this? */
9341 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
9342 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS);
9343 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
9344 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_VMCS_CTRL_PROC_EXEC_MWAIT_EXIT); /* paranoia */
9345 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
9346 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_VMCS_CTRL_PROC_EXEC_MONITOR_EXIT); /* paranoia */
9347 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
9348#if 0 /** @todo too slow, fix handler. */
9349 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_VMCS_CTRL_PROC_EXEC_PAUSE_EXIT);
9350#endif
9351 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
9352
9353 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
9354 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
9355 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
9356 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
9357 {
9358 pDbgState->fCpe2Extra |= VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT;
9359 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XDTR_ACCESS);
9360 }
9361 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_XDTR_ACCESS);
9362 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_XDTR_ACCESS);
9363 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_XDTR_ACCESS);
9364 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_XDTR_ACCESS);
9365
9366 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
9367 || IS_EITHER_ENABLED(pVM, INSTR_STR)
9368 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
9369 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
9370 {
9371 pDbgState->fCpe2Extra |= VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT;
9372 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_TR_ACCESS);
9373 }
9374 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_TR_ACCESS);
9375 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_TR_ACCESS);
9376 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_TR_ACCESS);
9377 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_TR_ACCESS);
9378
9379 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
9380 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
9381 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT);
9382 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
9383 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
9384 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
9385 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT);
9386 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
9387 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
9388 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
9389 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT);
9390 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
9391 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT);
9392 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
9393 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
9394 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
9395 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_VMCS_CTRL_PROC_EXEC2_RDSEED_EXIT);
9396 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
9397 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
9398 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
9399 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
9400 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
9401
9402#undef IS_EITHER_ENABLED
9403#undef SET_ONLY_XBM_IF_EITHER_EN
9404#undef SET_CPE1_XBM_IF_EITHER_EN
9405#undef SET_CPEU_XBM_IF_EITHER_EN
9406#undef SET_CPE2_XBM_IF_EITHER_EN
9407
9408 /*
9409 * Sanitize the control stuff.
9410 */
9411 pDbgState->fCpe2Extra &= pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1;
9412 if (pDbgState->fCpe2Extra)
9413 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL;
9414 pDbgState->fCpe1Extra &= pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1;
9415 pDbgState->fCpe1Unwanted &= ~pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0;
9416 if (pVCpu->hm.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
9417 {
9418 pVCpu->hm.s.fDebugWantRdTscExit ^= true;
9419 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
9420 }
9421
9422 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
9423 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
9424 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
9425 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
9426}
9427
9428
9429/**
9430 * Fires off DBGF events and dtrace probes for an exit, when it's appropriate.
9431 *
9432 * The caller has checked exit against the VMXRUNDBGSTATE::bmExitsToCheck
9433 * bitmap. The caller has checked for NMIs already, so we don't have to do that
9434 * either.
9435 *
9436 * @returns Strict VBox status code (i.e. informational status codes too).
9437 * @param pVM The cross context VM structure.
9438 * @param pVCpu The cross context virtual CPU structure.
9439 * @param pMixedCtx Pointer to the guest-CPU context.
9440 * @param pVmxTransient Pointer to the VMX-transient structure.
9441 * @param uExitReason The VM-exit reason.
9442 *
9443 * @remarks The name of this function is displayed by dtrace, so keep it short
9444 * and to the point. No longer than 33 chars long, please.
9445 */
9446static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx,
9447 PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
9448{
9449 /*
9450 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
9451 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
9452 *
9453 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
9454 * does. Must add/change/remove both places. Same ordering, please.
9455 *
9456 * Added/removed events must also be reflected in the next section
9457 * where we dispatch dtrace events.
9458 */
9459 bool fDtrace1 = false;
9460 bool fDtrace2 = false;
9461 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
9462 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
9463 uint32_t uEventArg = 0;
9464#define SET_EXIT(a_EventSubName) \
9465 do { \
9466 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
9467 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
9468 } while (0)
9469#define SET_BOTH(a_EventSubName) \
9470 do { \
9471 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
9472 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
9473 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
9474 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
9475 } while (0)
9476 switch (uExitReason)
9477 {
9478 case VMX_EXIT_MTF:
9479 return hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient);
9480
9481 case VMX_EXIT_XCPT_OR_NMI:
9482 {
9483 uint8_t const idxVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
9484 switch (VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo))
9485 {
9486 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT:
9487 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT:
9488 case VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT:
9489 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
9490 {
9491 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uExitIntInfo))
9492 {
9493 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
9494 uEventArg = pVmxTransient->uExitIntErrorCode;
9495 }
9496 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
9497 switch (enmEvent1)
9498 {
9499 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
9500 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
9501 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
9502 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
9503 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
9504 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
9505 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
9506 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
9507 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
9508 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
9509 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
9510 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
9511 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
9512 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
9513 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
9514 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
9515 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
9516 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
9517 default: break;
9518 }
9519 }
9520 else
9521 AssertFailed();
9522 break;
9523
9524 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT:
9525 uEventArg = idxVector;
9526 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
9527 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
9528 break;
9529 }
9530 break;
9531 }
9532
9533 case VMX_EXIT_TRIPLE_FAULT:
9534 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
9535 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
9536 break;
9537 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
9538 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
9539 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
9540 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
9541 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
9542
9543 /* Instruction specific VM-exits: */
9544 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
9545 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
9546 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
9547 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
9548 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
9549 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
9550 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
9551 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
9552 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
9553 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
9554 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
9555 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
9556 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
9557 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
9558 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
9559 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
9560 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
9561 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
9562 case VMX_EXIT_MOV_CRX:
9563 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9564/** @todo r=bird: I feel these macros aren't very descriptive and needs to be at least 30 chars longer! ;-)
9565* Sensible abbreviations strongly recommended here because even with 130 columns this stuff get too wide! */
9566 if ( VMX_EXIT_QUALIFICATION_CRX_ACCESS(pVmxTransient->uExitQualification)
9567 == VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ)
9568 SET_BOTH(CRX_READ);
9569 else
9570 SET_BOTH(CRX_WRITE);
9571 uEventArg = VMX_EXIT_QUALIFICATION_CRX_REGISTER(pVmxTransient->uExitQualification);
9572 break;
9573 case VMX_EXIT_MOV_DRX:
9574 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9575 if ( VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification)
9576 == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_READ)
9577 SET_BOTH(DRX_READ);
9578 else
9579 SET_BOTH(DRX_WRITE);
9580 uEventArg = VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification);
9581 break;
9582 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
9583 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
9584 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
9585 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
9586 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
9587 case VMX_EXIT_XDTR_ACCESS:
9588 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
9589 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_XDTR_INSINFO_INSTR_ID))
9590 {
9591 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
9592 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
9593 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
9594 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
9595 }
9596 break;
9597
9598 case VMX_EXIT_TR_ACCESS:
9599 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
9600 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_YYTR_INSINFO_INSTR_ID))
9601 {
9602 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
9603 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
9604 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
9605 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
9606 }
9607 break;
9608
9609 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
9610 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
9611 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
9612 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
9613 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
9614 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
9615 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
9616 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
9617 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
9618 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
9619 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
9620
9621 /* Events that aren't relevant at this point. */
9622 case VMX_EXIT_EXT_INT:
9623 case VMX_EXIT_INT_WINDOW:
9624 case VMX_EXIT_NMI_WINDOW:
9625 case VMX_EXIT_TPR_BELOW_THRESHOLD:
9626 case VMX_EXIT_PREEMPT_TIMER:
9627 case VMX_EXIT_IO_INSTR:
9628 break;
9629
9630 /* Errors and unexpected events. */
9631 case VMX_EXIT_INIT_SIGNAL:
9632 case VMX_EXIT_SIPI:
9633 case VMX_EXIT_IO_SMI:
9634 case VMX_EXIT_SMI:
9635 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
9636 case VMX_EXIT_ERR_MSR_LOAD:
9637 case VMX_EXIT_ERR_MACHINE_CHECK:
9638 break;
9639
9640 default:
9641 AssertMsgFailed(("Unexpected exit=%#x\n", uExitReason));
9642 break;
9643 }
9644#undef SET_BOTH
9645#undef SET_EXIT
9646
9647 /*
9648 * Dtrace tracepoints go first. We do them here at once so we don't
9649 * have to copy the guest state saving and stuff a few dozen times.
9650 * Down side is that we've got to repeat the switch, though this time
9651 * we use enmEvent since the probes are a subset of what DBGF does.
9652 */
9653 if (fDtrace1 || fDtrace2)
9654 {
9655 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9656 hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
9657 switch (enmEvent1)
9658 {
9659 /** @todo consider which extra parameters would be helpful for each probe. */
9660 case DBGFEVENT_END: break;
9661 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pMixedCtx); break;
9662 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pMixedCtx, pMixedCtx->dr[6]); break;
9663 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pMixedCtx); break;
9664 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pMixedCtx); break;
9665 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pMixedCtx); break;
9666 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pMixedCtx); break;
9667 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pMixedCtx); break;
9668 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pMixedCtx); break;
9669 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pMixedCtx, uEventArg); break;
9670 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pMixedCtx, uEventArg); break;
9671 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pMixedCtx, uEventArg); break;
9672 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pMixedCtx, uEventArg); break;
9673 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pMixedCtx, uEventArg, pMixedCtx->cr2); break;
9674 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pMixedCtx); break;
9675 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pMixedCtx); break;
9676 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pMixedCtx); break;
9677 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pMixedCtx); break;
9678 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pMixedCtx, uEventArg); break;
9679 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9680 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pMixedCtx, pMixedCtx->eax, pMixedCtx->ecx); break;
9681 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pMixedCtx); break;
9682 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pMixedCtx); break;
9683 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pMixedCtx); break;
9684 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pMixedCtx); break;
9685 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pMixedCtx); break;
9686 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pMixedCtx); break;
9687 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pMixedCtx); break;
9688 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9689 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9690 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9691 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9692 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pMixedCtx, pMixedCtx->ecx); break;
9693 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pMixedCtx, pMixedCtx->ecx,
9694 RT_MAKE_U64(pMixedCtx->eax, pMixedCtx->edx)); break;
9695 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pMixedCtx); break;
9696 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pMixedCtx); break;
9697 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pMixedCtx); break;
9698 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pMixedCtx); break;
9699 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pMixedCtx); break;
9700 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pMixedCtx); break;
9701 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pMixedCtx); break;
9702 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pMixedCtx); break;
9703 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pMixedCtx); break;
9704 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pMixedCtx); break;
9705 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pMixedCtx); break;
9706 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pMixedCtx); break;
9707 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pMixedCtx); break;
9708 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pMixedCtx); break;
9709 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pMixedCtx); break;
9710 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pMixedCtx); break;
9711 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pMixedCtx); break;
9712 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pMixedCtx); break;
9713 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pMixedCtx); break;
9714 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pMixedCtx); break;
9715 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pMixedCtx); break;
9716 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pMixedCtx); break;
9717 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pMixedCtx); break;
9718 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pMixedCtx); break;
9719 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pMixedCtx); break;
9720 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pMixedCtx); break;
9721 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pMixedCtx); break;
9722 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pMixedCtx); break;
9723 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pMixedCtx); break;
9724 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pMixedCtx); break;
9725 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pMixedCtx); break;
9726 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pMixedCtx); break;
9727 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
9728 }
9729 switch (enmEvent2)
9730 {
9731 /** @todo consider which extra parameters would be helpful for each probe. */
9732 case DBGFEVENT_END: break;
9733 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pMixedCtx); break;
9734 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pMixedCtx, pMixedCtx->eax, pMixedCtx->ecx); break;
9735 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pMixedCtx); break;
9736 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pMixedCtx); break;
9737 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pMixedCtx); break;
9738 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pMixedCtx); break;
9739 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pMixedCtx); break;
9740 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pMixedCtx); break;
9741 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pMixedCtx); break;
9742 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9743 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9744 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9745 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
9746 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pMixedCtx, pMixedCtx->ecx); break;
9747 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pMixedCtx, pMixedCtx->ecx,
9748 RT_MAKE_U64(pMixedCtx->eax, pMixedCtx->edx)); break;
9749 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pMixedCtx); break;
9750 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pMixedCtx); break;
9751 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pMixedCtx); break;
9752 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pMixedCtx); break;
9753 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pMixedCtx); break;
9754 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pMixedCtx); break;
9755 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pMixedCtx); break;
9756 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pMixedCtx); break;
9757 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pMixedCtx); break;
9758 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pMixedCtx); break;
9759 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pMixedCtx); break;
9760 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pMixedCtx); break;
9761 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pMixedCtx); break;
9762 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pMixedCtx); break;
9763 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pMixedCtx); break;
9764 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pMixedCtx); break;
9765 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pMixedCtx); break;
9766 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pMixedCtx); break;
9767 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pMixedCtx); break;
9768 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pMixedCtx); break;
9769 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pMixedCtx); break;
9770 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pMixedCtx); break;
9771 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pMixedCtx); break;
9772 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pMixedCtx); break;
9773 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pMixedCtx); break;
9774 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pMixedCtx); break;
9775 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pMixedCtx); break;
9776 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pMixedCtx); break;
9777 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pMixedCtx); break;
9778 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pMixedCtx); break;
9779 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pMixedCtx); break;
9780 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pMixedCtx); break;
9781 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pMixedCtx); break;
9782 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pMixedCtx); break;
9783 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pMixedCtx); break;
9784 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pMixedCtx); break;
9785 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
9786 }
9787 }
9788
9789 /*
9790 * Fire of the DBGF event, if enabled (our check here is just a quick one,
9791 * the DBGF call will do a full check).
9792 *
9793 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
9794 * Note! If we have to events, we prioritize the first, i.e. the instruction
9795 * one, in order to avoid event nesting.
9796 */
9797 if ( enmEvent1 != DBGFEVENT_END
9798 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
9799 {
9800 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArg(pVM, pVCpu, enmEvent1, uEventArg, DBGFEVENTCTX_HM);
9801 if (rcStrict != VINF_SUCCESS)
9802 return rcStrict;
9803 }
9804 else if ( enmEvent2 != DBGFEVENT_END
9805 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
9806 {
9807 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArg(pVM, pVCpu, enmEvent2, uEventArg, DBGFEVENTCTX_HM);
9808 if (rcStrict != VINF_SUCCESS)
9809 return rcStrict;
9810 }
9811
9812 return VINF_SUCCESS;
9813}
9814
9815
9816/**
9817 * Single-stepping VM-exit filtering.
9818 *
9819 * This is preprocessing the exits and deciding whether we've gotten far enough
9820 * to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit handling is
9821 * performed.
9822 *
9823 * @returns Strict VBox status code (i.e. informational status codes too).
9824 * @param pVM The cross context VM structure.
9825 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
9826 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
9827 * out-of-sync. Make sure to update the required
9828 * fields before using them.
9829 * @param pVmxTransient Pointer to the VMX-transient structure.
9830 * @param uExitReason The VM-exit reason.
9831 * @param pDbgState The debug state.
9832 */
9833DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient,
9834 uint32_t uExitReason, PVMXRUNDBGSTATE pDbgState)
9835{
9836 /*
9837 * Expensive (saves context) generic dtrace exit probe.
9838 */
9839 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
9840 { /* more likely */ }
9841 else
9842 {
9843 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9844 hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
9845 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, pMixedCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQualification);
9846 }
9847
9848 /*
9849 * Check for host NMI, just to get that out of the way.
9850 */
9851 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
9852 { /* normally likely */ }
9853 else
9854 {
9855 int rc2 = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
9856 AssertRCReturn(rc2, rc2);
9857 uint32_t uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo);
9858 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
9859 return hmR0VmxExitXcptOrNmi(pVCpu, pMixedCtx, pVmxTransient);
9860 }
9861
9862 /*
9863 * Check for single stepping event if we're stepping.
9864 */
9865 if (pVCpu->hm.s.fSingleInstruction)
9866 {
9867 switch (uExitReason)
9868 {
9869 case VMX_EXIT_MTF:
9870 return hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient);
9871
9872 /* Various events: */
9873 case VMX_EXIT_XCPT_OR_NMI:
9874 case VMX_EXIT_EXT_INT:
9875 case VMX_EXIT_TRIPLE_FAULT:
9876 case VMX_EXIT_INT_WINDOW:
9877 case VMX_EXIT_NMI_WINDOW:
9878 case VMX_EXIT_TASK_SWITCH:
9879 case VMX_EXIT_TPR_BELOW_THRESHOLD:
9880 case VMX_EXIT_APIC_ACCESS:
9881 case VMX_EXIT_EPT_VIOLATION:
9882 case VMX_EXIT_EPT_MISCONFIG:
9883 case VMX_EXIT_PREEMPT_TIMER:
9884
9885 /* Instruction specific VM-exits: */
9886 case VMX_EXIT_CPUID:
9887 case VMX_EXIT_GETSEC:
9888 case VMX_EXIT_HLT:
9889 case VMX_EXIT_INVD:
9890 case VMX_EXIT_INVLPG:
9891 case VMX_EXIT_RDPMC:
9892 case VMX_EXIT_RDTSC:
9893 case VMX_EXIT_RSM:
9894 case VMX_EXIT_VMCALL:
9895 case VMX_EXIT_VMCLEAR:
9896 case VMX_EXIT_VMLAUNCH:
9897 case VMX_EXIT_VMPTRLD:
9898 case VMX_EXIT_VMPTRST:
9899 case VMX_EXIT_VMREAD:
9900 case VMX_EXIT_VMRESUME:
9901 case VMX_EXIT_VMWRITE:
9902 case VMX_EXIT_VMXOFF:
9903 case VMX_EXIT_VMXON:
9904 case VMX_EXIT_MOV_CRX:
9905 case VMX_EXIT_MOV_DRX:
9906 case VMX_EXIT_IO_INSTR:
9907 case VMX_EXIT_RDMSR:
9908 case VMX_EXIT_WRMSR:
9909 case VMX_EXIT_MWAIT:
9910 case VMX_EXIT_MONITOR:
9911 case VMX_EXIT_PAUSE:
9912 case VMX_EXIT_XDTR_ACCESS:
9913 case VMX_EXIT_TR_ACCESS:
9914 case VMX_EXIT_INVEPT:
9915 case VMX_EXIT_RDTSCP:
9916 case VMX_EXIT_INVVPID:
9917 case VMX_EXIT_WBINVD:
9918 case VMX_EXIT_XSETBV:
9919 case VMX_EXIT_RDRAND:
9920 case VMX_EXIT_INVPCID:
9921 case VMX_EXIT_VMFUNC:
9922 case VMX_EXIT_RDSEED:
9923 case VMX_EXIT_XSAVES:
9924 case VMX_EXIT_XRSTORS:
9925 {
9926 int rc2 = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
9927 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
9928 AssertRCReturn(rc2, rc2);
9929 if ( pMixedCtx->rip != pDbgState->uRipStart
9930 || pMixedCtx->cs.Sel != pDbgState->uCsStart)
9931 return VINF_EM_DBG_STEPPED;
9932 break;
9933 }
9934
9935 /* Errors and unexpected events: */
9936 case VMX_EXIT_INIT_SIGNAL:
9937 case VMX_EXIT_SIPI:
9938 case VMX_EXIT_IO_SMI:
9939 case VMX_EXIT_SMI:
9940 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
9941 case VMX_EXIT_ERR_MSR_LOAD:
9942 case VMX_EXIT_ERR_MACHINE_CHECK:
9943 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
9944 break;
9945
9946 default:
9947 AssertMsgFailed(("Unexpected exit=%#x\n", uExitReason));
9948 break;
9949 }
9950 }
9951
9952 /*
9953 * Check for debugger event breakpoints and dtrace probes.
9954 */
9955 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
9956 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
9957 {
9958 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVM, pVCpu, pMixedCtx, pVmxTransient, uExitReason);
9959 if (rcStrict != VINF_SUCCESS)
9960 return rcStrict;
9961 }
9962
9963 /*
9964 * Normal processing.
9965 */
9966#ifdef HMVMX_USE_FUNCTION_TABLE
9967 return g_apfnVMExitHandlers[uExitReason](pVCpu, pMixedCtx, pVmxTransient);
9968#else
9969 return hmR0VmxHandleExit(pVCpu, pMixedCtx, pVmxTransient, uExitReason);
9970#endif
9971}
9972
9973
9974/**
9975 * Single steps guest code using VT-x.
9976 *
9977 * @returns Strict VBox status code (i.e. informational status codes too).
9978 * @param pVM The cross context VM structure.
9979 * @param pVCpu The cross context virtual CPU structure.
9980 * @param pCtx Pointer to the guest-CPU context.
9981 *
9982 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
9983 */
9984static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
9985{
9986 VMXTRANSIENT VmxTransient;
9987 VmxTransient.fUpdateTscOffsettingAndPreemptTimer = true;
9988
9989 /* Set HMCPU indicators. */
9990 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
9991 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
9992 pVCpu->hm.s.fDebugWantRdTscExit = false;
9993 pVCpu->hm.s.fUsingDebugLoop = true;
9994
9995 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
9996 VMXRUNDBGSTATE DbgState;
9997 hmR0VmxRunDebugStateInit(pVCpu, pCtx, &DbgState);
9998 hmR0VmxPreRunGuestDebugStateUpdate(pVM, pVCpu, pCtx, &DbgState, &VmxTransient);
9999
10000 /*
10001 * The loop.
10002 */
10003 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10004 for (uint32_t cLoops = 0; ; cLoops++)
10005 {
10006 Assert(!HMR0SuspendPending());
10007 HMVMX_ASSERT_CPU_SAFE();
10008 bool fStepping = pVCpu->hm.s.fSingleInstruction;
10009
10010 /*
10011 * Preparatory work for running guest code, this may force us to return
10012 * to ring-3. This bugger disables interrupts on VINF_SUCCESS!
10013 */
10014 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10015 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &DbgState); /* Set up execute controls the next to can respond to. */
10016 rcStrict = hmR0VmxPreRunGuest(pVM, pVCpu, pCtx, &VmxTransient, fStepping);
10017 if (rcStrict != VINF_SUCCESS)
10018 break;
10019
10020 hmR0VmxPreRunGuestCommitted(pVM, pVCpu, pCtx, &VmxTransient);
10021 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &DbgState); /* Override any obnoxious code in the above two calls. */
10022
10023 /*
10024 * Now we can run the guest code.
10025 */
10026 int rcRun = hmR0VmxRunGuest(pVM, pVCpu, pCtx);
10027
10028 /* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
10029
10030 /*
10031 * Restore any residual host-state and save any bits shared between host
10032 * and guest into the guest-CPU state. Re-enables interrupts!
10033 */
10034 hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, VBOXSTRICTRC_TODO(rcStrict));
10035
10036 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
10037 if (RT_SUCCESS(rcRun))
10038 { /* very likely */ }
10039 else
10040 {
10041 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
10042 hmR0VmxReportWorldSwitchError(pVM, pVCpu, rcRun, pCtx, &VmxTransient);
10043 return rcRun;
10044 }
10045
10046 /* Profile the VM-exit. */
10047 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10048 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10049 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10050 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
10051 HMVMX_START_EXIT_DISPATCH_PROF();
10052
10053 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, pCtx, VmxTransient.uExitReason);
10054
10055 /*
10056 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
10057 */
10058 rcStrict = hmR0VmxRunDebugHandleExit(pVM, pVCpu, pCtx, &VmxTransient, VmxTransient.uExitReason, &DbgState);
10059 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
10060 if (rcStrict != VINF_SUCCESS)
10061 break;
10062 if (cLoops > pVM->hm.s.cMaxResumeLoops)
10063 {
10064 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10065 rcStrict = VINF_EM_RAW_INTERRUPT;
10066 break;
10067 }
10068
10069 /*
10070 * Stepping: Did the RIP change, if so, consider it a single step.
10071 * Otherwise, make sure one of the TFs gets set.
10072 */
10073 if (fStepping)
10074 {
10075 int rc2 = hmR0VmxSaveGuestRip(pVCpu, pCtx);
10076 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pCtx);
10077 AssertRCReturn(rc2, rc2);
10078 if ( pCtx->rip != DbgState.uRipStart
10079 || pCtx->cs.Sel != DbgState.uCsStart)
10080 {
10081 rcStrict = VINF_EM_DBG_STEPPED;
10082 break;
10083 }
10084 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
10085 }
10086
10087 /*
10088 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
10089 */
10090 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
10091 hmR0VmxPreRunGuestDebugStateUpdate(pVM, pVCpu, pCtx, &DbgState, &VmxTransient);
10092 }
10093
10094 /*
10095 * Clear the X86_EFL_TF if necessary.
10096 */
10097 if (pVCpu->hm.s.fClearTrapFlag)
10098 {
10099 int rc2 = hmR0VmxSaveGuestRflags(pVCpu, pCtx);
10100 AssertRCReturn(rc2, rc2);
10101 pVCpu->hm.s.fClearTrapFlag = false;
10102 pCtx->eflags.Bits.u1TF = 0;
10103 }
10104 /** @todo there seems to be issues with the resume flag when the monitor trap
10105 * flag is pending without being used. Seen early in bios init when
10106 * accessing APIC page in protected mode. */
10107
10108 /*
10109 * Restore VM-exit control settings as we may not reenter this function the
10110 * next time around.
10111 */
10112 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &DbgState, rcStrict);
10113
10114 /* Restore HMCPU indicators. */
10115 pVCpu->hm.s.fUsingDebugLoop = false;
10116 pVCpu->hm.s.fDebugWantRdTscExit = false;
10117 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
10118
10119 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10120 return rcStrict;
10121}
10122
10123
10124/** @} */
10125
10126
10127/**
10128 * Checks if any expensive dtrace probes are enabled and we should go to the
10129 * debug loop.
10130 *
10131 * @returns true if we should use debug loop, false if not.
10132 */
10133static bool hmR0VmxAnyExpensiveProbesEnabled(void)
10134{
10135 /* It's probably faster to OR the raw 32-bit counter variables together.
10136 Since the variables are in an array and the probes are next to one
10137 another (more or less), we have good locality. So, better read
10138 eight-nine cache lines ever time and only have one conditional, than
10139 128+ conditionals, right? */
10140 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
10141 | VBOXVMM_XCPT_DE_ENABLED_RAW()
10142 | VBOXVMM_XCPT_DB_ENABLED_RAW()
10143 | VBOXVMM_XCPT_BP_ENABLED_RAW()
10144 | VBOXVMM_XCPT_OF_ENABLED_RAW()
10145 | VBOXVMM_XCPT_BR_ENABLED_RAW()
10146 | VBOXVMM_XCPT_UD_ENABLED_RAW()
10147 | VBOXVMM_XCPT_NM_ENABLED_RAW()
10148 | VBOXVMM_XCPT_DF_ENABLED_RAW()
10149 | VBOXVMM_XCPT_TS_ENABLED_RAW()
10150 | VBOXVMM_XCPT_NP_ENABLED_RAW()
10151 | VBOXVMM_XCPT_SS_ENABLED_RAW()
10152 | VBOXVMM_XCPT_GP_ENABLED_RAW()
10153 | VBOXVMM_XCPT_PF_ENABLED_RAW()
10154 | VBOXVMM_XCPT_MF_ENABLED_RAW()
10155 | VBOXVMM_XCPT_AC_ENABLED_RAW()
10156 | VBOXVMM_XCPT_XF_ENABLED_RAW()
10157 | VBOXVMM_XCPT_VE_ENABLED_RAW()
10158 | VBOXVMM_XCPT_SX_ENABLED_RAW()
10159 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
10160 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
10161 ) != 0
10162 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
10163 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
10164 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
10165 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
10166 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
10167 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
10168 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
10169 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
10170 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
10171 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
10172 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
10173 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
10174 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
10175 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
10176 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
10177 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
10178 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
10179 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
10180 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
10181 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
10182 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
10183 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
10184 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
10185 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
10186 | VBOXVMM_INSTR_STR_ENABLED_RAW()
10187 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
10188 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
10189 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
10190 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
10191 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
10192 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
10193 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
10194 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
10195 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
10196 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
10197 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
10198 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
10199 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
10200 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
10201 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
10202 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
10203 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
10204 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
10205 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
10206 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
10207 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
10208 ) != 0
10209 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
10210 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
10211 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
10212 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
10213 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
10214 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
10215 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
10216 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
10217 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
10218 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
10219 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
10220 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
10221 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
10222 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
10223 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
10224 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
10225 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
10226 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
10227 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
10228 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
10229 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
10230 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
10231 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
10232 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
10233 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
10234 | VBOXVMM_EXIT_STR_ENABLED_RAW()
10235 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
10236 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
10237 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
10238 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
10239 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
10240 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
10241 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
10242 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
10243 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
10244 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
10245 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
10246 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
10247 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
10248 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
10249 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
10250 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
10251 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
10252 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
10253 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
10254 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
10255 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
10256 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
10257 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
10258 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
10259 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
10260 ) != 0;
10261}
10262
10263
10264/**
10265 * Runs the guest code using VT-x.
10266 *
10267 * @returns Strict VBox status code (i.e. informational status codes too).
10268 * @param pVM The cross context VM structure.
10269 * @param pVCpu The cross context virtual CPU structure.
10270 * @param pCtx Pointer to the guest-CPU context.
10271 */
10272VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10273{
10274 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10275 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
10276 HMVMX_ASSERT_PREEMPT_SAFE();
10277
10278 VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pCtx);
10279
10280 VBOXSTRICTRC rcStrict;
10281 if ( !pVCpu->hm.s.fUseDebugLoop
10282 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
10283 && !DBGFIsStepping(pVCpu) )
10284 rcStrict = hmR0VmxRunGuestCodeNormal(pVM, pVCpu, pCtx);
10285 else
10286 rcStrict = hmR0VmxRunGuestCodeDebug(pVM, pVCpu, pCtx);
10287
10288 if (rcStrict == VERR_EM_INTERPRETER)
10289 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
10290 else if (rcStrict == VINF_EM_RESET)
10291 rcStrict = VINF_EM_TRIPLE_FAULT;
10292
10293 int rc2 = hmR0VmxExitToRing3(pVM, pVCpu, pCtx, rcStrict);
10294 if (RT_FAILURE(rc2))
10295 {
10296 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
10297 rcStrict = rc2;
10298 }
10299 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
10300 return rcStrict;
10301}
10302
10303
10304#ifndef HMVMX_USE_FUNCTION_TABLE
10305DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason)
10306{
10307# ifdef DEBUG_ramshankar
10308# define RETURN_EXIT_CALL(a_CallExpr) \
10309 do { \
10310 int rc2 = hmR0VmxSaveGuestState(pVCpu, pMixedCtx); AssertRC(rc2); \
10311 VBOXSTRICTRC rcStrict = a_CallExpr; \
10312 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST); \
10313 return rcStrict; \
10314 } while (0)
10315# else
10316# define RETURN_EXIT_CALL(a_CallExpr) return a_CallExpr
10317# endif
10318 switch (rcReason)
10319 {
10320 case VMX_EXIT_EPT_MISCONFIG: RETURN_EXIT_CALL(hmR0VmxExitEptMisconfig(pVCpu, pMixedCtx, pVmxTransient));
10321 case VMX_EXIT_EPT_VIOLATION: RETURN_EXIT_CALL(hmR0VmxExitEptViolation(pVCpu, pMixedCtx, pVmxTransient));
10322 case VMX_EXIT_IO_INSTR: RETURN_EXIT_CALL(hmR0VmxExitIoInstr(pVCpu, pMixedCtx, pVmxTransient));
10323 case VMX_EXIT_CPUID: RETURN_EXIT_CALL(hmR0VmxExitCpuid(pVCpu, pMixedCtx, pVmxTransient));
10324 case VMX_EXIT_RDTSC: RETURN_EXIT_CALL(hmR0VmxExitRdtsc(pVCpu, pMixedCtx, pVmxTransient));
10325 case VMX_EXIT_RDTSCP: RETURN_EXIT_CALL(hmR0VmxExitRdtscp(pVCpu, pMixedCtx, pVmxTransient));
10326 case VMX_EXIT_APIC_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitApicAccess(pVCpu, pMixedCtx, pVmxTransient));
10327 case VMX_EXIT_XCPT_OR_NMI: RETURN_EXIT_CALL(hmR0VmxExitXcptOrNmi(pVCpu, pMixedCtx, pVmxTransient));
10328 case VMX_EXIT_MOV_CRX: RETURN_EXIT_CALL(hmR0VmxExitMovCRx(pVCpu, pMixedCtx, pVmxTransient));
10329 case VMX_EXIT_EXT_INT: RETURN_EXIT_CALL(hmR0VmxExitExtInt(pVCpu, pMixedCtx, pVmxTransient));
10330 case VMX_EXIT_INT_WINDOW: RETURN_EXIT_CALL(hmR0VmxExitIntWindow(pVCpu, pMixedCtx, pVmxTransient));
10331 case VMX_EXIT_MWAIT: RETURN_EXIT_CALL(hmR0VmxExitMwait(pVCpu, pMixedCtx, pVmxTransient));
10332 case VMX_EXIT_MONITOR: RETURN_EXIT_CALL(hmR0VmxExitMonitor(pVCpu, pMixedCtx, pVmxTransient));
10333 case VMX_EXIT_TASK_SWITCH: RETURN_EXIT_CALL(hmR0VmxExitTaskSwitch(pVCpu, pMixedCtx, pVmxTransient));
10334 case VMX_EXIT_PREEMPT_TIMER: RETURN_EXIT_CALL(hmR0VmxExitPreemptTimer(pVCpu, pMixedCtx, pVmxTransient));
10335 case VMX_EXIT_RDMSR: RETURN_EXIT_CALL(hmR0VmxExitRdmsr(pVCpu, pMixedCtx, pVmxTransient));
10336 case VMX_EXIT_WRMSR: RETURN_EXIT_CALL(hmR0VmxExitWrmsr(pVCpu, pMixedCtx, pVmxTransient));
10337 case VMX_EXIT_MOV_DRX: RETURN_EXIT_CALL(hmR0VmxExitMovDRx(pVCpu, pMixedCtx, pVmxTransient));
10338 case VMX_EXIT_TPR_BELOW_THRESHOLD: RETURN_EXIT_CALL(hmR0VmxExitTprBelowThreshold(pVCpu, pMixedCtx, pVmxTransient));
10339 case VMX_EXIT_HLT: RETURN_EXIT_CALL(hmR0VmxExitHlt(pVCpu, pMixedCtx, pVmxTransient));
10340 case VMX_EXIT_INVD: RETURN_EXIT_CALL(hmR0VmxExitInvd(pVCpu, pMixedCtx, pVmxTransient));
10341 case VMX_EXIT_INVLPG: RETURN_EXIT_CALL(hmR0VmxExitInvlpg(pVCpu, pMixedCtx, pVmxTransient));
10342 case VMX_EXIT_RSM: RETURN_EXIT_CALL(hmR0VmxExitRsm(pVCpu, pMixedCtx, pVmxTransient));
10343 case VMX_EXIT_MTF: RETURN_EXIT_CALL(hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient));
10344 case VMX_EXIT_PAUSE: RETURN_EXIT_CALL(hmR0VmxExitPause(pVCpu, pMixedCtx, pVmxTransient));
10345 case VMX_EXIT_XDTR_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient));
10346 case VMX_EXIT_TR_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient));
10347 case VMX_EXIT_WBINVD: RETURN_EXIT_CALL(hmR0VmxExitWbinvd(pVCpu, pMixedCtx, pVmxTransient));
10348 case VMX_EXIT_XSETBV: RETURN_EXIT_CALL(hmR0VmxExitXsetbv(pVCpu, pMixedCtx, pVmxTransient));
10349 case VMX_EXIT_RDRAND: RETURN_EXIT_CALL(hmR0VmxExitRdrand(pVCpu, pMixedCtx, pVmxTransient));
10350 case VMX_EXIT_INVPCID: RETURN_EXIT_CALL(hmR0VmxExitInvpcid(pVCpu, pMixedCtx, pVmxTransient));
10351 case VMX_EXIT_GETSEC: RETURN_EXIT_CALL(hmR0VmxExitGetsec(pVCpu, pMixedCtx, pVmxTransient));
10352 case VMX_EXIT_RDPMC: RETURN_EXIT_CALL(hmR0VmxExitRdpmc(pVCpu, pMixedCtx, pVmxTransient));
10353 case VMX_EXIT_VMCALL: RETURN_EXIT_CALL(hmR0VmxExitVmcall(pVCpu, pMixedCtx, pVmxTransient));
10354
10355 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pMixedCtx, pVmxTransient);
10356 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pMixedCtx, pVmxTransient);
10357 case VMX_EXIT_INIT_SIGNAL: return hmR0VmxExitInitSignal(pVCpu, pMixedCtx, pVmxTransient);
10358 case VMX_EXIT_SIPI: return hmR0VmxExitSipi(pVCpu, pMixedCtx, pVmxTransient);
10359 case VMX_EXIT_IO_SMI: return hmR0VmxExitIoSmi(pVCpu, pMixedCtx, pVmxTransient);
10360 case VMX_EXIT_SMI: return hmR0VmxExitSmi(pVCpu, pMixedCtx, pVmxTransient);
10361 case VMX_EXIT_ERR_MSR_LOAD: return hmR0VmxExitErrMsrLoad(pVCpu, pMixedCtx, pVmxTransient);
10362 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pMixedCtx, pVmxTransient);
10363 case VMX_EXIT_ERR_MACHINE_CHECK: return hmR0VmxExitErrMachineCheck(pVCpu, pMixedCtx, pVmxTransient);
10364
10365 case VMX_EXIT_VMCLEAR:
10366 case VMX_EXIT_VMLAUNCH:
10367 case VMX_EXIT_VMPTRLD:
10368 case VMX_EXIT_VMPTRST:
10369 case VMX_EXIT_VMREAD:
10370 case VMX_EXIT_VMRESUME:
10371 case VMX_EXIT_VMWRITE:
10372 case VMX_EXIT_VMXOFF:
10373 case VMX_EXIT_VMXON:
10374 case VMX_EXIT_INVEPT:
10375 case VMX_EXIT_INVVPID:
10376 case VMX_EXIT_VMFUNC:
10377 case VMX_EXIT_XSAVES:
10378 case VMX_EXIT_XRSTORS:
10379 return hmR0VmxExitSetPendingXcptUD(pVCpu, pMixedCtx, pVmxTransient);
10380 case VMX_EXIT_RESERVED_60:
10381 case VMX_EXIT_RDSEED: /* only spurious exits, so undefined */
10382 case VMX_EXIT_RESERVED_62:
10383 default:
10384 return hmR0VmxExitErrUndefined(pVCpu, pMixedCtx, pVmxTransient);
10385 }
10386#undef RETURN_EXIT_CALL
10387}
10388#endif /* !HMVMX_USE_FUNCTION_TABLE */
10389
10390
10391#ifdef VBOX_STRICT
10392/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
10393# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
10394 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
10395
10396# define HMVMX_ASSERT_PREEMPT_CPUID() \
10397 do { \
10398 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
10399 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
10400 } while (0)
10401
10402# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS() \
10403 do { \
10404 AssertPtr(pVCpu); \
10405 AssertPtr(pMixedCtx); \
10406 AssertPtr(pVmxTransient); \
10407 Assert(pVmxTransient->fVMEntryFailed == false); \
10408 Assert(ASMIntAreEnabled()); \
10409 HMVMX_ASSERT_PREEMPT_SAFE(); \
10410 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
10411 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)); \
10412 HMVMX_ASSERT_PREEMPT_SAFE(); \
10413 if (VMMR0IsLogFlushDisabled(pVCpu)) \
10414 HMVMX_ASSERT_PREEMPT_CPUID(); \
10415 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
10416 } while (0)
10417
10418# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() \
10419 do { \
10420 Log4Func(("\n")); \
10421 } while (0)
10422#else /* nonstrict builds: */
10423# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS() \
10424 do { \
10425 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
10426 NOREF(pVCpu); NOREF(pMixedCtx); NOREF(pVmxTransient); \
10427 } while (0)
10428# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() do { } while (0)
10429#endif
10430
10431
10432/**
10433 * Advances the guest RIP by the specified number of bytes.
10434 *
10435 * @param pVCpu The cross context virtual CPU structure.
10436 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
10437 * out-of-sync. Make sure to update the required fields
10438 * before using them.
10439 * @param cbInstr Number of bytes to advance the RIP by.
10440 *
10441 * @remarks No-long-jump zone!!!
10442 */
10443DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
10444{
10445 /* Advance the RIP. */
10446 pMixedCtx->rip += cbInstr;
10447 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
10448
10449 /* Update interrupt inhibition. */
10450 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
10451 && pMixedCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
10452 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
10453}
10454
10455
10456/**
10457 * Advances the guest RIP after reading it from the VMCS.
10458 *
10459 * @returns VBox status code, no informational status codes.
10460 * @param pVCpu The cross context virtual CPU structure.
10461 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
10462 * out-of-sync. Make sure to update the required fields
10463 * before using them.
10464 * @param pVmxTransient Pointer to the VMX transient structure.
10465 *
10466 * @remarks No-long-jump zone!!!
10467 */
10468static int hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
10469{
10470 int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
10471 rc |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
10472 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
10473 AssertRCReturn(rc, rc);
10474
10475 hmR0VmxAdvanceGuestRipBy(pVCpu, pMixedCtx, pVmxTransient->cbInstr);
10476
10477 /*
10478 * Deliver a debug exception to the guest if it is single-stepping. Don't directly inject a #DB but use the
10479 * pending debug exception field as it takes care of priority of events.
10480 *
10481 * See Intel spec. 32.2.1 "Debug Exceptions".
10482 */
10483 if ( !pVCpu->hm.s.fSingleInstruction
10484 && pMixedCtx->eflags.Bits.u1TF)
10485 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
10486
10487 return VINF_SUCCESS;
10488}
10489
10490
10491/**
10492 * Tries to determine what part of the guest-state VT-x has deemed as invalid
10493 * and update error record fields accordingly.
10494 *
10495 * @return VMX_IGS_* return codes.
10496 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
10497 * wrong with the guest state.
10498 *
10499 * @param pVM The cross context VM structure.
10500 * @param pVCpu The cross context virtual CPU structure.
10501 * @param pCtx Pointer to the guest-CPU state.
10502 *
10503 * @remarks This function assumes our cache of the VMCS controls
10504 * are valid, i.e. hmR0VmxCheckVmcsCtls() succeeded.
10505 */
10506static uint32_t hmR0VmxCheckGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10507{
10508#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
10509#define HMVMX_CHECK_BREAK(expr, err) if (!(expr)) { \
10510 uError = (err); \
10511 break; \
10512 } else do { } while (0)
10513
10514 int rc;
10515 uint32_t uError = VMX_IGS_ERROR;
10516 uint32_t u32Val;
10517 bool fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuest;
10518
10519 do
10520 {
10521 /*
10522 * CR0.
10523 */
10524 uint32_t uSetCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
10525 uint32_t uZapCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
10526 /* Exceptions for unrestricted-guests for fixed CR0 bits (PE, PG).
10527 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
10528 if (fUnrestrictedGuest)
10529 uSetCR0 &= ~(X86_CR0_PE | X86_CR0_PG);
10530
10531 uint32_t u32GuestCR0;
10532 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32GuestCR0);
10533 AssertRCBreak(rc);
10534 HMVMX_CHECK_BREAK((u32GuestCR0 & uSetCR0) == uSetCR0, VMX_IGS_CR0_FIXED1);
10535 HMVMX_CHECK_BREAK(!(u32GuestCR0 & ~uZapCR0), VMX_IGS_CR0_FIXED0);
10536 if ( !fUnrestrictedGuest
10537 && (u32GuestCR0 & X86_CR0_PG)
10538 && !(u32GuestCR0 & X86_CR0_PE))
10539 {
10540 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
10541 }
10542
10543 /*
10544 * CR4.
10545 */
10546 uint64_t uSetCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
10547 uint64_t uZapCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
10548
10549 uint32_t u32GuestCR4;
10550 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &u32GuestCR4);
10551 AssertRCBreak(rc);
10552 HMVMX_CHECK_BREAK((u32GuestCR4 & uSetCR4) == uSetCR4, VMX_IGS_CR4_FIXED1);
10553 HMVMX_CHECK_BREAK(!(u32GuestCR4 & ~uZapCR4), VMX_IGS_CR4_FIXED0);
10554
10555 /*
10556 * IA32_DEBUGCTL MSR.
10557 */
10558 uint64_t u64Val;
10559 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
10560 AssertRCBreak(rc);
10561 if ( (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
10562 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
10563 {
10564 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
10565 }
10566 uint64_t u64DebugCtlMsr = u64Val;
10567
10568#ifdef VBOX_STRICT
10569 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
10570 AssertRCBreak(rc);
10571 Assert(u32Val == pVCpu->hm.s.vmx.u32EntryCtls);
10572#endif
10573 bool const fLongModeGuest = RT_BOOL(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST);
10574
10575 /*
10576 * RIP and RFLAGS.
10577 */
10578 uint32_t u32Eflags;
10579#if HC_ARCH_BITS == 64
10580 rc = VMXReadVmcs64(VMX_VMCS_GUEST_RIP, &u64Val);
10581 AssertRCBreak(rc);
10582 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
10583 if ( !fLongModeGuest
10584 || !pCtx->cs.Attr.n.u1Long)
10585 {
10586 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
10587 }
10588 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
10589 * must be identical if the "IA-32e mode guest" VM-entry
10590 * control is 1 and CS.L is 1. No check applies if the
10591 * CPU supports 64 linear-address bits. */
10592
10593 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
10594 rc = VMXReadVmcs64(VMX_VMCS_GUEST_RFLAGS, &u64Val);
10595 AssertRCBreak(rc);
10596 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
10597 VMX_IGS_RFLAGS_RESERVED);
10598 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
10599 u32Eflags = u64Val;
10600#else
10601 rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &u32Eflags);
10602 AssertRCBreak(rc);
10603 HMVMX_CHECK_BREAK(!(u32Eflags & 0xffc08028), VMX_IGS_RFLAGS_RESERVED); /* Bit 31:22, Bit 15, 5, 3 MBZ. */
10604 HMVMX_CHECK_BREAK((u32Eflags & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
10605#endif
10606
10607 if ( fLongModeGuest
10608 || ( fUnrestrictedGuest
10609 && !(u32GuestCR0 & X86_CR0_PE)))
10610 {
10611 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
10612 }
10613
10614 uint32_t u32EntryInfo;
10615 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
10616 AssertRCBreak(rc);
10617 if ( VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo)
10618 && VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
10619 {
10620 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
10621 }
10622
10623 /*
10624 * 64-bit checks.
10625 */
10626#if HC_ARCH_BITS == 64
10627 if (fLongModeGuest)
10628 {
10629 HMVMX_CHECK_BREAK(u32GuestCR0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
10630 HMVMX_CHECK_BREAK(u32GuestCR4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
10631 }
10632
10633 if ( !fLongModeGuest
10634 && (u32GuestCR4 & X86_CR4_PCIDE))
10635 {
10636 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
10637 }
10638
10639 /** @todo CR3 field must be such that bits 63:52 and bits in the range
10640 * 51:32 beyond the processor's physical-address width are 0. */
10641
10642 if ( (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
10643 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
10644 {
10645 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
10646 }
10647
10648 rc = VMXReadVmcs64(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
10649 AssertRCBreak(rc);
10650 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
10651
10652 rc = VMXReadVmcs64(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
10653 AssertRCBreak(rc);
10654 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
10655#endif
10656
10657 /*
10658 * PERF_GLOBAL MSR.
10659 */
10660 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PERF_MSR)
10661 {
10662 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
10663 AssertRCBreak(rc);
10664 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
10665 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
10666 }
10667
10668 /*
10669 * PAT MSR.
10670 */
10671 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PAT_MSR)
10672 {
10673 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
10674 AssertRCBreak(rc);
10675 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
10676 for (unsigned i = 0; i < 8; i++)
10677 {
10678 uint8_t u8Val = (u64Val & 0xff);
10679 if ( u8Val != 0 /* UC */
10680 && u8Val != 1 /* WC */
10681 && u8Val != 4 /* WT */
10682 && u8Val != 5 /* WP */
10683 && u8Val != 6 /* WB */
10684 && u8Val != 7 /* UC- */)
10685 {
10686 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
10687 }
10688 u64Val >>= 8;
10689 }
10690 }
10691
10692 /*
10693 * EFER MSR.
10694 */
10695 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR)
10696 {
10697 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
10698 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
10699 AssertRCBreak(rc);
10700 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
10701 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
10702 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVCpu->hm.s.vmx.u32EntryCtls
10703 & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST),
10704 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
10705 HMVMX_CHECK_BREAK( fUnrestrictedGuest
10706 || !(u32GuestCR0 & X86_CR0_PG)
10707 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
10708 VMX_IGS_EFER_LMA_LME_MISMATCH);
10709 }
10710
10711 /*
10712 * Segment registers.
10713 */
10714 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10715 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
10716 if (!(u32Eflags & X86_EFL_VM))
10717 {
10718 /* CS */
10719 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
10720 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
10721 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
10722 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
10723 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
10724 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
10725 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
10726 /* CS cannot be loaded with NULL in protected mode. */
10727 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
10728 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
10729 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
10730 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
10731 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
10732 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
10733 else if (pVM->hm.s.vmx.fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
10734 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
10735 else
10736 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
10737
10738 /* SS */
10739 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10740 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
10741 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
10742 if ( !(pCtx->cr0 & X86_CR0_PE)
10743 || pCtx->cs.Attr.n.u4Type == 3)
10744 {
10745 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
10746 }
10747 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
10748 {
10749 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
10750 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
10751 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
10752 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
10753 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
10754 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
10755 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
10756 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
10757 }
10758
10759 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxWriteSegmentReg(). */
10760 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
10761 {
10762 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
10763 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
10764 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10765 || pCtx->ds.Attr.n.u4Type > 11
10766 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
10767 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
10768 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
10769 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
10770 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
10771 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
10772 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
10773 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10774 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
10775 }
10776 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
10777 {
10778 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
10779 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
10780 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10781 || pCtx->es.Attr.n.u4Type > 11
10782 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
10783 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
10784 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
10785 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
10786 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
10787 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
10788 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
10789 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10790 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
10791 }
10792 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
10793 {
10794 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
10795 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
10796 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10797 || pCtx->fs.Attr.n.u4Type > 11
10798 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
10799 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
10800 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
10801 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
10802 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
10803 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
10804 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
10805 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10806 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
10807 }
10808 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
10809 {
10810 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
10811 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
10812 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
10813 || pCtx->gs.Attr.n.u4Type > 11
10814 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
10815 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
10816 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
10817 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
10818 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10819 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
10820 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10821 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10822 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
10823 }
10824 /* 64-bit capable CPUs. */
10825#if HC_ARCH_BITS == 64
10826 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10827 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10828 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10829 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10830 HMVMX_CHECK_BREAK(!(pCtx->cs.u64Base >> 32), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10831 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ss.u64Base >> 32),
10832 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10833 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ds.u64Base >> 32),
10834 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10835 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->es.u64Base >> 32),
10836 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10837#endif
10838 }
10839 else
10840 {
10841 /* V86 mode checks. */
10842 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
10843 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
10844 {
10845 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
10846 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
10847 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
10848 }
10849 else
10850 {
10851 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
10852 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
10853 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
10854 }
10855
10856 /* CS */
10857 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
10858 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
10859 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
10860 /* SS */
10861 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
10862 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
10863 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
10864 /* DS */
10865 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
10866 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
10867 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
10868 /* ES */
10869 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
10870 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
10871 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
10872 /* FS */
10873 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
10874 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
10875 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
10876 /* GS */
10877 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
10878 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
10879 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
10880 /* 64-bit capable CPUs. */
10881#if HC_ARCH_BITS == 64
10882 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10883 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10884 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10885 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10886 HMVMX_CHECK_BREAK(!(pCtx->cs.u64Base >> 32), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10887 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ss.u64Base >> 32),
10888 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10889 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ds.u64Base >> 32),
10890 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10891 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->es.u64Base >> 32),
10892 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10893#endif
10894 }
10895
10896 /*
10897 * TR.
10898 */
10899 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
10900 /* 64-bit capable CPUs. */
10901#if HC_ARCH_BITS == 64
10902 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
10903#endif
10904 if (fLongModeGuest)
10905 {
10906 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
10907 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
10908 }
10909 else
10910 {
10911 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
10912 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
10913 VMX_IGS_TR_ATTR_TYPE_INVALID);
10914 }
10915 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
10916 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
10917 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
10918 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
10919 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
10920 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
10921 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
10922 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
10923
10924 /*
10925 * GDTR and IDTR.
10926 */
10927#if HC_ARCH_BITS == 64
10928 rc = VMXReadVmcs64(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
10929 AssertRCBreak(rc);
10930 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
10931
10932 rc = VMXReadVmcs64(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
10933 AssertRCBreak(rc);
10934 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
10935#endif
10936
10937 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
10938 AssertRCBreak(rc);
10939 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
10940
10941 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
10942 AssertRCBreak(rc);
10943 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
10944
10945 /*
10946 * Guest Non-Register State.
10947 */
10948 /* Activity State. */
10949 uint32_t u32ActivityState;
10950 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
10951 AssertRCBreak(rc);
10952 HMVMX_CHECK_BREAK( !u32ActivityState
10953 || (u32ActivityState & MSR_IA32_VMX_MISC_ACTIVITY_STATES(pVM->hm.s.vmx.Msrs.u64Misc)),
10954 VMX_IGS_ACTIVITY_STATE_INVALID);
10955 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
10956 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
10957 uint32_t u32IntrState;
10958 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &u32IntrState);
10959 AssertRCBreak(rc);
10960 if ( u32IntrState == VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS
10961 || u32IntrState == VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
10962 {
10963 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
10964 }
10965
10966 /** @todo Activity state and injecting interrupts. Left as a todo since we
10967 * currently don't use activity states but ACTIVE. */
10968
10969 HMVMX_CHECK_BREAK( !(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_ENTRY_SMM)
10970 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
10971
10972 /* Guest interruptibility-state. */
10973 HMVMX_CHECK_BREAK(!(u32IntrState & 0xfffffff0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
10974 HMVMX_CHECK_BREAK((u32IntrState & ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI
10975 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS))
10976 != ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI
10977 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
10978 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
10979 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
10980 || !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI),
10981 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
10982 if (VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo))
10983 {
10984 if (VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
10985 {
10986 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
10987 && !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
10988 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
10989 }
10990 else if (VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
10991 {
10992 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
10993 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
10994 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI),
10995 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
10996 }
10997 }
10998 /** @todo Assumes the processor is not in SMM. */
10999 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI),
11000 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
11001 HMVMX_CHECK_BREAK( !(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_ENTRY_SMM)
11002 || (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI),
11003 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
11004 if ( (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
11005 && VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo)
11006 && VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11007 {
11008 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI),
11009 VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
11010 }
11011
11012 /* Pending debug exceptions. */
11013#if HC_ARCH_BITS == 64
11014 rc = VMXReadVmcs64(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, &u64Val);
11015 AssertRCBreak(rc);
11016 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
11017 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
11018 u32Val = u64Val; /* For pending debug exceptions checks below. */
11019#else
11020 rc = VMXReadVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, &u32Val);
11021 AssertRCBreak(rc);
11022 /* Bits 31:15, Bit 13, Bits 11:4 MBZ. */
11023 HMVMX_CHECK_BREAK(!(u32Val & 0xffffaff0), VMX_IGS_PENDING_DEBUG_RESERVED);
11024#endif
11025
11026 if ( (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
11027 || (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS)
11028 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
11029 {
11030 if ( (u32Eflags & X86_EFL_TF)
11031 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
11032 {
11033 /* Bit 14 is PendingDebug.BS. */
11034 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
11035 }
11036 if ( !(u32Eflags & X86_EFL_TF)
11037 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
11038 {
11039 /* Bit 14 is PendingDebug.BS. */
11040 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
11041 }
11042 }
11043
11044 /* VMCS link pointer. */
11045 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
11046 AssertRCBreak(rc);
11047 if (u64Val != UINT64_C(0xffffffffffffffff))
11048 {
11049 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
11050 /** @todo Bits beyond the processor's physical-address width MBZ. */
11051 /** @todo 32-bit located in memory referenced by value of this field (as a
11052 * physical address) must contain the processor's VMCS revision ID. */
11053 /** @todo SMM checks. */
11054 }
11055
11056 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
11057 * not using Nested Paging? */
11058 if ( pVM->hm.s.fNestedPaging
11059 && !fLongModeGuest
11060 && CPUMIsGuestInPAEModeEx(pCtx))
11061 {
11062 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
11063 AssertRCBreak(rc);
11064 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11065
11066 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
11067 AssertRCBreak(rc);
11068 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11069
11070 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
11071 AssertRCBreak(rc);
11072 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11073
11074 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
11075 AssertRCBreak(rc);
11076 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11077 }
11078
11079 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
11080 if (uError == VMX_IGS_ERROR)
11081 uError = VMX_IGS_REASON_NOT_FOUND;
11082 } while (0);
11083
11084 pVCpu->hm.s.u32HMError = uError;
11085 return uError;
11086
11087#undef HMVMX_ERROR_BREAK
11088#undef HMVMX_CHECK_BREAK
11089}
11090
11091/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
11092/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
11093/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
11094
11095/** @name VM-exit handlers.
11096 * @{
11097 */
11098
11099/**
11100 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
11101 */
11102HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11103{
11104 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11105 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
11106 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
11107 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
11108 return VINF_SUCCESS;
11109 return VINF_EM_RAW_INTERRUPT;
11110}
11111
11112
11113/**
11114 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
11115 */
11116HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11117{
11118 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11119 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
11120
11121 int rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
11122 AssertRCReturn(rc, rc);
11123
11124 uint32_t uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo);
11125 Assert( !(pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT)
11126 && uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
11127 Assert(VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
11128
11129 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11130 {
11131 /*
11132 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we injected it ourselves and
11133 * anything we inject is not going to cause a VM-exit directly for the event being injected.
11134 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
11135 *
11136 * Dispatch the NMI to the host. See Intel spec. 27.5.5 "Updating Non-Register State".
11137 */
11138 VMXDispatchHostNmi();
11139 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
11140 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11141 return VINF_SUCCESS;
11142 }
11143
11144 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
11145 VBOXSTRICTRC rcStrictRc1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
11146 if (RT_UNLIKELY(rcStrictRc1 == VINF_SUCCESS))
11147 { /* likely */ }
11148 else
11149 {
11150 if (rcStrictRc1 == VINF_HM_DOUBLE_FAULT)
11151 rcStrictRc1 = VINF_SUCCESS;
11152 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11153 return rcStrictRc1;
11154 }
11155
11156 uint32_t uExitIntInfo = pVmxTransient->uExitIntInfo;
11157 uint32_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(uExitIntInfo);
11158 switch (uIntType)
11159 {
11160 case VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT: /* Privileged software exception. (#DB from ICEBP) */
11161 Assert(uVector == X86_XCPT_DB);
11162 /* no break */
11163 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT: /* Software exception. (#BP or #OF) */
11164 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT);
11165 /* no break */
11166 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT:
11167 {
11168 switch (uVector)
11169 {
11170 case X86_XCPT_PF: rc = hmR0VmxExitXcptPF(pVCpu, pMixedCtx, pVmxTransient); break;
11171 case X86_XCPT_GP: rc = hmR0VmxExitXcptGP(pVCpu, pMixedCtx, pVmxTransient); break;
11172 case X86_XCPT_NM: rc = hmR0VmxExitXcptNM(pVCpu, pMixedCtx, pVmxTransient); break;
11173 case X86_XCPT_MF: rc = hmR0VmxExitXcptMF(pVCpu, pMixedCtx, pVmxTransient); break;
11174 case X86_XCPT_DB: rc = hmR0VmxExitXcptDB(pVCpu, pMixedCtx, pVmxTransient); break;
11175 case X86_XCPT_BP: rc = hmR0VmxExitXcptBP(pVCpu, pMixedCtx, pVmxTransient); break;
11176 case X86_XCPT_AC: rc = hmR0VmxExitXcptAC(pVCpu, pMixedCtx, pVmxTransient); break;
11177
11178 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF);
11179 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11180 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE);
11181 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11182 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD);
11183 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11184 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS);
11185 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11186 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP);
11187 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11188 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS);
11189 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11190 default:
11191 {
11192 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11193 AssertRCReturn(rc, rc);
11194
11195 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
11196 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
11197 {
11198 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
11199 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
11200 Assert(CPUMIsGuestInRealModeEx(pMixedCtx));
11201
11202 rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
11203 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
11204 AssertRCReturn(rc, rc);
11205 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(uExitIntInfo),
11206 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode,
11207 0 /* GCPtrFaultAddress */);
11208 AssertRCReturn(rc, rc);
11209 }
11210 else
11211 {
11212 AssertMsgFailed(("Unexpected VM-exit caused by exception %#x\n", uVector));
11213 pVCpu->hm.s.u32HMError = uVector;
11214 rc = VERR_VMX_UNEXPECTED_EXCEPTION;
11215 }
11216 break;
11217 }
11218 }
11219 break;
11220 }
11221
11222 default:
11223 {
11224 pVCpu->hm.s.u32HMError = uExitIntInfo;
11225 rc = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
11226 AssertMsgFailed(("Unexpected interruption info %#x\n", VMX_EXIT_INTERRUPTION_INFO_TYPE(uExitIntInfo)));
11227 break;
11228 }
11229 }
11230 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11231 return rc;
11232}
11233
11234
11235/**
11236 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
11237 */
11238HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11239{
11240 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11241
11242 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
11243 hmR0VmxClearIntWindowExitVmcs(pVCpu);
11244
11245 /* Deliver the pending interrupts via hmR0VmxEvaluatePendingEvent() and resume guest execution. */
11246 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
11247 return VINF_SUCCESS;
11248}
11249
11250
11251/**
11252 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
11253 */
11254HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11255{
11256 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11257 if (RT_UNLIKELY(!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT)))
11258 {
11259 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
11260 HMVMX_RETURN_UNEXPECTED_EXIT();
11261 }
11262
11263 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS));
11264
11265 /*
11266 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
11267 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
11268 */
11269 uint32_t uIntrState = 0;
11270 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
11271 AssertRCReturn(rc, rc);
11272
11273 bool const fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
11274 if ( fBlockSti
11275 && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
11276 {
11277 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
11278 }
11279
11280 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
11281 hmR0VmxClearNmiWindowExitVmcs(pVCpu);
11282
11283 /* Deliver the pending NMI via hmR0VmxEvaluatePendingEvent() and resume guest execution. */
11284 return VINF_SUCCESS;
11285}
11286
11287
11288/**
11289 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
11290 */
11291HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11292{
11293 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11294 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWbinvd);
11295 return hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11296}
11297
11298
11299/**
11300 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
11301 */
11302HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11303{
11304 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11305 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvd);
11306 return hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11307}
11308
11309
11310/**
11311 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
11312 */
11313HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11314{
11315 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11316 PVM pVM = pVCpu->CTX_SUFF(pVM);
11317 int rc = EMInterpretCpuId(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11318 if (RT_LIKELY(rc == VINF_SUCCESS))
11319 {
11320 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11321 Assert(pVmxTransient->cbInstr == 2);
11322 }
11323 else
11324 {
11325 AssertMsgFailed(("hmR0VmxExitCpuid: EMInterpretCpuId failed with %Rrc\n", rc));
11326 rc = VERR_EM_INTERPRETER;
11327 }
11328 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCpuid);
11329 return rc;
11330}
11331
11332
11333/**
11334 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
11335 */
11336HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11337{
11338 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11339 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11340 AssertRCReturn(rc, rc);
11341
11342 if (pMixedCtx->cr4 & X86_CR4_SMXE)
11343 return VINF_EM_RAW_EMULATE_INSTR;
11344
11345 AssertMsgFailed(("hmR0VmxExitGetsec: unexpected VM-exit when CR4.SMXE is 0.\n"));
11346 HMVMX_RETURN_UNEXPECTED_EXIT();
11347}
11348
11349
11350/**
11351 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
11352 */
11353HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11354{
11355 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11356 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx); /** @todo review if CR4 is really required by EM. */
11357 AssertRCReturn(rc, rc);
11358
11359 PVM pVM = pVCpu->CTX_SUFF(pVM);
11360 rc = EMInterpretRdtsc(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11361 if (RT_LIKELY(rc == VINF_SUCCESS))
11362 {
11363 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11364 Assert(pVmxTransient->cbInstr == 2);
11365 /* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
11366 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING)
11367 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11368 }
11369 else
11370 rc = VERR_EM_INTERPRETER;
11371 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
11372 return rc;
11373}
11374
11375
11376/**
11377 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
11378 */
11379HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11380{
11381 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11382 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx); /** @todo review if CR4 is really required by EM. */
11383 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx); /* For MSR_K8_TSC_AUX */
11384 AssertRCReturn(rc, rc);
11385
11386 PVM pVM = pVCpu->CTX_SUFF(pVM);
11387 rc = EMInterpretRdtscp(pVM, pVCpu, pMixedCtx);
11388 if (RT_SUCCESS(rc))
11389 {
11390 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11391 Assert(pVmxTransient->cbInstr == 3);
11392 /* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
11393 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING)
11394 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11395 }
11396 else
11397 {
11398 AssertMsgFailed(("hmR0VmxExitRdtscp: EMInterpretRdtscp failed with %Rrc\n", rc));
11399 rc = VERR_EM_INTERPRETER;
11400 }
11401 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
11402 return rc;
11403}
11404
11405
11406/**
11407 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
11408 */
11409HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11410{
11411 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11412 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx); /** @todo review if CR4 is really required by EM. */
11413 rc |= hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx); /** @todo review if CR0 is really required by EM. */
11414 AssertRCReturn(rc, rc);
11415
11416 PVM pVM = pVCpu->CTX_SUFF(pVM);
11417 rc = EMInterpretRdpmc(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11418 if (RT_LIKELY(rc == VINF_SUCCESS))
11419 {
11420 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11421 Assert(pVmxTransient->cbInstr == 2);
11422 }
11423 else
11424 {
11425 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
11426 rc = VERR_EM_INTERPRETER;
11427 }
11428 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdpmc);
11429 return rc;
11430}
11431
11432
11433/**
11434 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
11435 */
11436HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11437{
11438 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11439 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
11440
11441 if (pVCpu->hm.s.fHypercallsEnabled)
11442 {
11443#if 0
11444 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
11445#else
11446 /* Aggressive state sync. for now. */
11447 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
11448 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* For long-mode checks in gimKvmHypercall(). */
11449#endif
11450 rc |= hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11451 AssertRCReturn(rc, rc);
11452
11453 /** @todo pre-increment RIP before hypercall will break when we have to implement
11454 * continuing hypercalls (e.g. Hyper-V). */
11455 /** @todo r=bird: GIMHypercall will probably have to be able to return
11456 * informational status codes, so it should be made VBOXSTRICTRC. Not
11457 * doing that now because the status code handling isn't clean (i.e.
11458 * if you use RT_SUCCESS(rc) on the result of something, you don't
11459 * return rc in the success case, you return VINF_SUCCESS). */
11460 rc = GIMHypercall(pVCpu, pMixedCtx);
11461 /* If the hypercall changes anything other than guest general-purpose registers,
11462 we would need to reload the guest changed bits here before VM-entry. */
11463 return rc;
11464 }
11465
11466 Log4(("hmR0VmxExitVmcall: Hypercalls not enabled\n"));
11467 hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
11468 return VINF_SUCCESS;
11469}
11470
11471
11472/**
11473 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
11474 */
11475HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11476{
11477 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11478 PVM pVM = pVCpu->CTX_SUFF(pVM);
11479 Assert(!pVM->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
11480
11481 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
11482 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
11483 AssertRCReturn(rc, rc);
11484
11485 VBOXSTRICTRC rcStrict = EMInterpretInvlpg(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), pVmxTransient->uExitQualification);
11486 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
11487 rcStrict = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11488 else
11489 AssertMsg(rcStrict == VERR_EM_INTERPRETER, ("hmR0VmxExitInvlpg: EMInterpretInvlpg %#RX64 failed with %Rrc\n",
11490 pVmxTransient->uExitQualification, VBOXSTRICTRC_VAL(rcStrict)));
11491 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvlpg);
11492 return rcStrict;
11493}
11494
11495
11496/**
11497 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
11498 */
11499HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11500{
11501 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11502 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11503 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
11504 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
11505 AssertRCReturn(rc, rc);
11506
11507 PVM pVM = pVCpu->CTX_SUFF(pVM);
11508 rc = EMInterpretMonitor(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11509 if (RT_LIKELY(rc == VINF_SUCCESS))
11510 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11511 else
11512 {
11513 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMonitor: EMInterpretMonitor failed with %Rrc\n", rc));
11514 rc = VERR_EM_INTERPRETER;
11515 }
11516 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMonitor);
11517 return rc;
11518}
11519
11520
11521/**
11522 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
11523 */
11524HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11525{
11526 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11527 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11528 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
11529 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
11530 AssertRCReturn(rc, rc);
11531
11532 PVM pVM = pVCpu->CTX_SUFF(pVM);
11533 VBOXSTRICTRC rc2 = EMInterpretMWait(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11534 rc = VBOXSTRICTRC_VAL(rc2);
11535 if (RT_LIKELY( rc == VINF_SUCCESS
11536 || rc == VINF_EM_HALT))
11537 {
11538 int rc3 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11539 AssertRCReturn(rc3, rc3);
11540
11541 if ( rc == VINF_EM_HALT
11542 && EMMonitorWaitShouldContinue(pVCpu, pMixedCtx))
11543 {
11544 rc = VINF_SUCCESS;
11545 }
11546 }
11547 else
11548 {
11549 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMwait: EMInterpretMWait failed with %Rrc\n", rc));
11550 rc = VERR_EM_INTERPRETER;
11551 }
11552 AssertMsg(rc == VINF_SUCCESS || rc == VINF_EM_HALT || rc == VERR_EM_INTERPRETER,
11553 ("hmR0VmxExitMwait: failed, invalid error code %Rrc\n", rc));
11554 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMwait);
11555 return rc;
11556}
11557
11558
11559/**
11560 * VM-exit handler for RSM (VMX_EXIT_RSM). Unconditional VM-exit.
11561 */
11562HMVMX_EXIT_NSRC_DECL hmR0VmxExitRsm(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11563{
11564 /*
11565 * Execution of RSM outside of SMM mode causes #UD regardless of VMX root or VMX non-root mode. In theory, we should never
11566 * get this VM-exit. This can happen only if dual-monitor treatment of SMI and VMX is enabled, which can (only?) be done by
11567 * executing VMCALL in VMX root operation. If we get here, something funny is going on.
11568 * See Intel spec. "33.15.5 Enabling the Dual-Monitor Treatment".
11569 */
11570 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11571 AssertMsgFailed(("Unexpected RSM VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11572 HMVMX_RETURN_UNEXPECTED_EXIT();
11573}
11574
11575
11576/**
11577 * VM-exit handler for SMI (VMX_EXIT_SMI). Unconditional VM-exit.
11578 */
11579HMVMX_EXIT_NSRC_DECL hmR0VmxExitSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11580{
11581 /*
11582 * This can only happen if we support dual-monitor treatment of SMI, which can be activated by executing VMCALL in VMX
11583 * root operation. Only an STM (SMM transfer monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL
11584 * in VMX root mode or receive an SMI. If we get here, something funny is going on.
11585 * See Intel spec. "33.15.6 Activating the Dual-Monitor Treatment" and Intel spec. 25.3 "Other Causes of VM-Exits"
11586 */
11587 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11588 AssertMsgFailed(("Unexpected SMI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11589 HMVMX_RETURN_UNEXPECTED_EXIT();
11590}
11591
11592
11593/**
11594 * VM-exit handler for IO SMI (VMX_EXIT_IO_SMI). Unconditional VM-exit.
11595 */
11596HMVMX_EXIT_NSRC_DECL hmR0VmxExitIoSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11597{
11598 /* Same treatment as VMX_EXIT_SMI. See comment in hmR0VmxExitSmi(). */
11599 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11600 AssertMsgFailed(("Unexpected IO SMI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11601 HMVMX_RETURN_UNEXPECTED_EXIT();
11602}
11603
11604
11605/**
11606 * VM-exit handler for SIPI (VMX_EXIT_SIPI). Conditional VM-exit.
11607 */
11608HMVMX_EXIT_NSRC_DECL hmR0VmxExitSipi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11609{
11610 /*
11611 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest activity state is used. We currently
11612 * don't make use of it (see hmR0VmxLoadGuestActivityState()) as our guests don't have direct access to the host LAPIC.
11613 * See Intel spec. 25.3 "Other Causes of VM-exits".
11614 */
11615 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11616 AssertMsgFailed(("Unexpected SIPI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11617 HMVMX_RETURN_UNEXPECTED_EXIT();
11618}
11619
11620
11621/**
11622 * VM-exit handler for INIT signal (VMX_EXIT_INIT_SIGNAL). Unconditional
11623 * VM-exit.
11624 */
11625HMVMX_EXIT_NSRC_DECL hmR0VmxExitInitSignal(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11626{
11627 /*
11628 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
11629 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery" and Intel spec. 29.3 "VMX Instructions" for "VMXON".
11630 *
11631 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these VM-exits.
11632 * See Intel spec. "23.8 Restrictions on VMX operation".
11633 */
11634 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11635 return VINF_SUCCESS;
11636}
11637
11638
11639/**
11640 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
11641 * VM-exit.
11642 */
11643HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11644{
11645 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11646 return VINF_EM_RESET;
11647}
11648
11649
11650/**
11651 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
11652 */
11653HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11654{
11655 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11656 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT);
11657
11658 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11659 AssertRCReturn(rc, rc);
11660
11661 if (EMShouldContinueAfterHalt(pVCpu, pMixedCtx)) /* Requires eflags. */
11662 rc = VINF_SUCCESS;
11663 else
11664 rc = VINF_EM_HALT;
11665
11666 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
11667 if (rc != VINF_SUCCESS)
11668 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
11669 return rc;
11670}
11671
11672
11673/**
11674 * VM-exit handler for instructions that result in a \#UD exception delivered to
11675 * the guest.
11676 */
11677HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11678{
11679 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11680 hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
11681 return VINF_SUCCESS;
11682}
11683
11684
11685/**
11686 * VM-exit handler for expiry of the VMX preemption timer.
11687 */
11688HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11689{
11690 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11691
11692 /* If the preemption-timer has expired, reinitialize the preemption timer on next VM-entry. */
11693 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11694
11695 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
11696 PVM pVM = pVCpu->CTX_SUFF(pVM);
11697 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
11698 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
11699 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
11700}
11701
11702
11703/**
11704 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
11705 */
11706HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11707{
11708 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11709
11710 int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
11711 rc |= hmR0VmxSaveGuestRegsForIemExec(pVCpu, pMixedCtx, false /*fMemory*/, false /*fNeedRsp*/);
11712 rc |= hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11713 AssertRCReturn(rc, rc);
11714
11715 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbInstr);
11716 HMCPU_CF_SET(pVCpu, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS : HM_CHANGED_ALL_GUEST);
11717
11718 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pMixedCtx->cr4 & X86_CR4_OSXSAVE) && pMixedCtx->aXcr[0] != ASMGetXcr0();
11719
11720 return rcStrict;
11721}
11722
11723
11724/**
11725 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
11726 */
11727HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11728{
11729 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11730
11731 /* The guest should not invalidate the host CPU's TLBs, fallback to interpreter. */
11732 /** @todo implement EMInterpretInvpcid() */
11733 return VERR_EM_INTERPRETER;
11734}
11735
11736
11737/**
11738 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE).
11739 * Error VM-exit.
11740 */
11741HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11742{
11743 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
11744 AssertRCReturn(rc, rc);
11745
11746 rc = hmR0VmxCheckVmcsCtls(pVCpu);
11747 AssertRCReturn(rc, rc);
11748
11749 uint32_t uInvalidReason = hmR0VmxCheckGuestState(pVCpu->CTX_SUFF(pVM), pVCpu, pMixedCtx);
11750 NOREF(uInvalidReason);
11751
11752#ifdef VBOX_STRICT
11753 uint32_t uIntrState;
11754 RTHCUINTREG uHCReg;
11755 uint64_t u64Val;
11756 uint32_t u32Val;
11757
11758 rc = hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
11759 rc |= hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
11760 rc |= hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
11761 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
11762 AssertRCReturn(rc, rc);
11763
11764 Log4(("uInvalidReason %u\n", uInvalidReason));
11765 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
11766 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
11767 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
11768 Log4(("VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE %#RX32\n", uIntrState));
11769
11770 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32Val); AssertRC(rc);
11771 Log4(("VMX_VMCS_GUEST_CR0 %#RX32\n", u32Val));
11772 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
11773 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
11774 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
11775 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
11776 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
11777 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
11778 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
11779 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
11780 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
11781 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
11782#else
11783 NOREF(pVmxTransient);
11784#endif
11785
11786 HMDumpRegs(pVCpu->CTX_SUFF(pVM), pVCpu, pMixedCtx);
11787 return VERR_VMX_INVALID_GUEST_STATE;
11788}
11789
11790
11791/**
11792 * VM-exit handler for VM-entry failure due to an MSR-load
11793 * (VMX_EXIT_ERR_MSR_LOAD). Error VM-exit.
11794 */
11795HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrMsrLoad(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11796{
11797 NOREF(pVmxTransient);
11798 AssertMsgFailed(("Unexpected MSR-load exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx)); NOREF(pMixedCtx);
11799 HMVMX_RETURN_UNEXPECTED_EXIT();
11800}
11801
11802
11803/**
11804 * VM-exit handler for VM-entry failure due to a machine-check event
11805 * (VMX_EXIT_ERR_MACHINE_CHECK). Error VM-exit.
11806 */
11807HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrMachineCheck(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11808{
11809 NOREF(pVmxTransient);
11810 AssertMsgFailed(("Unexpected machine-check event exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx)); NOREF(pMixedCtx);
11811 HMVMX_RETURN_UNEXPECTED_EXIT();
11812}
11813
11814
11815/**
11816 * VM-exit handler for all undefined reasons. Should never ever happen.. in
11817 * theory.
11818 */
11819HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUndefined(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11820{
11821 AssertMsgFailed(("Huh!? Undefined VM-exit reason %d. pVCpu=%p pMixedCtx=%p\n", pVmxTransient->uExitReason, pVCpu, pMixedCtx));
11822 NOREF(pVCpu); NOREF(pMixedCtx); NOREF(pVmxTransient);
11823 return VERR_VMX_UNDEFINED_EXIT_CODE;
11824}
11825
11826
11827/**
11828 * VM-exit handler for XDTR (LGDT, SGDT, LIDT, SIDT) accesses
11829 * (VMX_EXIT_XDTR_ACCESS) and LDT and TR access (LLDT, LTR, SLDT, STR).
11830 * Conditional VM-exit.
11831 */
11832HMVMX_EXIT_DECL hmR0VmxExitXdtrAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11833{
11834 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11835
11836 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT. */
11837 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitXdtrAccess);
11838 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT)
11839 return VERR_EM_INTERPRETER;
11840 AssertMsgFailed(("Unexpected XDTR access. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11841 HMVMX_RETURN_UNEXPECTED_EXIT();
11842}
11843
11844
11845/**
11846 * VM-exit handler for RDRAND (VMX_EXIT_RDRAND). Conditional VM-exit.
11847 */
11848HMVMX_EXIT_DECL hmR0VmxExitRdrand(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11849{
11850 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11851
11852 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT. */
11853 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdrand);
11854 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT)
11855 return VERR_EM_INTERPRETER;
11856 AssertMsgFailed(("Unexpected RDRAND exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11857 HMVMX_RETURN_UNEXPECTED_EXIT();
11858}
11859
11860
11861/**
11862 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
11863 */
11864HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11865{
11866 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11867
11868 /* EMInterpretRdmsr() requires CR0, Eflags and SS segment register. */
11869 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11870 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
11871 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
11872 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
11873 {
11874 rc |= hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
11875 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
11876 }
11877 AssertRCReturn(rc, rc);
11878 Log4(("ecx=%#RX32\n", pMixedCtx->ecx));
11879
11880#ifdef VBOX_STRICT
11881 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
11882 {
11883 if ( hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx)
11884 && pMixedCtx->ecx != MSR_K6_EFER)
11885 {
11886 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
11887 pMixedCtx->ecx));
11888 HMVMX_RETURN_UNEXPECTED_EXIT();
11889 }
11890# if HC_ARCH_BITS == 64
11891 if ( pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests
11892 && hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
11893 {
11894 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", pMixedCtx->ecx));
11895 HMVMX_RETURN_UNEXPECTED_EXIT();
11896 }
11897# endif
11898 }
11899#endif
11900
11901 PVM pVM = pVCpu->CTX_SUFF(pVM);
11902 rc = EMInterpretRdmsr(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11903 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER,
11904 ("hmR0VmxExitRdmsr: failed, invalid error code %Rrc\n", rc));
11905 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
11906 if (RT_SUCCESS(rc))
11907 {
11908 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11909 Assert(pVmxTransient->cbInstr == 2);
11910 }
11911 return rc;
11912}
11913
11914
11915/**
11916 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
11917 */
11918HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11919{
11920 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11921 PVM pVM = pVCpu->CTX_SUFF(pVM);
11922 int rc = VINF_SUCCESS;
11923
11924 /* EMInterpretWrmsr() requires CR0, EFLAGS and SS segment register. */
11925 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11926 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
11927 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
11928 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
11929 {
11930 rc |= hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
11931 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
11932 }
11933 AssertRCReturn(rc, rc);
11934 Log4(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", pMixedCtx->ecx, pMixedCtx->edx, pMixedCtx->eax));
11935
11936 rc = EMInterpretWrmsr(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11937 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER, ("hmR0VmxExitWrmsr: failed, invalid error code %Rrc\n", rc));
11938 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
11939
11940 if (RT_SUCCESS(rc))
11941 {
11942 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11943
11944 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
11945 if ( pMixedCtx->ecx >= MSR_IA32_X2APIC_START
11946 && pMixedCtx->ecx <= MSR_IA32_X2APIC_END)
11947 {
11948 /* We've already saved the APIC related guest-state (TPR) in hmR0VmxPostRunGuest(). When full APIC register
11949 * virtualization is implemented we'll have to make sure APIC state is saved from the VMCS before
11950 EMInterpretWrmsr() changes it. */
11951 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
11952 }
11953 else if (pMixedCtx->ecx == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
11954 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11955 else if (pMixedCtx->ecx == MSR_K6_EFER)
11956 {
11957 /*
11958 * If the guest touches EFER we need to update the VM-Entry and VM-Exit controls as well,
11959 * even if it is -not- touching bits that cause paging mode changes (LMA/LME). We care about
11960 * the other bits as well, SCE and NXE. See @bugref{7368}.
11961 */
11962 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_CTLS | HM_CHANGED_VMX_EXIT_CTLS);
11963 }
11964
11965 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not supported. */
11966 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
11967 {
11968 switch (pMixedCtx->ecx)
11969 {
11970 case MSR_IA32_SYSENTER_CS: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
11971 case MSR_IA32_SYSENTER_EIP: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
11972 case MSR_IA32_SYSENTER_ESP: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
11973 case MSR_K8_FS_BASE: /* no break */
11974 case MSR_K8_GS_BASE: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS); break;
11975 case MSR_K6_EFER: /* already handled above */ break;
11976 default:
11977 {
11978 if (hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx))
11979 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
11980#if HC_ARCH_BITS == 64
11981 else if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
11982 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS);
11983#endif
11984 break;
11985 }
11986 }
11987 }
11988#ifdef VBOX_STRICT
11989 else
11990 {
11991 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
11992 switch (pMixedCtx->ecx)
11993 {
11994 case MSR_IA32_SYSENTER_CS:
11995 case MSR_IA32_SYSENTER_EIP:
11996 case MSR_IA32_SYSENTER_ESP:
11997 case MSR_K8_FS_BASE:
11998 case MSR_K8_GS_BASE:
11999 {
12000 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", pMixedCtx->ecx));
12001 HMVMX_RETURN_UNEXPECTED_EXIT();
12002 }
12003
12004 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
12005 default:
12006 {
12007 if (hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx))
12008 {
12009 /* EFER writes are always intercepted, see hmR0VmxLoadGuestMsrs(). */
12010 if (pMixedCtx->ecx != MSR_K6_EFER)
12011 {
12012 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
12013 pMixedCtx->ecx));
12014 HMVMX_RETURN_UNEXPECTED_EXIT();
12015 }
12016 }
12017
12018#if HC_ARCH_BITS == 64
12019 if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
12020 {
12021 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", pMixedCtx->ecx));
12022 HMVMX_RETURN_UNEXPECTED_EXIT();
12023 }
12024#endif
12025 break;
12026 }
12027 }
12028 }
12029#endif /* VBOX_STRICT */
12030 }
12031 return rc;
12032}
12033
12034
12035/**
12036 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
12037 */
12038HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12039{
12040 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12041
12042 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPause);
12043 return VINF_EM_RAW_INTERRUPT;
12044}
12045
12046
12047/**
12048 * VM-exit handler for when the TPR value is lowered below the specified
12049 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
12050 */
12051HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12052{
12053 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12054 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW);
12055
12056 /*
12057 * The TPR has already been updated, see hmR0VMXPostRunGuest(). RIP is also updated as part of the VM-exit by VT-x. Update
12058 * the threshold in the VMCS, deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectPendingEvent() and
12059 * resume guest execution.
12060 */
12061 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
12062 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
12063 return VINF_SUCCESS;
12064}
12065
12066
12067/**
12068 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
12069 * VM-exit.
12070 *
12071 * @retval VINF_SUCCESS when guest execution can continue.
12072 * @retval VINF_PGM_CHANGE_MODE when shadow paging mode changed, back to ring-3.
12073 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
12074 * @retval VERR_EM_INTERPRETER when something unexpected happened, fallback to
12075 * interpreter.
12076 */
12077HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12078{
12079 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12080 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
12081 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12082 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12083 AssertRCReturn(rc, rc);
12084
12085 RTGCUINTPTR const uExitQualification = pVmxTransient->uExitQualification;
12086 uint32_t const uAccessType = VMX_EXIT_QUALIFICATION_CRX_ACCESS(uExitQualification);
12087 PVM pVM = pVCpu->CTX_SUFF(pVM);
12088 VBOXSTRICTRC rcStrict;
12089 rc = hmR0VmxSaveGuestRegsForIemExec(pVCpu, pMixedCtx, false /*fMemory*/, true /*fNeedRsp*/);
12090 switch (uAccessType)
12091 {
12092 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_WRITE: /* MOV to CRx */
12093 {
12094 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12095 AssertRCReturn(rc, rc);
12096
12097 rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, pVmxTransient->cbInstr,
12098 VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification),
12099 VMX_EXIT_QUALIFICATION_CRX_GENREG(uExitQualification));
12100 AssertMsg( rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT || rcStrict == VINF_PGM_CHANGE_MODE
12101 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12102 switch (VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification))
12103 {
12104 case 0: /* CR0 */
12105 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
12106 Log4(("CRX CR0 write rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr0));
12107 break;
12108 case 2: /* CR2 */
12109 /* Nothing to do here, CR2 it's not part of the VMCS. */
12110 break;
12111 case 3: /* CR3 */
12112 Assert(!pVM->hm.s.fNestedPaging || !CPUMIsGuestPagingEnabledEx(pMixedCtx) || pVCpu->hm.s.fUsingDebugLoop);
12113 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR3);
12114 Log4(("CRX CR3 write rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr3));
12115 break;
12116 case 4: /* CR4 */
12117 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
12118 Log4(("CRX CR4 write rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n",
12119 VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr4, pVCpu->hm.s.fLoadSaveGuestXcr0));
12120 break;
12121 case 8: /* CR8 */
12122 Assert(!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW));
12123 /* CR8 contains the APIC TPR. Was updated by IEMExecDecodedMovCRxWrite(). */
12124 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
12125 break;
12126 default:
12127 AssertMsgFailed(("Invalid CRx register %#x\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)));
12128 break;
12129 }
12130
12131 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxWrite[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
12132 break;
12133 }
12134
12135 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ: /* MOV from CRx */
12136 {
12137 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12138 AssertRCReturn(rc, rc);
12139
12140 Assert( !pVM->hm.s.fNestedPaging
12141 || !CPUMIsGuestPagingEnabledEx(pMixedCtx)
12142 || pVCpu->hm.s.fUsingDebugLoop
12143 || VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification) != 3);
12144
12145 /* CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
12146 Assert( VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification) != 8
12147 || !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW));
12148
12149 rcStrict = IEMExecDecodedMovCRxRead(pVCpu, pVmxTransient->cbInstr,
12150 VMX_EXIT_QUALIFICATION_CRX_GENREG(uExitQualification),
12151 VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification));
12152 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12153 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxRead[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
12154 Log4(("CRX CR%d Read access rcStrict=%Rrc\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification),
12155 VBOXSTRICTRC_VAL(rcStrict)));
12156 break;
12157 }
12158
12159 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_CLTS: /* CLTS (Clear Task-Switch Flag in CR0) */
12160 {
12161 AssertRCReturn(rc, rc);
12162 rcStrict = IEMExecDecodedClts(pVCpu, pVmxTransient->cbInstr);
12163 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12164 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
12165 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
12166 Log4(("CRX CLTS rcStrict=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
12167 break;
12168 }
12169
12170 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
12171 {
12172 AssertRCReturn(rc, rc);
12173 rcStrict = IEMExecDecodedLmsw(pVCpu, pVmxTransient->cbInstr,
12174 VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(uExitQualification));
12175 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT || rcStrict == VINF_PGM_CHANGE_MODE,
12176 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12177 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
12178 Log4(("CRX LMSW rcStrict=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
12179 break;
12180 }
12181
12182 default:
12183 AssertMsgFailedReturn(("Invalid access-type in Mov CRx VM-exit qualification %#x\n", uAccessType),
12184 VERR_VMX_UNEXPECTED_EXCEPTION);
12185 }
12186
12187 HMCPU_CF_SET(pVCpu, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS : HM_CHANGED_ALL_GUEST);
12188 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
12189 NOREF(pVM);
12190 return rcStrict;
12191}
12192
12193
12194/**
12195 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
12196 * VM-exit.
12197 */
12198HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12199{
12200 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12201 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
12202
12203 int rc2 = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12204 rc2 |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12205 rc2 |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
12206 rc2 |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx); /* Eflag checks in EMInterpretDisasCurrent(). */
12207 rc2 |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx); /* CR0 checks & PGM* in EMInterpretDisasCurrent(). */
12208 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* SELM checks in EMInterpretDisasCurrent(). */
12209 /* EFER also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
12210 AssertRCReturn(rc2, rc2);
12211
12212 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
12213 uint32_t uIOPort = VMX_EXIT_QUALIFICATION_IO_PORT(pVmxTransient->uExitQualification);
12214 uint8_t uIOWidth = VMX_EXIT_QUALIFICATION_IO_WIDTH(pVmxTransient->uExitQualification);
12215 bool fIOWrite = ( VMX_EXIT_QUALIFICATION_IO_DIRECTION(pVmxTransient->uExitQualification)
12216 == VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT);
12217 bool fIOString = VMX_EXIT_QUALIFICATION_IO_IS_STRING(pVmxTransient->uExitQualification);
12218 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
12219 bool fDbgStepping = pVCpu->hm.s.fSingleInstruction;
12220 AssertReturn(uIOWidth <= 3 && uIOWidth != 2, VERR_VMX_IPE_1);
12221
12222 /* I/O operation lookup arrays. */
12223 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses. */
12224 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving the result (in AL/AX/EAX). */
12225
12226 VBOXSTRICTRC rcStrict;
12227 uint32_t const cbValue = s_aIOSizes[uIOWidth];
12228 uint32_t const cbInstr = pVmxTransient->cbInstr;
12229 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
12230 PVM pVM = pVCpu->CTX_SUFF(pVM);
12231 if (fIOString)
12232 {
12233#ifdef VBOX_WITH_2ND_IEM_STEP /* This used to gurus with debian 32-bit guest without NP (on ATA reads).
12234 See @bugref{5752#c158}. Should work now. */
12235 /*
12236 * INS/OUTS - I/O String instruction.
12237 *
12238 * Use instruction-information if available, otherwise fall back on
12239 * interpreting the instruction.
12240 */
12241 Log4(("CS:RIP=%04x:%08RX64 %#06x/%u %c str\n", pMixedCtx->cs.Sel, pMixedCtx->rip, uIOPort, cbValue,
12242 fIOWrite ? 'w' : 'r'));
12243 AssertReturn(pMixedCtx->dx == uIOPort, VERR_VMX_IPE_2);
12244 if (MSR_IA32_VMX_BASIC_INFO_VMCS_INS_OUTS(pVM->hm.s.vmx.Msrs.u64BasicInfo))
12245 {
12246 rc2 = hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12247 /** @todo optimize this, IEM should request the additional state if it needs it (GP, PF, ++). */
12248 rc2 |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12249 AssertRCReturn(rc2, rc2);
12250 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
12251 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
12252 IEMMODE enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
12253 bool fRep = VMX_EXIT_QUALIFICATION_IO_IS_REP(pVmxTransient->uExitQualification);
12254 if (fIOWrite)
12255 {
12256 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
12257 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
12258 }
12259 else
12260 {
12261 /*
12262 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
12263 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
12264 * See Intel Instruction spec. for "INS".
12265 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
12266 */
12267 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
12268 }
12269 }
12270 else
12271 {
12272 /** @todo optimize this, IEM should request the additional state if it needs it (GP, PF, ++). */
12273 rc2 = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12274 AssertRCReturn(rc2, rc2);
12275 rcStrict = IEMExecOne(pVCpu);
12276 }
12277 /** @todo IEM needs to be setting these flags somehow. */
12278 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
12279 fUpdateRipAlready = true;
12280#else
12281 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
12282 rcStrict = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL /* pcbInstr */);
12283 if (RT_SUCCESS(rcStrict))
12284 {
12285 if (fIOWrite)
12286 {
12287 rcStrict = IOMInterpretOUTSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix,
12288 (DISCPUMODE)pDis->uAddrMode, cbValue);
12289 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringWrite);
12290 }
12291 else
12292 {
12293 rcStrict = IOMInterpretINSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix,
12294 (DISCPUMODE)pDis->uAddrMode, cbValue);
12295 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringRead);
12296 }
12297 }
12298 else
12299 {
12300 AssertMsg(rcStrict == VERR_EM_INTERPRETER, ("rcStrict=%Rrc RIP=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict),
12301 pMixedCtx->rip));
12302 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
12303 }
12304#endif
12305 }
12306 else
12307 {
12308 /*
12309 * IN/OUT - I/O instruction.
12310 */
12311 Log4(("CS:RIP=%04x:%08RX64 %#06x/%u %c\n", pMixedCtx->cs.Sel, pMixedCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
12312 uint32_t const uAndVal = s_aIOOpAnd[uIOWidth];
12313 Assert(!VMX_EXIT_QUALIFICATION_IO_IS_REP(pVmxTransient->uExitQualification));
12314 if (fIOWrite)
12315 {
12316 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pMixedCtx->eax & uAndVal, cbValue);
12317 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
12318 }
12319 else
12320 {
12321 uint32_t u32Result = 0;
12322 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
12323 if (IOM_SUCCESS(rcStrict))
12324 {
12325 /* Save result of I/O IN instr. in AL/AX/EAX. */
12326 pMixedCtx->eax = (pMixedCtx->eax & ~uAndVal) | (u32Result & uAndVal);
12327 }
12328 else if (rcStrict == VINF_IOM_R3_IOPORT_READ)
12329 HMR0SavePendingIOPortRead(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbValue);
12330 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
12331 }
12332 }
12333
12334 if (IOM_SUCCESS(rcStrict))
12335 {
12336 if (!fUpdateRipAlready)
12337 {
12338 hmR0VmxAdvanceGuestRipBy(pVCpu, pMixedCtx, cbInstr);
12339 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
12340 }
12341
12342 /*
12343 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru while booting Fedora 17 64-bit guest.
12344 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
12345 */
12346 if (fIOString)
12347 {
12348 /** @todo Single-step for INS/OUTS with REP prefix? */
12349 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
12350 }
12351 else if ( !fDbgStepping
12352 && fGstStepping)
12353 {
12354 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
12355 }
12356
12357 /*
12358 * If any I/O breakpoints are armed, we need to check if one triggered
12359 * and take appropriate action.
12360 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
12361 */
12362 rc2 = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
12363 AssertRCReturn(rc2, rc2);
12364
12365 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
12366 * execution engines about whether hyper BPs and such are pending. */
12367 uint32_t const uDr7 = pMixedCtx->dr[7];
12368 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
12369 && X86_DR7_ANY_RW_IO(uDr7)
12370 && (pMixedCtx->cr4 & X86_CR4_DE))
12371 || DBGFBpIsHwIoArmed(pVM)))
12372 {
12373 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
12374
12375 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
12376 VMMRZCallRing3Disable(pVCpu);
12377 HM_DISABLE_PREEMPT();
12378
12379 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
12380
12381 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pMixedCtx, uIOPort, cbValue);
12382 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
12383 {
12384 /* Raise #DB. */
12385 if (fIsGuestDbgActive)
12386 ASMSetDR6(pMixedCtx->dr[6]);
12387 if (pMixedCtx->dr[7] != uDr7)
12388 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
12389
12390 hmR0VmxSetPendingXcptDB(pVCpu, pMixedCtx);
12391 }
12392 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
12393 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
12394 else if ( rcStrict2 != VINF_SUCCESS
12395 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
12396 rcStrict = rcStrict2;
12397 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
12398
12399 HM_RESTORE_PREEMPT();
12400 VMMRZCallRing3Enable(pVCpu);
12401 }
12402 }
12403
12404#ifdef VBOX_STRICT
12405 if (rcStrict == VINF_IOM_R3_IOPORT_READ)
12406 Assert(!fIOWrite);
12407 else if (rcStrict == VINF_IOM_R3_IOPORT_WRITE || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE)
12408 Assert(fIOWrite);
12409 else
12410 {
12411#if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
12412 * statuses, that the VMM device and some others may return. See
12413 * IOM_SUCCESS() for guidance. */
12414 AssertMsg( RT_FAILURE(rcStrict)
12415 || rcStrict == VINF_SUCCESS
12416 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
12417 || rcStrict == VINF_EM_DBG_BREAKPOINT
12418 || rcStrict == VINF_EM_RAW_GUEST_TRAP
12419 || rcStrict == VINF_EM_RAW_TO_R3
12420 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12421#endif
12422 }
12423#endif
12424
12425 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
12426 return rcStrict;
12427}
12428
12429
12430/**
12431 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
12432 * VM-exit.
12433 */
12434HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12435{
12436 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12437
12438 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
12439 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12440 AssertRCReturn(rc, rc);
12441 if (VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_IDT)
12442 {
12443 rc = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
12444 AssertRCReturn(rc, rc);
12445 if (VMX_IDT_VECTORING_INFO_VALID(pVmxTransient->uIdtVectoringInfo))
12446 {
12447 uint32_t uIntType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
12448
12449 uint32_t uVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
12450 bool fErrorCodeValid = VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo);
12451
12452 /* Save it as a pending event and it'll be converted to a TRPM event on the way out to ring-3. */
12453 Assert(!pVCpu->hm.s.Event.fPending);
12454 pVCpu->hm.s.Event.fPending = true;
12455 pVCpu->hm.s.Event.u64IntInfo = pVmxTransient->uIdtVectoringInfo;
12456 rc = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
12457 AssertRCReturn(rc, rc);
12458 if (fErrorCodeValid)
12459 pVCpu->hm.s.Event.u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
12460 else
12461 pVCpu->hm.s.Event.u32ErrCode = 0;
12462 if ( uIntType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
12463 && uVector == X86_XCPT_PF)
12464 {
12465 pVCpu->hm.s.Event.GCPtrFaultAddress = pMixedCtx->cr2;
12466 }
12467
12468 Log4(("Pending event on TaskSwitch uIntType=%#x uVector=%#x\n", uIntType, uVector));
12469 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
12470 return VINF_EM_RAW_INJECT_TRPM_EVENT;
12471 }
12472 }
12473
12474 /** @todo Emulate task switch someday, currently just going back to ring-3 for
12475 * emulation. */
12476 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
12477 return VERR_EM_INTERPRETER;
12478}
12479
12480
12481/**
12482 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
12483 */
12484HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12485{
12486 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12487 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG);
12488 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG;
12489 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
12490 AssertRCReturn(rc, rc);
12491 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMtf);
12492 return VINF_EM_DBG_STEPPED;
12493}
12494
12495
12496/**
12497 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
12498 */
12499HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12500{
12501 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12502
12503 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
12504 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
12505 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
12506 { /* likely */ }
12507 else
12508 {
12509 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
12510 rcStrict1 = VINF_SUCCESS;
12511 return rcStrict1;
12512 }
12513
12514#if 0
12515 /** @todo Investigate if IOMMMIOPhysHandler() requires a lot of state, for now
12516 * just sync the whole thing. */
12517 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12518#else
12519 /* Aggressive state sync. for now. */
12520 int rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
12521 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12522 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12523#endif
12524 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12525 AssertRCReturn(rc, rc);
12526
12527 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
12528 uint32_t uAccessType = VMX_EXIT_QUALIFICATION_APIC_ACCESS_TYPE(pVmxTransient->uExitQualification);
12529 VBOXSTRICTRC rcStrict2;
12530 switch (uAccessType)
12531 {
12532 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
12533 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
12534 {
12535 AssertMsg( !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
12536 || VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification) != 0x80,
12537 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
12538
12539 RTGCPHYS GCPhys = pMixedCtx->msrApicBase; /* Always up-to-date, msrApicBase is not part of the VMCS. */
12540 GCPhys &= PAGE_BASE_GC_MASK;
12541 GCPhys += VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification);
12542 PVM pVM = pVCpu->CTX_SUFF(pVM);
12543 Log4(("ApicAccess uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
12544 VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification)));
12545
12546 rcStrict2 = IOMMMIOPhysHandler(pVM, pVCpu,
12547 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW,
12548 CPUMCTX2CORE(pMixedCtx), GCPhys);
12549 Log4(("ApicAccess rcStrict2=%d\n", VBOXSTRICTRC_VAL(rcStrict2)));
12550 if ( rcStrict2 == VINF_SUCCESS
12551 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
12552 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
12553 {
12554 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
12555 | HM_CHANGED_GUEST_RSP
12556 | HM_CHANGED_GUEST_RFLAGS
12557 | HM_CHANGED_VMX_GUEST_APIC_STATE);
12558 rcStrict2 = VINF_SUCCESS;
12559 }
12560 break;
12561 }
12562
12563 default:
12564 Log4(("ApicAccess uAccessType=%#x\n", uAccessType));
12565 rcStrict2 = VINF_EM_RAW_EMULATE_INSTR;
12566 break;
12567 }
12568
12569 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
12570 if (rcStrict2 != VINF_SUCCESS)
12571 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
12572 return rcStrict2;
12573}
12574
12575
12576/**
12577 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
12578 * VM-exit.
12579 */
12580HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12581{
12582 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12583
12584 /* We should -not- get this VM-exit if the guest's debug registers were active. */
12585 if (pVmxTransient->fWasGuestDebugStateActive)
12586 {
12587 AssertMsgFailed(("Unexpected MOV DRx exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12588 HMVMX_RETURN_UNEXPECTED_EXIT();
12589 }
12590
12591 if ( !pVCpu->hm.s.fSingleInstruction
12592 && !pVmxTransient->fWasHyperDebugStateActive)
12593 {
12594 Assert(!DBGFIsStepping(pVCpu));
12595 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
12596
12597 /* Don't intercept MOV DRx any more. */
12598 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
12599 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
12600 AssertRCReturn(rc, rc);
12601
12602 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
12603 VMMRZCallRing3Disable(pVCpu);
12604 HM_DISABLE_PREEMPT();
12605
12606 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
12607 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
12608 Assert(CPUMIsGuestDebugStateActive(pVCpu) || HC_ARCH_BITS == 32);
12609
12610 HM_RESTORE_PREEMPT();
12611 VMMRZCallRing3Enable(pVCpu);
12612
12613#ifdef VBOX_WITH_STATISTICS
12614 rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12615 AssertRCReturn(rc, rc);
12616 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
12617 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
12618 else
12619 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
12620#endif
12621 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
12622 return VINF_SUCCESS;
12623 }
12624
12625 /*
12626 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER, CS. EFER is always up-to-date.
12627 * Update the segment registers and DR7 from the CPU.
12628 */
12629 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12630 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12631 rc |= hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
12632 AssertRCReturn(rc, rc);
12633 Log4(("CS:RIP=%04x:%08RX64\n", pMixedCtx->cs.Sel, pMixedCtx->rip));
12634
12635 PVM pVM = pVCpu->CTX_SUFF(pVM);
12636 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
12637 {
12638 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
12639 VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification),
12640 VMX_EXIT_QUALIFICATION_DRX_GENREG(pVmxTransient->uExitQualification));
12641 if (RT_SUCCESS(rc))
12642 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
12643 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
12644 }
12645 else
12646 {
12647 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
12648 VMX_EXIT_QUALIFICATION_DRX_GENREG(pVmxTransient->uExitQualification),
12649 VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification));
12650 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
12651 }
12652
12653 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
12654 if (RT_SUCCESS(rc))
12655 {
12656 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12657 AssertRCReturn(rc2, rc2);
12658 return VINF_SUCCESS;
12659 }
12660 return rc;
12661}
12662
12663
12664/**
12665 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
12666 * Conditional VM-exit.
12667 */
12668HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12669{
12670 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12671 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
12672
12673 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
12674 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
12675 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
12676 { /* likely */ }
12677 else
12678 {
12679 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
12680 rcStrict1 = VINF_SUCCESS;
12681 return rcStrict1;
12682 }
12683
12684 RTGCPHYS GCPhys = 0;
12685 int rc = VMXReadVmcs64(VMX_VMCS64_EXIT_GUEST_PHYS_ADDR_FULL, &GCPhys);
12686
12687#if 0
12688 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx); /** @todo Can we do better? */
12689#else
12690 /* Aggressive state sync. for now. */
12691 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
12692 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12693 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12694#endif
12695 AssertRCReturn(rc, rc);
12696
12697 /*
12698 * If we succeed, resume guest execution.
12699 * If we fail in interpreting the instruction because we couldn't get the guest physical address
12700 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
12701 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
12702 * weird case. See @bugref{6043}.
12703 */
12704 PVM pVM = pVCpu->CTX_SUFF(pVM);
12705 VBOXSTRICTRC rcStrict2 = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pMixedCtx), GCPhys, UINT32_MAX);
12706 Log4(("EPT misconfig at %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pMixedCtx->rip, VBOXSTRICTRC_VAL(rcStrict2)));
12707 if ( rcStrict2 == VINF_SUCCESS
12708 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
12709 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
12710 {
12711 /* Successfully handled MMIO operation. */
12712 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
12713 | HM_CHANGED_GUEST_RSP
12714 | HM_CHANGED_GUEST_RFLAGS
12715 | HM_CHANGED_VMX_GUEST_APIC_STATE);
12716 return VINF_SUCCESS;
12717 }
12718 return rcStrict2;
12719}
12720
12721
12722/**
12723 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
12724 * VM-exit.
12725 */
12726HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12727{
12728 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12729 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
12730
12731 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
12732 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
12733 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
12734 { /* likely */ }
12735 else
12736 {
12737 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
12738 rcStrict1 = VINF_SUCCESS;
12739 return rcStrict1;
12740 }
12741
12742 RTGCPHYS GCPhys = 0;
12743 int rc = VMXReadVmcs64(VMX_VMCS64_EXIT_GUEST_PHYS_ADDR_FULL, &GCPhys);
12744 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12745#if 0
12746 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx); /** @todo Can we do better? */
12747#else
12748 /* Aggressive state sync. for now. */
12749 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
12750 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12751 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12752#endif
12753 AssertRCReturn(rc, rc);
12754
12755 /* Intel spec. Table 27-7 "Exit Qualifications for EPT violations". */
12756 AssertMsg(((pVmxTransient->uExitQualification >> 7) & 3) != 2, ("%#RX64", pVmxTransient->uExitQualification));
12757
12758 RTGCUINT uErrorCode = 0;
12759 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_INSTR_FETCH)
12760 uErrorCode |= X86_TRAP_PF_ID;
12761 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_DATA_WRITE)
12762 uErrorCode |= X86_TRAP_PF_RW;
12763 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_ENTRY_PRESENT)
12764 uErrorCode |= X86_TRAP_PF_P;
12765
12766 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
12767
12768 Log4(("EPT violation %#x at %#RX64 ErrorCode %#x CS:RIP=%04x:%08RX64\n", pVmxTransient->uExitQualification, GCPhys,
12769 uErrorCode, pMixedCtx->cs.Sel, pMixedCtx->rip));
12770
12771 /* Handle the pagefault trap for the nested shadow table. */
12772 PVM pVM = pVCpu->CTX_SUFF(pVM);
12773 VBOXSTRICTRC rcStrict2 = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pMixedCtx), GCPhys);
12774 TRPMResetTrap(pVCpu);
12775
12776 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
12777 if ( rcStrict2 == VINF_SUCCESS
12778 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
12779 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
12780 {
12781 /* Successfully synced our nested page tables. */
12782 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
12783 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
12784 | HM_CHANGED_GUEST_RSP
12785 | HM_CHANGED_GUEST_RFLAGS);
12786 return VINF_SUCCESS;
12787 }
12788
12789 Log4(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)));
12790 return rcStrict2;
12791}
12792
12793/** @} */
12794
12795/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12796/* -=-=-=-=-=-=-=-=-=- VM-exit Exception Handlers -=-=-=-=-=-=-=-=-=-=- */
12797/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-= */
12798
12799/** @name VM-exit exception handlers.
12800 * @{
12801 */
12802
12803/**
12804 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
12805 */
12806static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12807{
12808 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
12809 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
12810
12811 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
12812 AssertRCReturn(rc, rc);
12813
12814 if (!(pMixedCtx->cr0 & X86_CR0_NE))
12815 {
12816 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
12817 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
12818
12819 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
12820 * provides VM-exit instruction length. If this causes problem later,
12821 * disassemble the instruction like it's done on AMD-V. */
12822 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12823 AssertRCReturn(rc2, rc2);
12824 return rc;
12825 }
12826
12827 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
12828 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
12829 return rc;
12830}
12831
12832
12833/**
12834 * VM-exit exception handler for \#BP (Breakpoint exception).
12835 */
12836static int hmR0VmxExitXcptBP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12837{
12838 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
12839 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
12840
12841 /** @todo Try optimize this by not saving the entire guest state unless
12842 * really needed. */
12843 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12844 AssertRCReturn(rc, rc);
12845
12846 PVM pVM = pVCpu->CTX_SUFF(pVM);
12847 rc = DBGFRZTrap03Handler(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
12848 if (rc == VINF_EM_RAW_GUEST_TRAP)
12849 {
12850 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
12851 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12852 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
12853 AssertRCReturn(rc, rc);
12854
12855 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
12856 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
12857 }
12858
12859 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_EM_DBG_BREAKPOINT);
12860 return rc;
12861}
12862
12863
12864/**
12865 * VM-exit exception handler for \#AC (alignment check exception).
12866 */
12867static int hmR0VmxExitXcptAC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12868{
12869 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
12870
12871 /*
12872 * Re-inject it. We'll detect any nesting before getting here.
12873 */
12874 int rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
12875 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12876 AssertRCReturn(rc, rc);
12877 Assert(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO);
12878
12879 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
12880 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
12881 return VINF_SUCCESS;
12882}
12883
12884
12885/**
12886 * VM-exit exception handler for \#DB (Debug exception).
12887 */
12888static int hmR0VmxExitXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12889{
12890 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
12891 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
12892 Log6(("XcptDB\n"));
12893
12894 /*
12895 * Get the DR6-like values from the VM-exit qualification and pass it to DBGF
12896 * for processing.
12897 */
12898 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12899 AssertRCReturn(rc, rc);
12900
12901 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
12902 uint64_t uDR6 = X86_DR6_INIT_VAL;
12903 uDR6 |= ( pVmxTransient->uExitQualification
12904 & (X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3 | X86_DR6_BD | X86_DR6_BS));
12905
12906 rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pMixedCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
12907 if (rc == VINF_EM_RAW_GUEST_TRAP)
12908 {
12909 /*
12910 * The exception was for the guest. Update DR6, DR7.GD and
12911 * IA32_DEBUGCTL.LBR before forwarding it.
12912 * (See Intel spec. 27.1 "Architectural State before a VM-Exit".)
12913 */
12914 VMMRZCallRing3Disable(pVCpu);
12915 HM_DISABLE_PREEMPT();
12916
12917 pMixedCtx->dr[6] &= ~X86_DR6_B_MASK;
12918 pMixedCtx->dr[6] |= uDR6;
12919 if (CPUMIsGuestDebugStateActive(pVCpu))
12920 ASMSetDR6(pMixedCtx->dr[6]);
12921
12922 HM_RESTORE_PREEMPT();
12923 VMMRZCallRing3Enable(pVCpu);
12924
12925 rc = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
12926 AssertRCReturn(rc, rc);
12927
12928 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
12929 pMixedCtx->dr[7] &= ~X86_DR7_GD;
12930
12931 /* Paranoia. */
12932 pMixedCtx->dr[7] &= ~X86_DR7_RAZ_MASK;
12933 pMixedCtx->dr[7] |= X86_DR7_RA1_MASK;
12934
12935 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, (uint32_t)pMixedCtx->dr[7]);
12936 AssertRCReturn(rc, rc);
12937
12938 /*
12939 * Raise #DB in the guest.
12940 *
12941 * It is important to reflect what the VM-exit gave us (preserving the interruption-type) rather than use
12942 * hmR0VmxSetPendingXcptDB() as the #DB could've been raised while executing ICEBP and not the 'normal' #DB.
12943 * Thus it -may- trigger different handling in the CPU (like skipped DPL checks). See @bugref{6398}.
12944 *
12945 * Since ICEBP isn't documented on Intel, see AMD spec. 15.20 "Event Injection".
12946 */
12947 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
12948 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12949 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
12950 AssertRCReturn(rc, rc);
12951 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
12952 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
12953 return VINF_SUCCESS;
12954 }
12955
12956 /*
12957 * Not a guest trap, must be a hypervisor related debug event then.
12958 * Update DR6 in case someone is interested in it.
12959 */
12960 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
12961 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
12962 CPUMSetHyperDR6(pVCpu, uDR6);
12963
12964 return rc;
12965}
12966
12967
12968/**
12969 * VM-exit exception handler for \#NM (Device-not-available exception: floating
12970 * point exception).
12971 */
12972static int hmR0VmxExitXcptNM(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12973{
12974 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
12975
12976 /* We require CR0 and EFER. EFER is always up-to-date. */
12977 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
12978 AssertRCReturn(rc, rc);
12979
12980 /* We're playing with the host CPU state here, have to disable preemption or longjmp. */
12981 VMMRZCallRing3Disable(pVCpu);
12982 HM_DISABLE_PREEMPT();
12983
12984 /* If the guest FPU was active at the time of the #NM exit, then it's a guest fault. */
12985 if (pVmxTransient->fWasGuestFPUStateActive)
12986 {
12987 rc = VINF_EM_RAW_GUEST_TRAP;
12988 Assert(CPUMIsGuestFPUStateActive(pVCpu) || HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0));
12989 }
12990 else
12991 {
12992#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
12993 Assert(!pVmxTransient->fWasGuestFPUStateActive || pVCpu->hm.s.fUsingDebugLoop);
12994#endif
12995 rc = CPUMR0Trap07Handler(pVCpu->CTX_SUFF(pVM), pVCpu, pMixedCtx);
12996 Assert(rc == VINF_EM_RAW_GUEST_TRAP || (rc == VINF_SUCCESS && CPUMIsGuestFPUStateActive(pVCpu)));
12997 }
12998
12999 HM_RESTORE_PREEMPT();
13000 VMMRZCallRing3Enable(pVCpu);
13001
13002 if (rc == VINF_SUCCESS)
13003 {
13004 /* Guest FPU state was activated, we'll want to change CR0 FPU intercepts before the next VM-reentry. */
13005 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
13006 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowNM);
13007 pVCpu->hm.s.fPreloadGuestFpu = true;
13008 }
13009 else
13010 {
13011 /* Forward #NM to the guest. */
13012 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
13013 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13014 AssertRCReturn(rc, rc);
13015 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13016 pVmxTransient->cbInstr, 0 /* error code */, 0 /* GCPtrFaultAddress */);
13017 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNM);
13018 }
13019
13020 return VINF_SUCCESS;
13021}
13022
13023
13024/**
13025 * VM-exit exception handler for \#GP (General-protection exception).
13026 *
13027 * @remarks Requires pVmxTransient->uExitIntInfo to be up-to-date.
13028 */
13029static int hmR0VmxExitXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13030{
13031 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13032 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
13033
13034 int rc;
13035 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
13036 { /* likely */ }
13037 else
13038 {
13039#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13040 Assert(pVCpu->hm.s.fUsingDebugLoop);
13041#endif
13042 /* If the guest is not in real-mode or we have unrestricted execution support, reflect #GP to the guest. */
13043 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13044 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13045 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13046 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13047 AssertRCReturn(rc, rc);
13048 Log4(("#GP Gst: CS:RIP %04x:%08RX64 ErrorCode=%#x CR0=%#RX64 CPL=%u TR=%#04x\n", pMixedCtx->cs.Sel, pMixedCtx->rip,
13049 pVmxTransient->uExitIntErrorCode, pMixedCtx->cr0, CPUMGetGuestCPL(pVCpu), pMixedCtx->tr.Sel));
13050 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13051 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13052 return rc;
13053 }
13054
13055 Assert(CPUMIsGuestInRealModeEx(pMixedCtx));
13056 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
13057
13058 /* EMInterpretDisasCurrent() requires a lot of the state, save the entire state. */
13059 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13060 AssertRCReturn(rc, rc);
13061
13062 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
13063 uint32_t cbOp = 0;
13064 PVM pVM = pVCpu->CTX_SUFF(pVM);
13065 bool fDbgStepping = pVCpu->hm.s.fSingleInstruction;
13066 rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, &cbOp);
13067 if (RT_SUCCESS(rc))
13068 {
13069 rc = VINF_SUCCESS;
13070 Assert(cbOp == pDis->cbInstr);
13071 Log4(("#GP Disas OpCode=%u CS:EIP %04x:%04RX64\n", pDis->pCurInstr->uOpcode, pMixedCtx->cs.Sel, pMixedCtx->rip));
13072 switch (pDis->pCurInstr->uOpcode)
13073 {
13074 case OP_CLI:
13075 {
13076 pMixedCtx->eflags.Bits.u1IF = 0;
13077 pMixedCtx->eflags.Bits.u1RF = 0;
13078 pMixedCtx->rip += pDis->cbInstr;
13079 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13080 if ( !fDbgStepping
13081 && pMixedCtx->eflags.Bits.u1TF)
13082 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13083 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCli);
13084 break;
13085 }
13086
13087 case OP_STI:
13088 {
13089 bool fOldIF = pMixedCtx->eflags.Bits.u1IF;
13090 pMixedCtx->eflags.Bits.u1IF = 1;
13091 pMixedCtx->eflags.Bits.u1RF = 0;
13092 pMixedCtx->rip += pDis->cbInstr;
13093 if (!fOldIF)
13094 {
13095 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
13096 Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
13097 }
13098 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13099 if ( !fDbgStepping
13100 && pMixedCtx->eflags.Bits.u1TF)
13101 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13102 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitSti);
13103 break;
13104 }
13105
13106 case OP_HLT:
13107 {
13108 rc = VINF_EM_HALT;
13109 pMixedCtx->rip += pDis->cbInstr;
13110 pMixedCtx->eflags.Bits.u1RF = 0;
13111 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13112 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
13113 break;
13114 }
13115
13116 case OP_POPF:
13117 {
13118 Log4(("POPF CS:EIP %04x:%04RX64\n", pMixedCtx->cs.Sel, pMixedCtx->rip));
13119 uint32_t cbParm;
13120 uint32_t uMask;
13121 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
13122 if (pDis->fPrefix & DISPREFIX_OPSIZE)
13123 {
13124 cbParm = 4;
13125 uMask = 0xffffffff;
13126 }
13127 else
13128 {
13129 cbParm = 2;
13130 uMask = 0xffff;
13131 }
13132
13133 /* Get the stack pointer & pop the contents of the stack onto Eflags. */
13134 RTGCPTR GCPtrStack = 0;
13135 X86EFLAGS Eflags;
13136 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
13137 &GCPtrStack);
13138 if (RT_SUCCESS(rc))
13139 {
13140 Assert(sizeof(Eflags.u32) >= cbParm);
13141 Eflags.u32 = 0;
13142 rc = VBOXSTRICTRC_TODO(PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &Eflags.u32, cbParm, PGMACCESSORIGIN_HM));
13143 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc)); /** @todo allow strict return codes here */
13144 }
13145 if (RT_FAILURE(rc))
13146 {
13147 rc = VERR_EM_INTERPRETER;
13148 break;
13149 }
13150 Log4(("POPF %#x -> %#RX64 mask=%#x RIP=%#RX64\n", Eflags.u, pMixedCtx->rsp, uMask, pMixedCtx->rip));
13151 pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ~((X86_EFL_POPF_BITS & uMask) | X86_EFL_RF))
13152 | (Eflags.u32 & X86_EFL_POPF_BITS & uMask);
13153 pMixedCtx->esp += cbParm;
13154 pMixedCtx->esp &= uMask;
13155 pMixedCtx->rip += pDis->cbInstr;
13156 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13157 | HM_CHANGED_GUEST_RSP
13158 | HM_CHANGED_GUEST_RFLAGS);
13159 /* Generate a pending-debug exception when the guest stepping over POPF regardless of how
13160 POPF restores EFLAGS.TF. */
13161 if ( !fDbgStepping
13162 && fGstStepping)
13163 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13164 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPopf);
13165 break;
13166 }
13167
13168 case OP_PUSHF:
13169 {
13170 uint32_t cbParm;
13171 uint32_t uMask;
13172 if (pDis->fPrefix & DISPREFIX_OPSIZE)
13173 {
13174 cbParm = 4;
13175 uMask = 0xffffffff;
13176 }
13177 else
13178 {
13179 cbParm = 2;
13180 uMask = 0xffff;
13181 }
13182
13183 /* Get the stack pointer & push the contents of eflags onto the stack. */
13184 RTGCPTR GCPtrStack = 0;
13185 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), (pMixedCtx->esp - cbParm) & uMask,
13186 SELMTOFLAT_FLAGS_CPL0, &GCPtrStack);
13187 if (RT_FAILURE(rc))
13188 {
13189 rc = VERR_EM_INTERPRETER;
13190 break;
13191 }
13192 X86EFLAGS Eflags = pMixedCtx->eflags;
13193 /* The RF & VM bits are cleared on image stored on stack; see Intel Instruction reference for PUSHF. */
13194 Eflags.Bits.u1RF = 0;
13195 Eflags.Bits.u1VM = 0;
13196
13197 rc = VBOXSTRICTRC_TODO(PGMPhysWrite(pVM, (RTGCPHYS)GCPtrStack, &Eflags.u, cbParm, PGMACCESSORIGIN_HM));
13198 if (RT_UNLIKELY(rc != VINF_SUCCESS))
13199 {
13200 AssertMsgFailed(("%Rrc\n", rc)); /** @todo allow strict return codes here */
13201 rc = VERR_EM_INTERPRETER;
13202 break;
13203 }
13204 Log4(("PUSHF %#x -> %#RGv\n", Eflags.u, GCPtrStack));
13205 pMixedCtx->esp -= cbParm;
13206 pMixedCtx->esp &= uMask;
13207 pMixedCtx->rip += pDis->cbInstr;
13208 pMixedCtx->eflags.Bits.u1RF = 0;
13209 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13210 | HM_CHANGED_GUEST_RSP
13211 | HM_CHANGED_GUEST_RFLAGS);
13212 if ( !fDbgStepping
13213 && pMixedCtx->eflags.Bits.u1TF)
13214 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13215 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPushf);
13216 break;
13217 }
13218
13219 case OP_IRET:
13220 {
13221 /** @todo Handle 32-bit operand sizes and check stack limits. See Intel
13222 * instruction reference. */
13223 RTGCPTR GCPtrStack = 0;
13224 uint32_t uMask = 0xffff;
13225 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
13226 uint16_t aIretFrame[3];
13227 if (pDis->fPrefix & (DISPREFIX_OPSIZE | DISPREFIX_ADDRSIZE))
13228 {
13229 rc = VERR_EM_INTERPRETER;
13230 break;
13231 }
13232 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
13233 &GCPtrStack);
13234 if (RT_SUCCESS(rc))
13235 {
13236 rc = VBOXSTRICTRC_TODO(PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &aIretFrame[0], sizeof(aIretFrame),
13237 PGMACCESSORIGIN_HM));
13238 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc)); /** @todo allow strict return codes here */
13239 }
13240 if (RT_FAILURE(rc))
13241 {
13242 rc = VERR_EM_INTERPRETER;
13243 break;
13244 }
13245 pMixedCtx->eip = 0;
13246 pMixedCtx->ip = aIretFrame[0];
13247 pMixedCtx->cs.Sel = aIretFrame[1];
13248 pMixedCtx->cs.ValidSel = aIretFrame[1];
13249 pMixedCtx->cs.u64Base = (uint64_t)pMixedCtx->cs.Sel << 4;
13250 pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ((UINT32_C(0xffff0000) | X86_EFL_1) & ~X86_EFL_RF))
13251 | (aIretFrame[2] & X86_EFL_POPF_BITS & uMask);
13252 pMixedCtx->sp += sizeof(aIretFrame);
13253 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13254 | HM_CHANGED_GUEST_SEGMENT_REGS
13255 | HM_CHANGED_GUEST_RSP
13256 | HM_CHANGED_GUEST_RFLAGS);
13257 /* Generate a pending-debug exception when stepping over IRET regardless of how IRET modifies EFLAGS.TF. */
13258 if ( !fDbgStepping
13259 && fGstStepping)
13260 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13261 Log4(("IRET %#RX32 to %04x:%04x\n", GCPtrStack, pMixedCtx->cs.Sel, pMixedCtx->ip));
13262 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIret);
13263 break;
13264 }
13265
13266 case OP_INT:
13267 {
13268 uint16_t uVector = pDis->Param1.uValue & 0xff;
13269 hmR0VmxSetPendingIntN(pVCpu, pMixedCtx, uVector, pDis->cbInstr);
13270 /* INT clears EFLAGS.TF, we must not set any pending debug exceptions here. */
13271 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
13272 break;
13273 }
13274
13275 case OP_INTO:
13276 {
13277 if (pMixedCtx->eflags.Bits.u1OF)
13278 {
13279 hmR0VmxSetPendingXcptOF(pVCpu, pMixedCtx, pDis->cbInstr);
13280 /* INTO clears EFLAGS.TF, we must not set any pending debug exceptions here. */
13281 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
13282 }
13283 else
13284 {
13285 pMixedCtx->eflags.Bits.u1RF = 0;
13286 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
13287 }
13288 break;
13289 }
13290
13291 default:
13292 {
13293 pMixedCtx->eflags.Bits.u1RF = 0; /* This is correct most of the time... */
13294 VBOXSTRICTRC rc2 = EMInterpretInstructionDisasState(pVCpu, pDis, CPUMCTX2CORE(pMixedCtx), 0 /* pvFault */,
13295 EMCODETYPE_SUPERVISOR);
13296 rc = VBOXSTRICTRC_VAL(rc2);
13297 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
13298 /** @todo We have to set pending-debug exceptions here when the guest is
13299 * single-stepping depending on the instruction that was interpreted. */
13300 Log4(("#GP rc=%Rrc\n", rc));
13301 break;
13302 }
13303 }
13304 }
13305 else
13306 rc = VERR_EM_INTERPRETER;
13307
13308 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_EM_HALT,
13309 ("#GP Unexpected rc=%Rrc\n", rc));
13310 return rc;
13311}
13312
13313
13314/**
13315 * VM-exit exception handler wrapper for generic exceptions. Simply re-injects
13316 * the exception reported in the VMX transient structure back into the VM.
13317 *
13318 * @remarks Requires uExitIntInfo in the VMX transient structure to be
13319 * up-to-date.
13320 */
13321static int hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13322{
13323 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13324#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13325 Assert(pVCpu->hm.s.fUsingDebugLoop);
13326#endif
13327
13328 /* Re-inject the exception into the guest. This cannot be a double-fault condition which would have been handled in
13329 hmR0VmxCheckExitDueToEventDelivery(). */
13330 int rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13331 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13332 AssertRCReturn(rc, rc);
13333 Assert(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO);
13334
13335#ifdef DEBUG_ramshankar
13336 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
13337 uint8_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13338 Log(("hmR0VmxExitXcptGeneric: Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
13339#endif
13340
13341 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13342 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13343 return VINF_SUCCESS;
13344}
13345
13346
13347/**
13348 * VM-exit exception handler for \#PF (Page-fault exception).
13349 */
13350static int hmR0VmxExitXcptPF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13351{
13352 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13353 PVM pVM = pVCpu->CTX_SUFF(pVM);
13354 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
13355 rc |= hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13356 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13357 AssertRCReturn(rc, rc);
13358
13359 if (!pVM->hm.s.fNestedPaging)
13360 { /* likely */ }
13361 else
13362 {
13363#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13364 Assert(pVCpu->hm.s.fUsingDebugLoop);
13365#endif
13366 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13367 if (RT_LIKELY(!pVmxTransient->fVectoringDoublePF))
13368 {
13369 pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
13370 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13371 0 /* cbInstr */, pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQualification);
13372 }
13373 else
13374 {
13375 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13376 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
13377 Log4(("Pending #DF due to vectoring #PF. NP\n"));
13378 }
13379 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13380 return rc;
13381 }
13382
13383 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13384 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13385 if (pVmxTransient->fVectoringPF)
13386 {
13387 Assert(pVCpu->hm.s.Event.fPending);
13388 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13389 }
13390
13391 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13392 AssertRCReturn(rc, rc);
13393
13394 Log4(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQualification,
13395 pMixedCtx->cs.Sel, pMixedCtx->rip, pVmxTransient->uExitIntErrorCode, pMixedCtx->cr3));
13396
13397 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQualification, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13398 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pMixedCtx),
13399 (RTGCPTR)pVmxTransient->uExitQualification);
13400
13401 Log4(("#PF: rc=%Rrc\n", rc));
13402 if (rc == VINF_SUCCESS)
13403 {
13404 /* Successfully synced shadow pages tables or emulated an MMIO instruction. */
13405 /** @todo this isn't quite right, what if guest does lgdt with some MMIO
13406 * memory? We don't update the whole state here... */
13407 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13408 | HM_CHANGED_GUEST_RSP
13409 | HM_CHANGED_GUEST_RFLAGS
13410 | HM_CHANGED_VMX_GUEST_APIC_STATE);
13411 TRPMResetTrap(pVCpu);
13412 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
13413 return rc;
13414 }
13415
13416 if (rc == VINF_EM_RAW_GUEST_TRAP)
13417 {
13418 if (!pVmxTransient->fVectoringDoublePF)
13419 {
13420 /* It's a guest page fault and needs to be reflected to the guest. */
13421 uint32_t uGstErrorCode = TRPMGetErrorCode(pVCpu);
13422 TRPMResetTrap(pVCpu);
13423 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
13424 pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
13425 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13426 0 /* cbInstr */, uGstErrorCode, pVmxTransient->uExitQualification);
13427 }
13428 else
13429 {
13430 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13431 TRPMResetTrap(pVCpu);
13432 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
13433 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
13434 Log4(("#PF: Pending #DF due to vectoring #PF\n"));
13435 }
13436
13437 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13438 return VINF_SUCCESS;
13439 }
13440
13441 TRPMResetTrap(pVCpu);
13442 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
13443 return rc;
13444}
13445
13446/** @} */
13447
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