VirtualBox

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

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

VMM/HMVMXR0: Build fix for r115095.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 596.7 KB
Line 
1/* $Id: HMVMXR0.cpp 66705 2017-04-27 17:33:48Z vboxsync $ */
2/** @file
3 * HM VMX (Intel VT-x) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2012-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_HM
23#include <iprt/x86.h>
24#include <iprt/asm-amd64-x86.h>
25#include <iprt/thread.h>
26
27#include <VBox/vmm/pdmapi.h>
28#include <VBox/vmm/dbgf.h>
29#include <VBox/vmm/iem.h>
30#include <VBox/vmm/iom.h>
31#include <VBox/vmm/selm.h>
32#include <VBox/vmm/tm.h>
33#include <VBox/vmm/gim.h>
34#include <VBox/vmm/apic.h>
35#ifdef VBOX_WITH_REM
36# include <VBox/vmm/rem.h>
37#endif
38#include "HMInternal.h"
39#include <VBox/vmm/vm.h>
40#include "HMVMXR0.h"
41#include "dtrace/VBoxVMM.h"
42
43#ifdef DEBUG_ramshankar
44# define HMVMX_ALWAYS_SAVE_GUEST_RFLAGS
45# define HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE
46# define HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
47# define HMVMX_ALWAYS_CHECK_GUEST_STATE
48# define HMVMX_ALWAYS_TRAP_ALL_XCPTS
49# define HMVMX_ALWAYS_TRAP_PF
50# define HMVMX_ALWAYS_SWAP_FPU_STATE
51# define HMVMX_ALWAYS_FLUSH_TLB
52# define HMVMX_ALWAYS_SWAP_EFER
53#endif
54
55
56/*********************************************************************************************************************************
57* Defined Constants And Macros *
58*********************************************************************************************************************************/
59/** Use the function table. */
60#define HMVMX_USE_FUNCTION_TABLE
61
62/** Determine which tagged-TLB flush handler to use. */
63#define HMVMX_FLUSH_TAGGED_TLB_EPT_VPID 0
64#define HMVMX_FLUSH_TAGGED_TLB_EPT 1
65#define HMVMX_FLUSH_TAGGED_TLB_VPID 2
66#define HMVMX_FLUSH_TAGGED_TLB_NONE 3
67
68/** @name Updated-guest-state flags.
69 * @{ */
70#define HMVMX_UPDATED_GUEST_RIP RT_BIT(0)
71#define HMVMX_UPDATED_GUEST_RSP RT_BIT(1)
72#define HMVMX_UPDATED_GUEST_RFLAGS RT_BIT(2)
73#define HMVMX_UPDATED_GUEST_CR0 RT_BIT(3)
74#define HMVMX_UPDATED_GUEST_CR3 RT_BIT(4)
75#define HMVMX_UPDATED_GUEST_CR4 RT_BIT(5)
76#define HMVMX_UPDATED_GUEST_GDTR RT_BIT(6)
77#define HMVMX_UPDATED_GUEST_IDTR RT_BIT(7)
78#define HMVMX_UPDATED_GUEST_LDTR RT_BIT(8)
79#define HMVMX_UPDATED_GUEST_TR RT_BIT(9)
80#define HMVMX_UPDATED_GUEST_SEGMENT_REGS RT_BIT(10)
81#define HMVMX_UPDATED_GUEST_DR7 RT_BIT(11)
82#define HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR RT_BIT(12)
83#define HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR RT_BIT(13)
84#define HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR RT_BIT(14)
85#define HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS RT_BIT(15)
86#define HMVMX_UPDATED_GUEST_LAZY_MSRS RT_BIT(16)
87#define HMVMX_UPDATED_GUEST_ACTIVITY_STATE RT_BIT(17)
88#define HMVMX_UPDATED_GUEST_INTR_STATE RT_BIT(18)
89#define HMVMX_UPDATED_GUEST_APIC_STATE RT_BIT(19)
90#define HMVMX_UPDATED_GUEST_ALL ( HMVMX_UPDATED_GUEST_RIP \
91 | HMVMX_UPDATED_GUEST_RSP \
92 | HMVMX_UPDATED_GUEST_RFLAGS \
93 | HMVMX_UPDATED_GUEST_CR0 \
94 | HMVMX_UPDATED_GUEST_CR3 \
95 | HMVMX_UPDATED_GUEST_CR4 \
96 | HMVMX_UPDATED_GUEST_GDTR \
97 | HMVMX_UPDATED_GUEST_IDTR \
98 | HMVMX_UPDATED_GUEST_LDTR \
99 | HMVMX_UPDATED_GUEST_TR \
100 | HMVMX_UPDATED_GUEST_SEGMENT_REGS \
101 | HMVMX_UPDATED_GUEST_DR7 \
102 | HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR \
103 | HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR \
104 | HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR \
105 | HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS \
106 | HMVMX_UPDATED_GUEST_LAZY_MSRS \
107 | HMVMX_UPDATED_GUEST_ACTIVITY_STATE \
108 | HMVMX_UPDATED_GUEST_INTR_STATE \
109 | HMVMX_UPDATED_GUEST_APIC_STATE)
110/** @} */
111
112/** @name
113 * Flags to skip redundant reads of some common VMCS fields that are not part of
114 * the guest-CPU state but are in the transient structure.
115 */
116#define HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO RT_BIT(0)
117#define HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE RT_BIT(1)
118#define HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION RT_BIT(2)
119#define HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN RT_BIT(3)
120#define HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO RT_BIT(4)
121#define HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE RT_BIT(5)
122#define HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_INFO RT_BIT(6)
123/** @} */
124
125/** @name
126 * States of the VMCS.
127 *
128 * This does not reflect all possible VMCS states but currently only those
129 * needed for maintaining the VMCS consistently even when thread-context hooks
130 * are used. Maybe later this can be extended (i.e. Nested Virtualization).
131 */
132#define HMVMX_VMCS_STATE_CLEAR RT_BIT(0)
133#define HMVMX_VMCS_STATE_ACTIVE RT_BIT(1)
134#define HMVMX_VMCS_STATE_LAUNCHED RT_BIT(2)
135/** @} */
136
137/**
138 * Exception bitmap mask for real-mode guests (real-on-v86).
139 *
140 * We need to intercept all exceptions manually except:
141 * - \#NM, \#MF handled in hmR0VmxLoadSharedCR0().
142 * - \#AC and \#DB are always intercepted to prevent the CPU from deadlocking
143 * due to bugs in Intel CPUs.
144 * - \#PF need not be intercepted even in real-mode if we have Nested Paging
145 * support.
146 */
147#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) /* always: | RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI) \
148 | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
149 | RT_BIT(X86_XCPT_UD) /* RT_BIT(X86_XCPT_NM) */ | RT_BIT(X86_XCPT_DF) \
150 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
151 | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
152 /* RT_BIT(X86_XCPT_MF) always: | RT_BIT(X86_XCPT_AC) */ | RT_BIT(X86_XCPT_MC) \
153 | RT_BIT(X86_XCPT_XF))
154
155/**
156 * Exception bitmap mask for all contributory exceptions.
157 *
158 * Page fault is deliberately excluded here as it's conditional as to whether
159 * it's contributory or benign. Page faults are handled separately.
160 */
161#define HMVMX_CONTRIBUTORY_XCPT_MASK ( RT_BIT(X86_XCPT_GP) | RT_BIT(X86_XCPT_NP) | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_TS) \
162 | RT_BIT(X86_XCPT_DE))
163
164/** Maximum VM-instruction error number. */
165#define HMVMX_INSTR_ERROR_MAX 28
166
167/** Profiling macro. */
168#ifdef HM_PROFILE_EXIT_DISPATCH
169# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitDispatch, ed)
170# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitDispatch, ed)
171#else
172# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
173# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
174#endif
175
176/** Assert that preemption is disabled or covered by thread-context hooks. */
177#define HMVMX_ASSERT_PREEMPT_SAFE() Assert( VMMR0ThreadCtxHookIsEnabled(pVCpu) \
178 || !RTThreadPreemptIsEnabled(NIL_RTTHREAD));
179
180/** Assert that we haven't migrated CPUs when thread-context hooks are not
181 * used. */
182#define HMVMX_ASSERT_CPU_SAFE() AssertMsg( VMMR0ThreadCtxHookIsEnabled(pVCpu) \
183 || pVCpu->hm.s.idEnteredCpu == RTMpCpuId(), \
184 ("Illegal migration! Entered on CPU %u Current %u\n", \
185 pVCpu->hm.s.idEnteredCpu, RTMpCpuId())); \
186
187/** Helper macro for VM-exit handlers called unexpectedly. */
188#define HMVMX_RETURN_UNEXPECTED_EXIT() \
189 do { \
190 pVCpu->hm.s.u32HMError = pVmxTransient->uExitReason; \
191 return VERR_VMX_UNEXPECTED_EXIT; \
192 } while (0)
193
194
195/*********************************************************************************************************************************
196* Structures and Typedefs *
197*********************************************************************************************************************************/
198/**
199 * VMX transient state.
200 *
201 * A state structure for holding miscellaneous information across
202 * VMX non-root operation and restored after the transition.
203 */
204typedef struct VMXTRANSIENT
205{
206 /** The host's rflags/eflags. */
207 RTCCUINTREG fEFlags;
208#if HC_ARCH_BITS == 32
209 uint32_t u32Alignment0;
210#endif
211 /** The guest's TPR value used for TPR shadowing. */
212 uint8_t u8GuestTpr;
213 /** Alignment. */
214 uint8_t abAlignment0[7];
215
216 /** The basic VM-exit reason. */
217 uint16_t uExitReason;
218 /** Alignment. */
219 uint16_t u16Alignment0;
220 /** The VM-exit interruption error code. */
221 uint32_t uExitIntErrorCode;
222 /** The VM-exit exit code qualification. */
223 uint64_t uExitQualification;
224
225 /** The VM-exit interruption-information field. */
226 uint32_t uExitIntInfo;
227 /** The VM-exit instruction-length field. */
228 uint32_t cbInstr;
229 /** The VM-exit instruction-information field. */
230 union
231 {
232 /** Plain unsigned int representation. */
233 uint32_t u;
234 /** INS and OUTS information. */
235 struct
236 {
237 uint32_t u7Reserved0 : 7;
238 /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */
239 uint32_t u3AddrSize : 3;
240 uint32_t u5Reserved1 : 5;
241 /** The segment register (X86_SREG_XXX). */
242 uint32_t iSegReg : 3;
243 uint32_t uReserved2 : 14;
244 } StrIo;
245 } ExitInstrInfo;
246 /** Whether the VM-entry failed or not. */
247 bool fVMEntryFailed;
248 /** Alignment. */
249 uint8_t abAlignment1[3];
250
251 /** The VM-entry interruption-information field. */
252 uint32_t uEntryIntInfo;
253 /** The VM-entry exception error code field. */
254 uint32_t uEntryXcptErrorCode;
255 /** The VM-entry instruction length field. */
256 uint32_t cbEntryInstr;
257
258 /** IDT-vectoring information field. */
259 uint32_t uIdtVectoringInfo;
260 /** IDT-vectoring error code. */
261 uint32_t uIdtVectoringErrorCode;
262
263 /** Mask of currently read VMCS fields; HMVMX_UPDATED_TRANSIENT_*. */
264 uint32_t fVmcsFieldsRead;
265
266 /** Whether the guest FPU was active at the time of VM-exit. */
267 bool fWasGuestFPUStateActive;
268 /** Whether the guest debug state was active at the time of VM-exit. */
269 bool fWasGuestDebugStateActive;
270 /** Whether the hyper debug state was active at the time of VM-exit. */
271 bool fWasHyperDebugStateActive;
272 /** Whether TSC-offsetting should be setup before VM-entry. */
273 bool fUpdateTscOffsettingAndPreemptTimer;
274 /** Whether the VM-exit was caused by a page-fault during delivery of a
275 * contributory exception or a page-fault. */
276 bool fVectoringDoublePF;
277 /** Whether the VM-exit was caused by a page-fault during delivery of an
278 * external interrupt or NMI. */
279 bool fVectoringPF;
280} VMXTRANSIENT;
281AssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, sizeof(uint64_t));
282AssertCompileMemberAlignment(VMXTRANSIENT, uExitIntInfo, sizeof(uint64_t));
283AssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntInfo, sizeof(uint64_t));
284AssertCompileMemberAlignment(VMXTRANSIENT, fWasGuestFPUStateActive, sizeof(uint64_t));
285AssertCompileMemberSize(VMXTRANSIENT, ExitInstrInfo, sizeof(uint32_t));
286/** Pointer to VMX transient state. */
287typedef VMXTRANSIENT *PVMXTRANSIENT;
288
289
290/**
291 * MSR-bitmap read permissions.
292 */
293typedef enum VMXMSREXITREAD
294{
295 /** Reading this MSR causes a VM-exit. */
296 VMXMSREXIT_INTERCEPT_READ = 0xb,
297 /** Reading this MSR does not cause a VM-exit. */
298 VMXMSREXIT_PASSTHRU_READ
299} VMXMSREXITREAD;
300/** Pointer to MSR-bitmap read permissions. */
301typedef VMXMSREXITREAD* PVMXMSREXITREAD;
302
303/**
304 * MSR-bitmap write permissions.
305 */
306typedef enum VMXMSREXITWRITE
307{
308 /** Writing to this MSR causes a VM-exit. */
309 VMXMSREXIT_INTERCEPT_WRITE = 0xd,
310 /** Writing to this MSR does not cause a VM-exit. */
311 VMXMSREXIT_PASSTHRU_WRITE
312} VMXMSREXITWRITE;
313/** Pointer to MSR-bitmap write permissions. */
314typedef VMXMSREXITWRITE* PVMXMSREXITWRITE;
315
316
317/**
318 * VMX VM-exit handler.
319 *
320 * @returns Strict VBox status code (i.e. informational status codes too).
321 * @param pVCpu The cross context virtual CPU structure.
322 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
323 * out-of-sync. Make sure to update the required
324 * fields before using them.
325 * @param pVmxTransient Pointer to the VMX-transient structure.
326 */
327#ifndef HMVMX_USE_FUNCTION_TABLE
328typedef VBOXSTRICTRC FNVMXEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
329#else
330typedef DECLCALLBACK(VBOXSTRICTRC) FNVMXEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
331/** Pointer to VM-exit handler. */
332typedef FNVMXEXITHANDLER *PFNVMXEXITHANDLER;
333#endif
334
335/**
336 * VMX VM-exit handler, non-strict status code.
337 *
338 * This is generally the same as FNVMXEXITHANDLER, the NSRC bit is just FYI.
339 *
340 * @returns VBox status code, no informational status code returned.
341 * @param pVCpu The cross context virtual CPU structure.
342 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
343 * out-of-sync. Make sure to update the required
344 * fields before using them.
345 * @param pVmxTransient Pointer to the VMX-transient structure.
346 *
347 * @remarks This is not used on anything returning VERR_EM_INTERPRETER as the
348 * use of that status code will be replaced with VINF_EM_SOMETHING
349 * later when switching over to IEM.
350 */
351#ifndef HMVMX_USE_FUNCTION_TABLE
352typedef int FNVMXEXITHANDLERNSRC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
353#else
354typedef FNVMXEXITHANDLER FNVMXEXITHANDLERNSRC;
355#endif
356
357
358/*********************************************************************************************************************************
359* Internal Functions *
360*********************************************************************************************************************************/
361static void hmR0VmxFlushEpt(PVMCPU pVCpu, VMXFLUSHEPT enmFlush);
362static void hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMXFLUSHVPID enmFlush, RTGCPTR GCPtr);
363static void hmR0VmxClearIntNmiWindowsVmcs(PVMCPU pVCpu);
364static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
365 uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress,
366 bool fStepping, uint32_t *puIntState);
367#if HC_ARCH_BITS == 32
368static int hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu);
369#endif
370#ifndef HMVMX_USE_FUNCTION_TABLE
371DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason);
372# define HMVMX_EXIT_DECL DECLINLINE(VBOXSTRICTRC)
373# define HMVMX_EXIT_NSRC_DECL DECLINLINE(int)
374#else
375# define HMVMX_EXIT_DECL static DECLCALLBACK(VBOXSTRICTRC)
376# define HMVMX_EXIT_NSRC_DECL HMVMX_EXIT_DECL
377#endif
378
379
380/** @name VM-exit handlers.
381 * @{
382 */
383static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmi;
384static FNVMXEXITHANDLER hmR0VmxExitExtInt;
385static FNVMXEXITHANDLER hmR0VmxExitTripleFault;
386static FNVMXEXITHANDLERNSRC hmR0VmxExitInitSignal;
387static FNVMXEXITHANDLERNSRC hmR0VmxExitSipi;
388static FNVMXEXITHANDLERNSRC hmR0VmxExitIoSmi;
389static FNVMXEXITHANDLERNSRC hmR0VmxExitSmi;
390static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindow;
391static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindow;
392static FNVMXEXITHANDLER hmR0VmxExitTaskSwitch;
393static FNVMXEXITHANDLER hmR0VmxExitCpuid;
394static FNVMXEXITHANDLER hmR0VmxExitGetsec;
395static FNVMXEXITHANDLER hmR0VmxExitHlt;
396static FNVMXEXITHANDLERNSRC hmR0VmxExitInvd;
397static FNVMXEXITHANDLER hmR0VmxExitInvlpg;
398static FNVMXEXITHANDLER hmR0VmxExitRdpmc;
399static FNVMXEXITHANDLER hmR0VmxExitVmcall;
400static FNVMXEXITHANDLER hmR0VmxExitRdtsc;
401static FNVMXEXITHANDLERNSRC hmR0VmxExitRsm;
402static FNVMXEXITHANDLERNSRC hmR0VmxExitSetPendingXcptUD;
403static FNVMXEXITHANDLER hmR0VmxExitMovCRx;
404static FNVMXEXITHANDLER hmR0VmxExitMovDRx;
405static FNVMXEXITHANDLER hmR0VmxExitIoInstr;
406static FNVMXEXITHANDLER hmR0VmxExitRdmsr;
407static FNVMXEXITHANDLER hmR0VmxExitWrmsr;
408static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestState;
409static FNVMXEXITHANDLERNSRC hmR0VmxExitErrMsrLoad;
410static FNVMXEXITHANDLERNSRC hmR0VmxExitErrUndefined;
411static FNVMXEXITHANDLER hmR0VmxExitMwait;
412static FNVMXEXITHANDLER hmR0VmxExitMtf;
413static FNVMXEXITHANDLER hmR0VmxExitMonitor;
414static FNVMXEXITHANDLER hmR0VmxExitPause;
415static FNVMXEXITHANDLERNSRC hmR0VmxExitErrMachineCheck;
416static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThreshold;
417static FNVMXEXITHANDLER hmR0VmxExitApicAccess;
418static FNVMXEXITHANDLER hmR0VmxExitXdtrAccess;
419static FNVMXEXITHANDLER hmR0VmxExitXdtrAccess;
420static FNVMXEXITHANDLER hmR0VmxExitEptViolation;
421static FNVMXEXITHANDLER hmR0VmxExitEptMisconfig;
422static FNVMXEXITHANDLER hmR0VmxExitRdtscp;
423static FNVMXEXITHANDLER hmR0VmxExitPreemptTimer;
424static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvd;
425static FNVMXEXITHANDLER hmR0VmxExitXsetbv;
426static FNVMXEXITHANDLER hmR0VmxExitRdrand;
427static FNVMXEXITHANDLER hmR0VmxExitInvpcid;
428/** @} */
429
430static int hmR0VmxExitXcptNM(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
431static int hmR0VmxExitXcptPF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
432static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
433static int hmR0VmxExitXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
434static int hmR0VmxExitXcptBP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
435static int hmR0VmxExitXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
436static int hmR0VmxExitXcptAC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
437static int hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
438static uint32_t hmR0VmxCheckGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx);
439
440
441/*********************************************************************************************************************************
442* Global Variables *
443*********************************************************************************************************************************/
444#ifdef HMVMX_USE_FUNCTION_TABLE
445
446/**
447 * VMX_EXIT dispatch table.
448 */
449static const PFNVMXEXITHANDLER g_apfnVMExitHandlers[VMX_EXIT_MAX + 1] =
450{
451 /* 00 VMX_EXIT_XCPT_OR_NMI */ hmR0VmxExitXcptOrNmi,
452 /* 01 VMX_EXIT_EXT_INT */ hmR0VmxExitExtInt,
453 /* 02 VMX_EXIT_TRIPLE_FAULT */ hmR0VmxExitTripleFault,
454 /* 03 VMX_EXIT_INIT_SIGNAL */ hmR0VmxExitInitSignal,
455 /* 04 VMX_EXIT_SIPI */ hmR0VmxExitSipi,
456 /* 05 VMX_EXIT_IO_SMI */ hmR0VmxExitIoSmi,
457 /* 06 VMX_EXIT_SMI */ hmR0VmxExitSmi,
458 /* 07 VMX_EXIT_INT_WINDOW */ hmR0VmxExitIntWindow,
459 /* 08 VMX_EXIT_NMI_WINDOW */ hmR0VmxExitNmiWindow,
460 /* 09 VMX_EXIT_TASK_SWITCH */ hmR0VmxExitTaskSwitch,
461 /* 10 VMX_EXIT_CPUID */ hmR0VmxExitCpuid,
462 /* 11 VMX_EXIT_GETSEC */ hmR0VmxExitGetsec,
463 /* 12 VMX_EXIT_HLT */ hmR0VmxExitHlt,
464 /* 13 VMX_EXIT_INVD */ hmR0VmxExitInvd,
465 /* 14 VMX_EXIT_INVLPG */ hmR0VmxExitInvlpg,
466 /* 15 VMX_EXIT_RDPMC */ hmR0VmxExitRdpmc,
467 /* 16 VMX_EXIT_RDTSC */ hmR0VmxExitRdtsc,
468 /* 17 VMX_EXIT_RSM */ hmR0VmxExitRsm,
469 /* 18 VMX_EXIT_VMCALL */ hmR0VmxExitVmcall,
470 /* 19 VMX_EXIT_VMCLEAR */ hmR0VmxExitSetPendingXcptUD,
471 /* 20 VMX_EXIT_VMLAUNCH */ hmR0VmxExitSetPendingXcptUD,
472 /* 21 VMX_EXIT_VMPTRLD */ hmR0VmxExitSetPendingXcptUD,
473 /* 22 VMX_EXIT_VMPTRST */ hmR0VmxExitSetPendingXcptUD,
474 /* 23 VMX_EXIT_VMREAD */ hmR0VmxExitSetPendingXcptUD,
475 /* 24 VMX_EXIT_VMRESUME */ hmR0VmxExitSetPendingXcptUD,
476 /* 25 VMX_EXIT_VMWRITE */ hmR0VmxExitSetPendingXcptUD,
477 /* 26 VMX_EXIT_VMXOFF */ hmR0VmxExitSetPendingXcptUD,
478 /* 27 VMX_EXIT_VMXON */ hmR0VmxExitSetPendingXcptUD,
479 /* 28 VMX_EXIT_MOV_CRX */ hmR0VmxExitMovCRx,
480 /* 29 VMX_EXIT_MOV_DRX */ hmR0VmxExitMovDRx,
481 /* 30 VMX_EXIT_IO_INSTR */ hmR0VmxExitIoInstr,
482 /* 31 VMX_EXIT_RDMSR */ hmR0VmxExitRdmsr,
483 /* 32 VMX_EXIT_WRMSR */ hmR0VmxExitWrmsr,
484 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ hmR0VmxExitErrInvalidGuestState,
485 /* 34 VMX_EXIT_ERR_MSR_LOAD */ hmR0VmxExitErrMsrLoad,
486 /* 35 UNDEFINED */ hmR0VmxExitErrUndefined,
487 /* 36 VMX_EXIT_MWAIT */ hmR0VmxExitMwait,
488 /* 37 VMX_EXIT_MTF */ hmR0VmxExitMtf,
489 /* 38 UNDEFINED */ hmR0VmxExitErrUndefined,
490 /* 39 VMX_EXIT_MONITOR */ hmR0VmxExitMonitor,
491 /* 40 UNDEFINED */ hmR0VmxExitPause,
492 /* 41 VMX_EXIT_PAUSE */ hmR0VmxExitErrMachineCheck,
493 /* 42 VMX_EXIT_ERR_MACHINE_CHECK */ hmR0VmxExitErrUndefined,
494 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ hmR0VmxExitTprBelowThreshold,
495 /* 44 VMX_EXIT_APIC_ACCESS */ hmR0VmxExitApicAccess,
496 /* 45 UNDEFINED */ hmR0VmxExitErrUndefined,
497 /* 46 VMX_EXIT_XDTR_ACCESS */ hmR0VmxExitXdtrAccess,
498 /* 47 VMX_EXIT_TR_ACCESS */ hmR0VmxExitXdtrAccess,
499 /* 48 VMX_EXIT_EPT_VIOLATION */ hmR0VmxExitEptViolation,
500 /* 49 VMX_EXIT_EPT_MISCONFIG */ hmR0VmxExitEptMisconfig,
501 /* 50 VMX_EXIT_INVEPT */ hmR0VmxExitSetPendingXcptUD,
502 /* 51 VMX_EXIT_RDTSCP */ hmR0VmxExitRdtscp,
503 /* 52 VMX_EXIT_PREEMPT_TIMER */ hmR0VmxExitPreemptTimer,
504 /* 53 VMX_EXIT_INVVPID */ hmR0VmxExitSetPendingXcptUD,
505 /* 54 VMX_EXIT_WBINVD */ hmR0VmxExitWbinvd,
506 /* 55 VMX_EXIT_XSETBV */ hmR0VmxExitXsetbv,
507 /* 56 VMX_EXIT_APIC_WRITE */ hmR0VmxExitErrUndefined,
508 /* 57 VMX_EXIT_RDRAND */ hmR0VmxExitRdrand,
509 /* 58 VMX_EXIT_INVPCID */ hmR0VmxExitInvpcid,
510 /* 59 VMX_EXIT_VMFUNC */ hmR0VmxExitSetPendingXcptUD,
511 /* 60 VMX_EXIT_ENCLS */ hmR0VmxExitErrUndefined,
512 /* 61 VMX_EXIT_RDSEED */ hmR0VmxExitErrUndefined, /* only spurious exits, so undefined */
513 /* 62 VMX_EXIT_PML_FULL */ hmR0VmxExitErrUndefined,
514 /* 63 VMX_EXIT_XSAVES */ hmR0VmxExitSetPendingXcptUD,
515 /* 64 VMX_EXIT_XRSTORS */ hmR0VmxExitSetPendingXcptUD,
516};
517#endif /* HMVMX_USE_FUNCTION_TABLE */
518
519#ifdef VBOX_STRICT
520static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
521{
522 /* 0 */ "(Not Used)",
523 /* 1 */ "VMCALL executed in VMX root operation.",
524 /* 2 */ "VMCLEAR with invalid physical address.",
525 /* 3 */ "VMCLEAR with VMXON pointer.",
526 /* 4 */ "VMLAUNCH with non-clear VMCS.",
527 /* 5 */ "VMRESUME with non-launched VMCS.",
528 /* 6 */ "VMRESUME after VMXOFF",
529 /* 7 */ "VM-entry with invalid control fields.",
530 /* 8 */ "VM-entry with invalid host state fields.",
531 /* 9 */ "VMPTRLD with invalid physical address.",
532 /* 10 */ "VMPTRLD with VMXON pointer.",
533 /* 11 */ "VMPTRLD with incorrect revision identifier.",
534 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
535 /* 13 */ "VMWRITE to read-only VMCS component.",
536 /* 14 */ "(Not Used)",
537 /* 15 */ "VMXON executed in VMX root operation.",
538 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
539 /* 17 */ "VM-entry with non-launched executing VMCS.",
540 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
541 /* 19 */ "VMCALL with non-clear VMCS.",
542 /* 20 */ "VMCALL with invalid VM-exit control fields.",
543 /* 21 */ "(Not Used)",
544 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
545 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
546 /* 24 */ "VMCALL with invalid SMM-monitor features.",
547 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
548 /* 26 */ "VM-entry with events blocked by MOV SS.",
549 /* 27 */ "(Not Used)",
550 /* 28 */ "Invalid operand to INVEPT/INVVPID."
551};
552#endif /* VBOX_STRICT */
553
554
555
556/**
557 * Updates the VM's last error record.
558 *
559 * If there was a VMX instruction error, reads the error data from the VMCS and
560 * updates VCPU's last error record as well.
561 *
562 * @param pVM The cross context VM structure.
563 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
564 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
565 * VERR_VMX_INVALID_VMCS_FIELD.
566 * @param rc The error code.
567 */
568static void hmR0VmxUpdateErrorRecord(PVM pVM, PVMCPU pVCpu, int rc)
569{
570 AssertPtr(pVM);
571 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
572 || rc == VERR_VMX_UNABLE_TO_START_VM)
573 {
574 AssertPtrReturnVoid(pVCpu);
575 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
576 }
577 pVM->hm.s.lLastError = rc;
578}
579
580
581/**
582 * Reads the VM-entry interruption-information field from the VMCS into the VMX
583 * transient structure.
584 *
585 * @returns VBox status code.
586 * @param pVmxTransient Pointer to the VMX transient structure.
587 *
588 * @remarks No-long-jump zone!!!
589 */
590DECLINLINE(int) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
591{
592 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
593 AssertRCReturn(rc, rc);
594 return VINF_SUCCESS;
595}
596
597
598#ifdef VBOX_STRICT
599/**
600 * Reads the VM-entry exception error code field from the VMCS into
601 * the VMX transient structure.
602 *
603 * @returns VBox status code.
604 * @param pVmxTransient Pointer to the VMX transient structure.
605 *
606 * @remarks No-long-jump zone!!!
607 */
608DECLINLINE(int) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
609{
610 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
611 AssertRCReturn(rc, rc);
612 return VINF_SUCCESS;
613}
614#endif /* VBOX_STRICT */
615
616
617#ifdef VBOX_STRICT
618/**
619 * Reads the VM-entry exception error code field from the VMCS into
620 * the VMX transient structure.
621 *
622 * @returns VBox status code.
623 * @param pVmxTransient Pointer to the VMX transient structure.
624 *
625 * @remarks No-long-jump zone!!!
626 */
627DECLINLINE(int) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
628{
629 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
630 AssertRCReturn(rc, rc);
631 return VINF_SUCCESS;
632}
633#endif /* VBOX_STRICT */
634
635
636/**
637 * Reads the VM-exit interruption-information field from the VMCS into the VMX
638 * transient structure.
639 *
640 * @returns VBox status code.
641 * @param pVmxTransient Pointer to the VMX transient structure.
642 */
643DECLINLINE(int) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
644{
645 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO))
646 {
647 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
648 AssertRCReturn(rc, rc);
649 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO;
650 }
651 return VINF_SUCCESS;
652}
653
654
655/**
656 * Reads the VM-exit interruption error code from the VMCS into the VMX
657 * transient structure.
658 *
659 * @returns VBox status code.
660 * @param pVmxTransient Pointer to the VMX transient structure.
661 */
662DECLINLINE(int) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
663{
664 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE))
665 {
666 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
667 AssertRCReturn(rc, rc);
668 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE;
669 }
670 return VINF_SUCCESS;
671}
672
673
674/**
675 * Reads the VM-exit instruction length field from the VMCS into the VMX
676 * transient structure.
677 *
678 * @returns VBox status code.
679 * @param pVmxTransient Pointer to the VMX transient structure.
680 */
681DECLINLINE(int) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
682{
683 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN))
684 {
685 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbInstr);
686 AssertRCReturn(rc, rc);
687 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN;
688 }
689 return VINF_SUCCESS;
690}
691
692
693/**
694 * Reads the VM-exit instruction-information field from the VMCS into
695 * the VMX transient structure.
696 *
697 * @returns VBox status code.
698 * @param pVmxTransient Pointer to the VMX transient structure.
699 */
700DECLINLINE(int) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
701{
702 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_INFO))
703 {
704 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
705 AssertRCReturn(rc, rc);
706 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_INFO;
707 }
708 return VINF_SUCCESS;
709}
710
711
712/**
713 * Reads the exit code qualification from the VMCS into the VMX transient
714 * structure.
715 *
716 * @returns VBox status code.
717 * @param pVCpu The cross context virtual CPU structure of the
718 * calling EMT. (Required for the VMCS cache case.)
719 * @param pVmxTransient Pointer to the VMX transient structure.
720 */
721DECLINLINE(int) hmR0VmxReadExitQualificationVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
722{
723 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION))
724 {
725 int rc = VMXReadVmcsGstN(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQualification); NOREF(pVCpu);
726 AssertRCReturn(rc, rc);
727 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION;
728 }
729 return VINF_SUCCESS;
730}
731
732
733/**
734 * Reads the IDT-vectoring information field from the VMCS into the VMX
735 * transient structure.
736 *
737 * @returns VBox status code.
738 * @param pVmxTransient Pointer to the VMX transient structure.
739 *
740 * @remarks No-long-jump zone!!!
741 */
742DECLINLINE(int) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
743{
744 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO))
745 {
746 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_INFO, &pVmxTransient->uIdtVectoringInfo);
747 AssertRCReturn(rc, rc);
748 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO;
749 }
750 return VINF_SUCCESS;
751}
752
753
754/**
755 * Reads the IDT-vectoring error code from the VMCS into the VMX
756 * transient structure.
757 *
758 * @returns VBox status code.
759 * @param pVmxTransient Pointer to the VMX transient structure.
760 */
761DECLINLINE(int) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
762{
763 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE))
764 {
765 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
766 AssertRCReturn(rc, rc);
767 pVmxTransient->fVmcsFieldsRead |= HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE;
768 }
769 return VINF_SUCCESS;
770}
771
772
773/**
774 * Enters VMX root mode operation on the current CPU.
775 *
776 * @returns VBox status code.
777 * @param pVM The cross context VM structure. Can be
778 * NULL, after a resume.
779 * @param HCPhysCpuPage Physical address of the VMXON region.
780 * @param pvCpuPage Pointer to the VMXON region.
781 */
782static int hmR0VmxEnterRootMode(PVM pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
783{
784 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
785 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
786 Assert(pvCpuPage);
787 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
788
789 if (pVM)
790 {
791 /* Write the VMCS revision dword to the VMXON region. */
792 *(uint32_t *)pvCpuPage = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.Msrs.u64BasicInfo);
793 }
794
795 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
796 RTCCUINTREG fEFlags = ASMIntDisableFlags();
797
798 /* Enable the VMX bit in CR4 if necessary. */
799 RTCCUINTREG uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
800
801 /* Enter VMX root mode. */
802 int rc = VMXEnable(HCPhysCpuPage);
803 if (RT_FAILURE(rc))
804 {
805 if (!(uOldCr4 & X86_CR4_VMXE))
806 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
807
808 if (pVM)
809 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
810 }
811
812 /* Restore interrupts. */
813 ASMSetFlags(fEFlags);
814 return rc;
815}
816
817
818/**
819 * Exits VMX root mode operation on the current CPU.
820 *
821 * @returns VBox status code.
822 */
823static int hmR0VmxLeaveRootMode(void)
824{
825 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
826
827 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
828 RTCCUINTREG fEFlags = ASMIntDisableFlags();
829
830 /* If we're for some reason not in VMX root mode, then don't leave it. */
831 RTCCUINTREG uHostCR4 = ASMGetCR4();
832
833 int rc;
834 if (uHostCR4 & X86_CR4_VMXE)
835 {
836 /* Exit VMX root mode and clear the VMX bit in CR4. */
837 VMXDisable();
838 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
839 rc = VINF_SUCCESS;
840 }
841 else
842 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
843
844 /* Restore interrupts. */
845 ASMSetFlags(fEFlags);
846 return rc;
847}
848
849
850/**
851 * Allocates and maps one physically contiguous page. The allocated page is
852 * zero'd out. (Used by various VT-x structures).
853 *
854 * @returns IPRT status code.
855 * @param pMemObj Pointer to the ring-0 memory object.
856 * @param ppVirt Where to store the virtual address of the
857 * allocation.
858 * @param pHCPhys Where to store the physical address of the
859 * allocation.
860 */
861DECLINLINE(int) hmR0VmxPageAllocZ(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
862{
863 AssertPtrReturn(pMemObj, VERR_INVALID_PARAMETER);
864 AssertPtrReturn(ppVirt, VERR_INVALID_PARAMETER);
865 AssertPtrReturn(pHCPhys, VERR_INVALID_PARAMETER);
866
867 int rc = RTR0MemObjAllocCont(pMemObj, PAGE_SIZE, false /* fExecutable */);
868 if (RT_FAILURE(rc))
869 return rc;
870 *ppVirt = RTR0MemObjAddress(*pMemObj);
871 *pHCPhys = RTR0MemObjGetPagePhysAddr(*pMemObj, 0 /* iPage */);
872 ASMMemZero32(*ppVirt, PAGE_SIZE);
873 return VINF_SUCCESS;
874}
875
876
877/**
878 * Frees and unmaps an allocated physical page.
879 *
880 * @param pMemObj Pointer to the ring-0 memory object.
881 * @param ppVirt Where to re-initialize the virtual address of
882 * allocation as 0.
883 * @param pHCPhys Where to re-initialize the physical address of the
884 * allocation as 0.
885 */
886DECLINLINE(void) hmR0VmxPageFree(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys)
887{
888 AssertPtr(pMemObj);
889 AssertPtr(ppVirt);
890 AssertPtr(pHCPhys);
891 if (*pMemObj != NIL_RTR0MEMOBJ)
892 {
893 int rc = RTR0MemObjFree(*pMemObj, true /* fFreeMappings */);
894 AssertRC(rc);
895 *pMemObj = NIL_RTR0MEMOBJ;
896 *ppVirt = 0;
897 *pHCPhys = 0;
898 }
899}
900
901
902/**
903 * Worker function to free VT-x related structures.
904 *
905 * @returns IPRT status code.
906 * @param pVM The cross context VM structure.
907 */
908static void hmR0VmxStructsFree(PVM pVM)
909{
910 for (VMCPUID i = 0; i < pVM->cCpus; i++)
911 {
912 PVMCPU pVCpu = &pVM->aCpus[i];
913 AssertPtr(pVCpu);
914
915 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjHostMsr, &pVCpu->hm.s.vmx.pvHostMsr, &pVCpu->hm.s.vmx.HCPhysHostMsr);
916 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjGuestMsr, &pVCpu->hm.s.vmx.pvGuestMsr, &pVCpu->hm.s.vmx.HCPhysGuestMsr);
917
918 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
919 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjMsrBitmap, &pVCpu->hm.s.vmx.pvMsrBitmap, &pVCpu->hm.s.vmx.HCPhysMsrBitmap);
920
921 hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjVmcs, &pVCpu->hm.s.vmx.pvVmcs, &pVCpu->hm.s.vmx.HCPhysVmcs);
922 }
923
924 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess, &pVM->hm.s.vmx.HCPhysApicAccess);
925#ifdef VBOX_WITH_CRASHDUMP_MAGIC
926 hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
927#endif
928}
929
930
931/**
932 * Worker function to allocate VT-x related VM structures.
933 *
934 * @returns IPRT status code.
935 * @param pVM The cross context VM structure.
936 */
937static int hmR0VmxStructsAlloc(PVM pVM)
938{
939 /*
940 * Initialize members up-front so we can cleanup properly on allocation failure.
941 */
942#define VMXLOCAL_INIT_VM_MEMOBJ(a_Name, a_VirtPrefix) \
943 pVM->hm.s.vmx.hMemObj##a_Name = NIL_RTR0MEMOBJ; \
944 pVM->hm.s.vmx.a_VirtPrefix##a_Name = 0; \
945 pVM->hm.s.vmx.HCPhys##a_Name = 0;
946
947#define VMXLOCAL_INIT_VMCPU_MEMOBJ(a_Name, a_VirtPrefix) \
948 pVCpu->hm.s.vmx.hMemObj##a_Name = NIL_RTR0MEMOBJ; \
949 pVCpu->hm.s.vmx.a_VirtPrefix##a_Name = 0; \
950 pVCpu->hm.s.vmx.HCPhys##a_Name = 0;
951
952#ifdef VBOX_WITH_CRASHDUMP_MAGIC
953 VMXLOCAL_INIT_VM_MEMOBJ(Scratch, pv);
954#endif
955 VMXLOCAL_INIT_VM_MEMOBJ(ApicAccess, pb);
956
957 AssertCompile(sizeof(VMCPUID) == sizeof(pVM->cCpus));
958 for (VMCPUID i = 0; i < pVM->cCpus; i++)
959 {
960 PVMCPU pVCpu = &pVM->aCpus[i];
961 VMXLOCAL_INIT_VMCPU_MEMOBJ(Vmcs, pv);
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 /* Get the allocated virtual-APIC page from the APIC device 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 = APICGetApicPageForCpu(pVCpu, &pVCpu->hm.s.vmx.HCPhysVirtApic, (PRTR0PTR)&pVCpu->hm.s.vmx.pbVirtApic,
1012 NULL /* pR3Ptr */, NULL /* pRCPtr */);
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/**
1461 * Saves a set of host MSRs to allow read/write passthru access to the guest and
1462 * perform lazy restoration of the host MSRs while leaving VT-x.
1463 *
1464 * @param pVCpu The cross context virtual CPU structure.
1465 *
1466 * @remarks No-long-jump zone!!!
1467 */
1468static void hmR0VmxLazySaveHostMsrs(PVMCPU pVCpu)
1469{
1470 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1471
1472 /*
1473 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap permissions in hmR0VmxSetupProcCtls().
1474 */
1475 if (!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST))
1476 {
1477 Assert(!(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)); /* Guest MSRs better not be loaded now. */
1478#if HC_ARCH_BITS == 64
1479 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
1480 {
1481 pVCpu->hm.s.vmx.u64HostLStarMsr = ASMRdMsr(MSR_K8_LSTAR);
1482 pVCpu->hm.s.vmx.u64HostStarMsr = ASMRdMsr(MSR_K6_STAR);
1483 pVCpu->hm.s.vmx.u64HostSFMaskMsr = ASMRdMsr(MSR_K8_SF_MASK);
1484 pVCpu->hm.s.vmx.u64HostKernelGSBaseMsr = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
1485 }
1486#endif
1487 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
1488 }
1489}
1490
1491
1492/**
1493 * Checks whether the MSR belongs to the set of guest MSRs that we restore
1494 * lazily while leaving VT-x.
1495 *
1496 * @returns true if it does, false otherwise.
1497 * @param pVCpu The cross context virtual CPU structure.
1498 * @param uMsr The MSR to check.
1499 */
1500static bool hmR0VmxIsLazyGuestMsr(PVMCPU pVCpu, uint32_t uMsr)
1501{
1502 NOREF(pVCpu);
1503#if HC_ARCH_BITS == 64
1504 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
1505 {
1506 switch (uMsr)
1507 {
1508 case MSR_K8_LSTAR:
1509 case MSR_K6_STAR:
1510 case MSR_K8_SF_MASK:
1511 case MSR_K8_KERNEL_GS_BASE:
1512 return true;
1513 }
1514 }
1515#else
1516 RT_NOREF(pVCpu, uMsr);
1517#endif
1518 return false;
1519}
1520
1521
1522/**
1523 * Saves a set of guest MSRs back into the guest-CPU context.
1524 *
1525 * @param pVCpu The cross context virtual CPU structure.
1526 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
1527 * out-of-sync. Make sure to update the required fields
1528 * before using them.
1529 *
1530 * @remarks No-long-jump zone!!!
1531 */
1532static void hmR0VmxLazySaveGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
1533{
1534 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1535 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1536
1537 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
1538 {
1539 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
1540#if HC_ARCH_BITS == 64
1541 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
1542 {
1543 pMixedCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
1544 pMixedCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
1545 pMixedCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
1546 pMixedCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
1547 }
1548#else
1549 NOREF(pMixedCtx);
1550#endif
1551 }
1552}
1553
1554
1555/**
1556 * Loads a set of guests MSRs to allow read/passthru to the guest.
1557 *
1558 * The name of this function is slightly confusing. This function does NOT
1559 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
1560 * common prefix for functions dealing with "lazy restoration" of the shared
1561 * MSRs.
1562 *
1563 * @param pVCpu The cross context virtual CPU structure.
1564 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
1565 * out-of-sync. Make sure to update the required fields
1566 * before using them.
1567 *
1568 * @remarks No-long-jump zone!!!
1569 */
1570static void hmR0VmxLazyLoadGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
1571{
1572 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1573 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1574
1575 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
1576#if HC_ARCH_BITS == 64
1577 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
1578 {
1579 /*
1580 * If the guest MSRs are not loaded -and- if all the guest MSRs are identical
1581 * to the MSRs on the CPU (which are the saved host MSRs, see assertion above) then
1582 * we can skip a few MSR writes.
1583 *
1584 * Otherwise, it implies either 1. they're not loaded, or 2. they're loaded but the
1585 * guest MSR values in the guest-CPU context might be different to what's currently
1586 * loaded in the CPU. In either case, we need to write the new guest MSR values to the
1587 * CPU, see @bugref{8728}.
1588 */
1589 if ( !(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
1590 && pMixedCtx->msrKERNELGSBASE == pVCpu->hm.s.vmx.u64HostKernelGSBaseMsr
1591 && pMixedCtx->msrLSTAR == pVCpu->hm.s.vmx.u64HostLStarMsr
1592 && pMixedCtx->msrSTAR == pVCpu->hm.s.vmx.u64HostStarMsr
1593 && pMixedCtx->msrSFMASK == pVCpu->hm.s.vmx.u64HostSFMaskMsr)
1594 {
1595#ifdef VBOX_STRICT
1596 Assert(ASMRdMsr(MSR_K8_KERNEL_GS_BASE) == pMixedCtx->msrKERNELGSBASE);
1597 Assert(ASMRdMsr(MSR_K8_LSTAR) == pMixedCtx->msrLSTAR);
1598 Assert(ASMRdMsr(MSR_K6_STAR) == pMixedCtx->msrSTAR);
1599 Assert(ASMRdMsr(MSR_K8_SF_MASK) == pMixedCtx->msrSFMASK);
1600#endif
1601 }
1602 else
1603 {
1604 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pMixedCtx->msrKERNELGSBASE);
1605 ASMWrMsr(MSR_K8_LSTAR, pMixedCtx->msrLSTAR);
1606 ASMWrMsr(MSR_K6_STAR, pMixedCtx->msrSTAR);
1607 ASMWrMsr(MSR_K8_SF_MASK, pMixedCtx->msrSFMASK);
1608 }
1609 }
1610#else
1611 RT_NOREF(pMixedCtx);
1612#endif
1613 pVCpu->hm.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
1614}
1615
1616
1617/**
1618 * Performs lazy restoration of the set of host MSRs if they were previously
1619 * loaded with guest MSR values.
1620 *
1621 * @param pVCpu The cross context virtual CPU structure.
1622 *
1623 * @remarks No-long-jump zone!!!
1624 * @remarks The guest MSRs should have been saved back into the guest-CPU
1625 * context by hmR0VmxSaveGuestLazyMsrs()!!!
1626 */
1627static void hmR0VmxLazyRestoreHostMsrs(PVMCPU pVCpu)
1628{
1629 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1630 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
1631
1632 if (pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
1633 {
1634 Assert(pVCpu->hm.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
1635#if HC_ARCH_BITS == 64
1636 if (pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests)
1637 {
1638 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hm.s.vmx.u64HostLStarMsr);
1639 ASMWrMsr(MSR_K6_STAR, pVCpu->hm.s.vmx.u64HostStarMsr);
1640 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hm.s.vmx.u64HostSFMaskMsr);
1641 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hm.s.vmx.u64HostKernelGSBaseMsr);
1642 }
1643#endif
1644 }
1645 pVCpu->hm.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
1646}
1647
1648
1649/**
1650 * Verifies that our cached values of the VMCS controls are all
1651 * consistent with what's actually present in the VMCS.
1652 *
1653 * @returns VBox status code.
1654 * @param pVCpu The cross context virtual CPU structure.
1655 */
1656static int hmR0VmxCheckVmcsCtls(PVMCPU pVCpu)
1657{
1658 uint32_t u32Val;
1659 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
1660 AssertRCReturn(rc, rc);
1661 AssertMsgReturn(pVCpu->hm.s.vmx.u32EntryCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32EntryCtls, u32Val),
1662 VERR_VMX_ENTRY_CTLS_CACHE_INVALID);
1663
1664 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
1665 AssertRCReturn(rc, rc);
1666 AssertMsgReturn(pVCpu->hm.s.vmx.u32ExitCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32ExitCtls, u32Val),
1667 VERR_VMX_EXIT_CTLS_CACHE_INVALID);
1668
1669 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
1670 AssertRCReturn(rc, rc);
1671 AssertMsgReturn(pVCpu->hm.s.vmx.u32PinCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32PinCtls, u32Val),
1672 VERR_VMX_PIN_EXEC_CTLS_CACHE_INVALID);
1673
1674 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
1675 AssertRCReturn(rc, rc);
1676 AssertMsgReturn(pVCpu->hm.s.vmx.u32ProcCtls == u32Val, ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32ProcCtls, u32Val),
1677 VERR_VMX_PROC_EXEC_CTLS_CACHE_INVALID);
1678
1679 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
1680 {
1681 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
1682 AssertRCReturn(rc, rc);
1683 AssertMsgReturn(pVCpu->hm.s.vmx.u32ProcCtls2 == u32Val,
1684 ("Cache=%#RX32 VMCS=%#RX32", pVCpu->hm.s.vmx.u32ProcCtls2, u32Val),
1685 VERR_VMX_PROC_EXEC2_CTLS_CACHE_INVALID);
1686 }
1687
1688 return VINF_SUCCESS;
1689}
1690
1691
1692#ifdef VBOX_STRICT
1693/**
1694 * Verifies that our cached host EFER value has not changed
1695 * since we cached it.
1696 *
1697 * @param pVCpu The cross context virtual CPU structure.
1698 */
1699static void hmR0VmxCheckHostEferMsr(PVMCPU pVCpu)
1700{
1701 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1702
1703 if (pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR)
1704 {
1705 uint64_t u64Val;
1706 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &u64Val);
1707 AssertRC(rc);
1708
1709 uint64_t u64HostEferMsr = ASMRdMsr(MSR_K6_EFER);
1710 AssertMsgReturnVoid(u64HostEferMsr == u64Val, ("u64HostEferMsr=%#RX64 u64Val=%#RX64\n", u64HostEferMsr, u64Val));
1711 }
1712}
1713
1714
1715/**
1716 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
1717 * VMCS are correct.
1718 *
1719 * @param pVCpu The cross context virtual CPU structure.
1720 */
1721static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPU pVCpu)
1722{
1723 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1724
1725 /* Verify MSR counts in the VMCS are what we think it should be. */
1726 uint32_t cMsrs;
1727 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cMsrs); AssertRC(rc);
1728 Assert(cMsrs == pVCpu->hm.s.vmx.cMsrs);
1729
1730 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cMsrs); AssertRC(rc);
1731 Assert(cMsrs == pVCpu->hm.s.vmx.cMsrs);
1732
1733 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cMsrs); AssertRC(rc);
1734 Assert(cMsrs == pVCpu->hm.s.vmx.cMsrs);
1735
1736 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
1737 PVMXAUTOMSR pGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
1738 for (uint32_t i = 0; i < cMsrs; i++, pHostMsr++, pGuestMsr++)
1739 {
1740 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
1741 AssertMsgReturnVoid(pHostMsr->u32Msr == pGuestMsr->u32Msr, ("HostMsr=%#RX32 GuestMsr=%#RX32 cMsrs=%u\n", pHostMsr->u32Msr,
1742 pGuestMsr->u32Msr, cMsrs));
1743
1744 uint64_t u64Msr = ASMRdMsr(pHostMsr->u32Msr);
1745 AssertMsgReturnVoid(pHostMsr->u64Value == u64Msr, ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
1746 pHostMsr->u32Msr, pHostMsr->u64Value, u64Msr, cMsrs));
1747
1748 /* Verify that the permissions are as expected in the MSR bitmap. */
1749 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
1750 {
1751 VMXMSREXITREAD enmRead;
1752 VMXMSREXITWRITE enmWrite;
1753 rc = hmR0VmxGetMsrPermission(pVCpu, pGuestMsr->u32Msr, &enmRead, &enmWrite);
1754 AssertMsgReturnVoid(rc == VINF_SUCCESS, ("hmR0VmxGetMsrPermission! failed. rc=%Rrc\n", rc));
1755 if (pGuestMsr->u32Msr == MSR_K6_EFER)
1756 {
1757 AssertMsgReturnVoid(enmRead == VMXMSREXIT_INTERCEPT_READ, ("Passthru read for EFER!?\n"));
1758 AssertMsgReturnVoid(enmWrite == VMXMSREXIT_INTERCEPT_WRITE, ("Passthru write for EFER!?\n"));
1759 }
1760 else
1761 {
1762 AssertMsgReturnVoid(enmRead == VMXMSREXIT_PASSTHRU_READ, ("u32Msr=%#RX32 cMsrs=%u No passthru read!\n",
1763 pGuestMsr->u32Msr, cMsrs));
1764 AssertMsgReturnVoid(enmWrite == VMXMSREXIT_PASSTHRU_WRITE, ("u32Msr=%#RX32 cMsrs=%u No passthru write!\n",
1765 pGuestMsr->u32Msr, cMsrs));
1766 }
1767 }
1768 }
1769}
1770#endif /* VBOX_STRICT */
1771
1772
1773/**
1774 * Flushes the TLB using EPT.
1775 *
1776 * @returns VBox status code.
1777 * @param pVCpu The cross context virtual CPU structure of the calling
1778 * EMT. Can be NULL depending on @a enmFlush.
1779 * @param enmFlush Type of flush.
1780 *
1781 * @remarks Caller is responsible for making sure this function is called only
1782 * when NestedPaging is supported and providing @a enmFlush that is
1783 * supported by the CPU.
1784 * @remarks Can be called with interrupts disabled.
1785 */
1786static void hmR0VmxFlushEpt(PVMCPU pVCpu, VMXFLUSHEPT enmFlush)
1787{
1788 uint64_t au64Descriptor[2];
1789 if (enmFlush == VMXFLUSHEPT_ALL_CONTEXTS)
1790 au64Descriptor[0] = 0;
1791 else
1792 {
1793 Assert(pVCpu);
1794 au64Descriptor[0] = pVCpu->hm.s.vmx.HCPhysEPTP;
1795 }
1796 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
1797
1798 int rc = VMXR0InvEPT(enmFlush, &au64Descriptor[0]);
1799 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %RGv failed with %Rrc\n", enmFlush, pVCpu ? pVCpu->hm.s.vmx.HCPhysEPTP : 0,
1800 rc));
1801 if ( RT_SUCCESS(rc)
1802 && pVCpu)
1803 {
1804 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
1805 }
1806}
1807
1808
1809/**
1810 * Flushes the TLB using VPID.
1811 *
1812 * @returns VBox status code.
1813 * @param pVM The cross context VM structure.
1814 * @param pVCpu The cross context virtual CPU structure of the calling
1815 * EMT. Can be NULL depending on @a enmFlush.
1816 * @param enmFlush Type of flush.
1817 * @param GCPtr Virtual address of the page to flush (can be 0 depending
1818 * on @a enmFlush).
1819 *
1820 * @remarks Can be called with interrupts disabled.
1821 */
1822static void hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMXFLUSHVPID enmFlush, RTGCPTR GCPtr)
1823{
1824 NOREF(pVM);
1825 AssertPtr(pVM);
1826 Assert(pVM->hm.s.vmx.fVpid);
1827
1828 uint64_t au64Descriptor[2];
1829 if (enmFlush == VMXFLUSHVPID_ALL_CONTEXTS)
1830 {
1831 au64Descriptor[0] = 0;
1832 au64Descriptor[1] = 0;
1833 }
1834 else
1835 {
1836 AssertPtr(pVCpu);
1837 AssertMsg(pVCpu->hm.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
1838 AssertMsg(pVCpu->hm.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
1839 au64Descriptor[0] = pVCpu->hm.s.uCurrentAsid;
1840 au64Descriptor[1] = GCPtr;
1841 }
1842
1843 int rc = VMXR0InvVPID(enmFlush, &au64Descriptor[0]); NOREF(rc);
1844 AssertMsg(rc == VINF_SUCCESS,
1845 ("VMXR0InvVPID %#x %u %RGv failed with %d\n", enmFlush, pVCpu ? pVCpu->hm.s.uCurrentAsid : 0, GCPtr, rc));
1846 if ( RT_SUCCESS(rc)
1847 && pVCpu)
1848 {
1849 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
1850 }
1851}
1852
1853
1854/**
1855 * Invalidates a guest page by guest virtual address. Only relevant for
1856 * EPT/VPID, otherwise there is nothing really to invalidate.
1857 *
1858 * @returns VBox status code.
1859 * @param pVM The cross context VM structure.
1860 * @param pVCpu The cross context virtual CPU structure.
1861 * @param GCVirt Guest virtual address of the page to invalidate.
1862 */
1863VMMR0DECL(int) VMXR0InvalidatePage(PVM pVM, PVMCPU pVCpu, RTGCPTR GCVirt)
1864{
1865 AssertPtr(pVM);
1866 AssertPtr(pVCpu);
1867 LogFlowFunc(("pVM=%p pVCpu=%p GCVirt=%RGv\n", pVM, pVCpu, GCVirt));
1868
1869 bool fFlushPending = VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TLB_FLUSH);
1870 if (!fFlushPending)
1871 {
1872 /*
1873 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for the EPT case
1874 * See @bugref{6043} and @bugref{6177}.
1875 *
1876 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*() as this
1877 * function maybe called in a loop with individual addresses.
1878 */
1879 if (pVM->hm.s.vmx.fVpid)
1880 {
1881 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
1882 {
1883 hmR0VmxFlushVpid(pVM, pVCpu, VMXFLUSHVPID_INDIV_ADDR, GCVirt);
1884 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
1885 }
1886 else
1887 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1888 }
1889 else if (pVM->hm.s.fNestedPaging)
1890 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1891 }
1892
1893 return VINF_SUCCESS;
1894}
1895
1896
1897/**
1898 * Invalidates a guest page by physical address. Only relevant for EPT/VPID,
1899 * otherwise there is nothing really to invalidate.
1900 *
1901 * @returns VBox status code.
1902 * @param pVM The cross context VM structure.
1903 * @param pVCpu The cross context virtual CPU structure.
1904 * @param GCPhys Guest physical address of the page to invalidate.
1905 */
1906VMMR0DECL(int) VMXR0InvalidatePhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
1907{
1908 NOREF(pVM); NOREF(GCPhys);
1909 LogFlowFunc(("%RGp\n", GCPhys));
1910
1911 /*
1912 * We cannot flush a page by guest-physical address. invvpid takes only a linear address while invept only flushes
1913 * by EPT not individual addresses. We update the force flag here and flush before the next VM-entry in hmR0VmxFlushTLB*().
1914 * This function might be called in a loop. This should cause a flush-by-EPT if EPT is in use. See @bugref{6568}.
1915 */
1916 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
1917 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgPhys);
1918 return VINF_SUCCESS;
1919}
1920
1921
1922/**
1923 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
1924 * case where neither EPT nor VPID is supported by the CPU.
1925 *
1926 * @param pVM The cross context VM structure.
1927 * @param pVCpu The cross context virtual CPU structure.
1928 * @param pCpu Pointer to the global HM struct.
1929 *
1930 * @remarks Called with interrupts disabled.
1931 */
1932static void hmR0VmxFlushTaggedTlbNone(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
1933{
1934 AssertPtr(pVCpu);
1935 AssertPtr(pCpu);
1936 NOREF(pVM);
1937
1938 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
1939
1940 Assert(pCpu->idCpu != NIL_RTCPUID);
1941 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
1942 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
1943 pVCpu->hm.s.fForceTLBFlush = false;
1944 return;
1945}
1946
1947
1948/**
1949 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
1950 *
1951 * @param pVM The cross context VM structure.
1952 * @param pVCpu The cross context virtual CPU structure.
1953 * @param pCpu Pointer to the global HM CPU struct.
1954 * @remarks All references to "ASID" in this function pertains to "VPID" in
1955 * Intel's nomenclature. The reason is, to avoid confusion in compare
1956 * statements since the host-CPU copies are named "ASID".
1957 *
1958 * @remarks Called with interrupts disabled.
1959 */
1960static void hmR0VmxFlushTaggedTlbBoth(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
1961{
1962#ifdef VBOX_WITH_STATISTICS
1963 bool fTlbFlushed = false;
1964# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
1965# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
1966 if (!fTlbFlushed) \
1967 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
1968 } while (0)
1969#else
1970# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
1971# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
1972#endif
1973
1974 AssertPtr(pVM);
1975 AssertPtr(pCpu);
1976 AssertPtr(pVCpu);
1977 Assert(pCpu->idCpu != NIL_RTCPUID);
1978
1979 AssertMsg(pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid,
1980 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
1981 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hm.s.fNestedPaging, pVM->hm.s.vmx.fVpid));
1982
1983 /*
1984 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
1985 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB
1986 * or the host CPU is online after a suspend/resume, so we cannot reuse the current ASID anymore.
1987 */
1988 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
1989 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
1990 {
1991 ++pCpu->uCurrentAsid;
1992 if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
1993 {
1994 pCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
1995 pCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
1996 pCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
1997 }
1998
1999 pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
2000 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
2001 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
2002
2003 /*
2004 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
2005 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
2006 */
2007 hmR0VmxFlushEpt(pVCpu, pVM->hm.s.vmx.enmFlushEpt);
2008 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2009 HMVMX_SET_TAGGED_TLB_FLUSHED();
2010 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH); /* Already flushed-by-EPT, skip doing it again below. */
2011 }
2012
2013 /* Check for explicit TLB flushes. */
2014 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2015 {
2016 /*
2017 * Changes to the EPT paging structure by VMM requires flushing by EPT as the CPU creates
2018 * guest-physical (only EPT-tagged) mappings while traversing the EPT tables when EPT is in use.
2019 * Flushing by VPID will only flush linear (only VPID-tagged) and combined (EPT+VPID tagged) mappings
2020 * but not guest-physical mappings.
2021 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information". See @bugref{6568}.
2022 */
2023 hmR0VmxFlushEpt(pVCpu, pVM->hm.s.vmx.enmFlushEpt);
2024 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2025 HMVMX_SET_TAGGED_TLB_FLUSHED();
2026 }
2027
2028 pVCpu->hm.s.fForceTLBFlush = false;
2029 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
2030
2031 Assert(pVCpu->hm.s.idLastCpu == pCpu->idCpu);
2032 Assert(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes);
2033 AssertMsg(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes,
2034 ("Flush count mismatch for cpu %d (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
2035 AssertMsg(pCpu->uCurrentAsid >= 1 && pCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
2036 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pCpu->idCpu,
2037 pCpu->uCurrentAsid, pCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
2038 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
2039 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
2040
2041 /* Update VMCS with the VPID. */
2042 int rc = VMXWriteVmcs32(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
2043 AssertRC(rc);
2044
2045#undef HMVMX_SET_TAGGED_TLB_FLUSHED
2046}
2047
2048
2049/**
2050 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
2051 *
2052 * @returns VBox status code.
2053 * @param pVM The cross context VM structure.
2054 * @param pVCpu The cross context virtual CPU structure.
2055 * @param pCpu Pointer to the global HM CPU struct.
2056 *
2057 * @remarks Called with interrupts disabled.
2058 */
2059static void hmR0VmxFlushTaggedTlbEpt(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
2060{
2061 AssertPtr(pVM);
2062 AssertPtr(pVCpu);
2063 AssertPtr(pCpu);
2064 Assert(pCpu->idCpu != NIL_RTCPUID);
2065 AssertMsg(pVM->hm.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with NestedPaging disabled."));
2066 AssertMsg(!pVM->hm.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID enabled."));
2067
2068 /*
2069 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
2070 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
2071 */
2072 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
2073 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
2074 {
2075 pVCpu->hm.s.fForceTLBFlush = true;
2076 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2077 }
2078
2079 /* Check for explicit TLB flushes. */
2080 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2081 {
2082 pVCpu->hm.s.fForceTLBFlush = true;
2083 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2084 }
2085
2086 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
2087 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
2088
2089 if (pVCpu->hm.s.fForceTLBFlush)
2090 {
2091 hmR0VmxFlushEpt(pVCpu, pVM->hm.s.vmx.enmFlushEpt);
2092 pVCpu->hm.s.fForceTLBFlush = false;
2093 }
2094}
2095
2096
2097/**
2098 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
2099 *
2100 * @returns VBox status code.
2101 * @param pVM The cross context VM structure.
2102 * @param pVCpu The cross context virtual CPU structure.
2103 * @param pCpu Pointer to the global HM CPU struct.
2104 *
2105 * @remarks Called with interrupts disabled.
2106 */
2107static void hmR0VmxFlushTaggedTlbVpid(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
2108{
2109 AssertPtr(pVM);
2110 AssertPtr(pVCpu);
2111 AssertPtr(pCpu);
2112 Assert(pCpu->idCpu != NIL_RTCPUID);
2113 AssertMsg(pVM->hm.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked with VPID disabled."));
2114 AssertMsg(!pVM->hm.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging enabled"));
2115
2116 /*
2117 * Force a TLB flush for the first world switch if the current CPU differs from the one we ran on last.
2118 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB
2119 * or the host CPU is online after a suspend/resume, so we cannot reuse the current ASID anymore.
2120 */
2121 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
2122 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
2123 {
2124 pVCpu->hm.s.fForceTLBFlush = true;
2125 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
2126 }
2127
2128 /* Check for explicit TLB flushes. */
2129 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2130 {
2131 /*
2132 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see hmR0VmxSetupTaggedTlb())
2133 * we would need to explicitly flush in this case (add an fExplicitFlush = true here and change the
2134 * pCpu->fFlushAsidBeforeUse check below to include fExplicitFlush's too) - an obscure corner case.
2135 */
2136 pVCpu->hm.s.fForceTLBFlush = true;
2137 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
2138 }
2139
2140 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
2141 if (pVCpu->hm.s.fForceTLBFlush)
2142 {
2143 ++pCpu->uCurrentAsid;
2144 if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
2145 {
2146 pCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
2147 pCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
2148 pCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
2149 }
2150
2151 pVCpu->hm.s.fForceTLBFlush = false;
2152 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
2153 pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
2154 if (pCpu->fFlushAsidBeforeUse)
2155 {
2156 if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_SINGLE_CONTEXT)
2157 hmR0VmxFlushVpid(pVM, pVCpu, VMXFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
2158 else if (pVM->hm.s.vmx.enmFlushVpid == VMXFLUSHVPID_ALL_CONTEXTS)
2159 {
2160 hmR0VmxFlushVpid(pVM, pVCpu, VMXFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
2161 pCpu->fFlushAsidBeforeUse = false;
2162 }
2163 else
2164 {
2165 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
2166 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
2167 }
2168 }
2169 }
2170
2171 AssertMsg(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes,
2172 ("Flush count mismatch for cpu %d (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
2173 AssertMsg(pCpu->uCurrentAsid >= 1 && pCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
2174 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pCpu->idCpu,
2175 pCpu->uCurrentAsid, pCpu->cTlbFlushes, pVCpu->hm.s.idLastCpu, pVCpu->hm.s.cTlbFlushes));
2176 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
2177 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
2178
2179 int rc = VMXWriteVmcs32(VMX_VMCS16_VPID, pVCpu->hm.s.uCurrentAsid);
2180 AssertRC(rc);
2181}
2182
2183
2184/**
2185 * Flushes the guest TLB entry based on CPU capabilities.
2186 *
2187 * @param pVCpu The cross context virtual CPU structure.
2188 * @param pCpu Pointer to the global HM CPU struct.
2189 */
2190DECLINLINE(void) hmR0VmxFlushTaggedTlb(PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
2191{
2192#ifdef HMVMX_ALWAYS_FLUSH_TLB
2193 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2194#endif
2195 PVM pVM = pVCpu->CTX_SUFF(pVM);
2196 switch (pVM->hm.s.vmx.uFlushTaggedTlb)
2197 {
2198 case HMVMX_FLUSH_TAGGED_TLB_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pVM, pVCpu, pCpu); break;
2199 case HMVMX_FLUSH_TAGGED_TLB_EPT: hmR0VmxFlushTaggedTlbEpt(pVM, pVCpu, pCpu); break;
2200 case HMVMX_FLUSH_TAGGED_TLB_VPID: hmR0VmxFlushTaggedTlbVpid(pVM, pVCpu, pCpu); break;
2201 case HMVMX_FLUSH_TAGGED_TLB_NONE: hmR0VmxFlushTaggedTlbNone(pVM, pVCpu, pCpu); break;
2202 default:
2203 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
2204 break;
2205 }
2206
2207 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
2208}
2209
2210
2211/**
2212 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
2213 * TLB entries from the host TLB before VM-entry.
2214 *
2215 * @returns VBox status code.
2216 * @param pVM The cross context VM structure.
2217 */
2218static int hmR0VmxSetupTaggedTlb(PVM pVM)
2219{
2220 /*
2221 * Determine optimal flush type for Nested Paging.
2222 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup unrestricted
2223 * guest execution (see hmR3InitFinalizeR0()).
2224 */
2225 if (pVM->hm.s.fNestedPaging)
2226 {
2227 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
2228 {
2229 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
2230 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_SINGLE_CONTEXT;
2231 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
2232 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_ALL_CONTEXTS;
2233 else
2234 {
2235 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
2236 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2237 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
2238 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2239 }
2240
2241 /* Make sure the write-back cacheable memory type for EPT is supported. */
2242 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB)))
2243 {
2244 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2245 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
2246 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2247 }
2248
2249 /* EPT requires a page-walk length of 4. */
2250 if (RT_UNLIKELY(!(pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
2251 {
2252 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2253 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
2254 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2255 }
2256 }
2257 else
2258 {
2259 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
2260 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NOT_SUPPORTED;
2261 pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
2262 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2263 }
2264 }
2265
2266 /*
2267 * Determine optimal flush type for VPID.
2268 */
2269 if (pVM->hm.s.vmx.fVpid)
2270 {
2271 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
2272 {
2273 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
2274 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_SINGLE_CONTEXT;
2275 else if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
2276 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_ALL_CONTEXTS;
2277 else
2278 {
2279 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
2280 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
2281 LogRel(("hmR0VmxSetupTaggedTlb: Only INDIV_ADDR supported. Ignoring VPID.\n"));
2282 if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
2283 LogRel(("hmR0VmxSetupTaggedTlb: Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
2284 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_NOT_SUPPORTED;
2285 pVM->hm.s.vmx.fVpid = false;
2286 }
2287 }
2288 else
2289 {
2290 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
2291 Log4(("hmR0VmxSetupTaggedTlb: VPID supported without INVEPT support. Ignoring VPID.\n"));
2292 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_NOT_SUPPORTED;
2293 pVM->hm.s.vmx.fVpid = false;
2294 }
2295 }
2296
2297 /*
2298 * Setup the handler for flushing tagged-TLBs.
2299 */
2300 if (pVM->hm.s.fNestedPaging && pVM->hm.s.vmx.fVpid)
2301 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_EPT_VPID;
2302 else if (pVM->hm.s.fNestedPaging)
2303 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_EPT;
2304 else if (pVM->hm.s.vmx.fVpid)
2305 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_VPID;
2306 else
2307 pVM->hm.s.vmx.uFlushTaggedTlb = HMVMX_FLUSH_TAGGED_TLB_NONE;
2308 return VINF_SUCCESS;
2309}
2310
2311
2312/**
2313 * Sets up pin-based VM-execution controls in the VMCS.
2314 *
2315 * @returns VBox status code.
2316 * @param pVM The cross context VM structure.
2317 * @param pVCpu The cross context virtual CPU structure.
2318 */
2319static int hmR0VmxSetupPinCtls(PVM pVM, PVMCPU pVCpu)
2320{
2321 AssertPtr(pVM);
2322 AssertPtr(pVCpu);
2323
2324 uint32_t val = pVM->hm.s.vmx.Msrs.VmxPinCtls.n.disallowed0; /* Bits set here must always be set. */
2325 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
2326
2327 val |= VMX_VMCS_CTRL_PIN_EXEC_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
2328 | VMX_VMCS_CTRL_PIN_EXEC_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
2329
2330 if (pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
2331 val |= VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
2332
2333 /* Enable the VMX preemption timer. */
2334 if (pVM->hm.s.vmx.fUsePreemptTimer)
2335 {
2336 Assert(pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_PREEMPT_TIMER);
2337 val |= VMX_VMCS_CTRL_PIN_EXEC_PREEMPT_TIMER;
2338 }
2339
2340#if 0
2341 /* Enable posted-interrupt processing. */
2342 if (pVM->hm.s.fPostedIntrs)
2343 {
2344 Assert(pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_POSTED_INTR);
2345 Assert(pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT);
2346 val |= VMX_VMCS_CTRL_PIN_EXEC_POSTED_INTR;
2347 }
2348#endif
2349
2350 if ((val & zap) != val)
2351 {
2352 LogRel(("hmR0VmxSetupPinCtls: Invalid pin-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
2353 pVM->hm.s.vmx.Msrs.VmxPinCtls.n.disallowed0, val, zap));
2354 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
2355 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2356 }
2357
2358 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, val);
2359 AssertRCReturn(rc, rc);
2360
2361 pVCpu->hm.s.vmx.u32PinCtls = val;
2362 return rc;
2363}
2364
2365
2366/**
2367 * Sets up processor-based VM-execution controls in the VMCS.
2368 *
2369 * @returns VBox status code.
2370 * @param pVM The cross context VM structure.
2371 * @param pVCpu The cross context virtual CPU structure.
2372 */
2373static int hmR0VmxSetupProcCtls(PVM pVM, PVMCPU pVCpu)
2374{
2375 AssertPtr(pVM);
2376 AssertPtr(pVCpu);
2377
2378 int rc = VERR_INTERNAL_ERROR_5;
2379 uint32_t val = pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0; /* Bits set here must be set in the VMCS. */
2380 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2381
2382 val |= VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT /* HLT causes a VM-exit. */
2383 | VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
2384 | VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
2385 | VMX_VMCS_CTRL_PROC_EXEC_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
2386 | VMX_VMCS_CTRL_PROC_EXEC_RDPMC_EXIT /* RDPMC causes a VM-exit. */
2387 | VMX_VMCS_CTRL_PROC_EXEC_MONITOR_EXIT /* MONITOR causes a VM-exit. */
2388 | VMX_VMCS_CTRL_PROC_EXEC_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
2389
2390 /* We toggle VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
2391 if ( !(pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT)
2392 || (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0 & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT))
2393 {
2394 LogRel(("hmR0VmxSetupProcCtls: Unsupported VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT combo!"));
2395 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
2396 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2397 }
2398
2399 /* Without Nested Paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
2400 if (!pVM->hm.s.fNestedPaging)
2401 {
2402 Assert(!pVM->hm.s.vmx.fUnrestrictedGuest); /* Paranoia. */
2403 val |= VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT
2404 | VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
2405 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
2406 }
2407
2408 /* Use TPR shadowing if supported by the CPU. */
2409 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
2410 {
2411 Assert(pVCpu->hm.s.vmx.HCPhysVirtApic);
2412 Assert(!(pVCpu->hm.s.vmx.HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
2413 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, 0);
2414 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VAPIC_PAGEADDR_FULL, pVCpu->hm.s.vmx.HCPhysVirtApic);
2415 AssertRCReturn(rc, rc);
2416
2417 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
2418 /* CR8 writes cause a VM-exit based on TPR threshold. */
2419 Assert(!(val & VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT));
2420 Assert(!(val & VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT));
2421 }
2422 else
2423 {
2424 /*
2425 * Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is invalid on 32-bit Intel CPUs.
2426 * Set this control only for 64-bit guests.
2427 */
2428 if (pVM->hm.s.fAllow64BitGuests)
2429 {
2430 val |= VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
2431 | VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
2432 }
2433 }
2434
2435 /* Use MSR-bitmaps if supported by the CPU. */
2436 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
2437 {
2438 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS;
2439
2440 Assert(pVCpu->hm.s.vmx.HCPhysMsrBitmap);
2441 Assert(!(pVCpu->hm.s.vmx.HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
2442 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, pVCpu->hm.s.vmx.HCPhysMsrBitmap);
2443 AssertRCReturn(rc, rc);
2444
2445 /*
2446 * The guest can access the following MSRs (read, write) without causing VM-exits; they are loaded/stored
2447 * automatically using dedicated fields in the VMCS.
2448 */
2449 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_CS, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2450 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_ESP, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2451 hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_EIP, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2452 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2453 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_FS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2454
2455#if HC_ARCH_BITS == 64
2456 /*
2457 * Set passthru permissions for the following MSRs (mandatory for VT-x) required for 64-bit guests.
2458 */
2459 if (pVM->hm.s.fAllow64BitGuests)
2460 {
2461 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_LSTAR, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2462 hmR0VmxSetMsrPermission(pVCpu, MSR_K6_STAR, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2463 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_SF_MASK, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2464 hmR0VmxSetMsrPermission(pVCpu, MSR_K8_KERNEL_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
2465 }
2466#endif
2467 /* Though MSR_IA32_PERF_GLOBAL_CTRL is saved/restored lazily, we want intercept reads/write to it for now. */
2468 }
2469
2470 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
2471 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
2472 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL;
2473
2474 if ((val & zap) != val)
2475 {
2476 LogRel(("hmR0VmxSetupProcCtls: Invalid processor-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
2477 pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0, val, zap));
2478 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
2479 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2480 }
2481
2482 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, val);
2483 AssertRCReturn(rc, rc);
2484
2485 pVCpu->hm.s.vmx.u32ProcCtls = val;
2486
2487 /*
2488 * Secondary processor-based VM-execution controls.
2489 */
2490 if (RT_LIKELY(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL))
2491 {
2492 val = pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.disallowed0; /* Bits set here must be set in the VMCS. */
2493 zap = pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
2494
2495 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT)
2496 val |= VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT; /* WBINVD causes a VM-exit. */
2497
2498 if (pVM->hm.s.fNestedPaging)
2499 val |= VMX_VMCS_CTRL_PROC_EXEC2_EPT; /* Enable EPT. */
2500 else
2501 {
2502 /*
2503 * Without Nested Paging, INVPCID should cause a VM-exit. Enabling this bit causes the CPU to refer to
2504 * VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT when INVPCID is executed by the guest.
2505 * See Intel spec. 25.4 "Changes to instruction behaviour in VMX non-root operation".
2506 */
2507 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_INVPCID)
2508 val |= VMX_VMCS_CTRL_PROC_EXEC2_INVPCID;
2509 }
2510
2511 if (pVM->hm.s.vmx.fVpid)
2512 val |= VMX_VMCS_CTRL_PROC_EXEC2_VPID; /* Enable VPID. */
2513
2514 if (pVM->hm.s.vmx.fUnrestrictedGuest)
2515 val |= VMX_VMCS_CTRL_PROC_EXEC2_UNRESTRICTED_GUEST; /* Enable Unrestricted Execution. */
2516
2517#if 0
2518 if (pVM->hm.s.fVirtApicRegs)
2519 {
2520 Assert(pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_APIC_REG_VIRT);
2521 val |= VMX_VMCS_CTRL_PROC_EXEC2_APIC_REG_VIRT; /* Enable APIC-register virtualization. */
2522
2523 Assert(pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_INTR_DELIVERY);
2524 val |= VMX_VMCS_CTRL_PROC_EXEC2_VIRT_INTR_DELIVERY; /* Enable virtual-interrupt delivery. */
2525 }
2526#endif
2527
2528 /* Enable Virtual-APIC page accesses if supported by the CPU. This is essentially where the TPR shadow resides. */
2529 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
2530 * done dynamically. */
2531 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC)
2532 {
2533 Assert(pVM->hm.s.vmx.HCPhysApicAccess);
2534 Assert(!(pVM->hm.s.vmx.HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
2535 val |= VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC; /* Virtualize APIC accesses. */
2536 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, pVM->hm.s.vmx.HCPhysApicAccess);
2537 AssertRCReturn(rc, rc);
2538 }
2539
2540 if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP)
2541 val |= VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP; /* Enable RDTSCP support. */
2542
2543 if ( pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_PAUSE_LOOP_EXIT
2544 && pVM->hm.s.vmx.cPleGapTicks
2545 && pVM->hm.s.vmx.cPleWindowTicks)
2546 {
2547 val |= VMX_VMCS_CTRL_PROC_EXEC2_PAUSE_LOOP_EXIT; /* Enable pause-loop exiting. */
2548
2549 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks);
2550 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks);
2551 AssertRCReturn(rc, rc);
2552 }
2553
2554 if ((val & zap) != val)
2555 {
2556 LogRel(("hmR0VmxSetupProcCtls: Invalid secondary processor-based VM-execution controls combo! "
2557 "cpu=%#RX64 val=%#RX64 zap=%#RX64\n", pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.disallowed0, val, zap));
2558 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
2559 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2560 }
2561
2562 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, val);
2563 AssertRCReturn(rc, rc);
2564
2565 pVCpu->hm.s.vmx.u32ProcCtls2 = val;
2566 }
2567 else if (RT_UNLIKELY(pVM->hm.s.vmx.fUnrestrictedGuest))
2568 {
2569 LogRel(("hmR0VmxSetupProcCtls: Unrestricted Guest set as true when secondary processor-based VM-execution controls not "
2570 "available\n"));
2571 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
2572 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2573 }
2574
2575 return VINF_SUCCESS;
2576}
2577
2578
2579/**
2580 * Sets up miscellaneous (everything other than Pin & Processor-based
2581 * VM-execution) control fields in the VMCS.
2582 *
2583 * @returns VBox status code.
2584 * @param pVM The cross context VM structure.
2585 * @param pVCpu The cross context virtual CPU structure.
2586 */
2587static int hmR0VmxSetupMiscCtls(PVM pVM, PVMCPU pVCpu)
2588{
2589 NOREF(pVM);
2590 AssertPtr(pVM);
2591 AssertPtr(pVCpu);
2592
2593 int rc = VERR_GENERAL_FAILURE;
2594
2595 /* All fields are zero-initialized during allocation; but don't remove the commented block below. */
2596#if 0
2597 /* All CR3 accesses cause VM-exits. Later we optimize CR3 accesses (see hmR0VmxLoadGuestCR3AndCR4())*/
2598 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_CR3_TARGET_COUNT, 0);
2599 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, 0);
2600
2601 /*
2602 * Set MASK & MATCH to 0. VMX checks if GuestPFErrCode & MASK == MATCH. If equal (in our case it always is)
2603 * 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.
2604 * We thus use the exception bitmap to control it rather than use both.
2605 */
2606 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, 0);
2607 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, 0);
2608
2609 /** @todo Explore possibility of using IO-bitmaps. */
2610 /* All IO & IOIO instructions cause VM-exits. */
2611 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_IO_BITMAP_A_FULL, 0);
2612 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_IO_BITMAP_B_FULL, 0);
2613
2614 /* Initialize the MSR-bitmap area. */
2615 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, 0);
2616 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, 0);
2617 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, 0);
2618 AssertRCReturn(rc, rc);
2619#endif
2620
2621 /* Setup MSR auto-load/store area. */
2622 Assert(pVCpu->hm.s.vmx.HCPhysGuestMsr);
2623 Assert(!(pVCpu->hm.s.vmx.HCPhysGuestMsr & 0xf)); /* Lower 4 bits MBZ. */
2624 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, pVCpu->hm.s.vmx.HCPhysGuestMsr);
2625 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, pVCpu->hm.s.vmx.HCPhysGuestMsr);
2626 AssertRCReturn(rc, rc);
2627
2628 Assert(pVCpu->hm.s.vmx.HCPhysHostMsr);
2629 Assert(!(pVCpu->hm.s.vmx.HCPhysHostMsr & 0xf)); /* Lower 4 bits MBZ. */
2630 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, pVCpu->hm.s.vmx.HCPhysHostMsr);
2631 AssertRCReturn(rc, rc);
2632
2633 /* Set VMCS link pointer. Reserved for future use, must be -1. Intel spec. 24.4 "Guest-State Area". */
2634 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, UINT64_C(0xffffffffffffffff));
2635 AssertRCReturn(rc, rc);
2636
2637 /* All fields are zero-initialized during allocation; but don't remove the commented block below. */
2638#if 0
2639 /* Setup debug controls */
2640 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, 0); /** @todo We don't support IA32_DEBUGCTL MSR. Should we? */
2641 rc |= VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, 0);
2642 AssertRCReturn(rc, rc);
2643#endif
2644
2645 return rc;
2646}
2647
2648
2649/**
2650 * Sets up the initial exception bitmap in the VMCS based on static conditions.
2651 *
2652 * We shall setup those exception intercepts that don't change during the
2653 * lifetime of the VM here. The rest are done dynamically while loading the
2654 * guest state.
2655 *
2656 * @returns VBox status code.
2657 * @param pVM The cross context VM structure.
2658 * @param pVCpu The cross context virtual CPU structure.
2659 */
2660static int hmR0VmxInitXcptBitmap(PVM pVM, PVMCPU pVCpu)
2661{
2662 AssertPtr(pVM);
2663 AssertPtr(pVCpu);
2664
2665 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
2666
2667 uint32_t u32XcptBitmap = 0;
2668
2669 /* Must always intercept #AC to prevent the guest from hanging the CPU. */
2670 u32XcptBitmap |= RT_BIT_32(X86_XCPT_AC);
2671
2672 /* Because we need to maintain the DR6 state even when intercepting DRx reads
2673 and writes, and because recursive #DBs can cause the CPU hang, we must always
2674 intercept #DB. */
2675 u32XcptBitmap |= RT_BIT_32(X86_XCPT_DB);
2676
2677 /* Without Nested Paging, #PF must cause a VM-exit so we can sync our shadow page tables. */
2678 if (!pVM->hm.s.fNestedPaging)
2679 u32XcptBitmap |= RT_BIT(X86_XCPT_PF);
2680
2681 pVCpu->hm.s.vmx.u32XcptBitmap = u32XcptBitmap;
2682 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
2683 AssertRCReturn(rc, rc);
2684 return rc;
2685}
2686
2687
2688/**
2689 * Sets up the initial guest-state mask. The guest-state mask is consulted
2690 * before reading guest-state fields from the VMCS as VMREADs can be expensive
2691 * for the nested virtualization case (as it would cause a VM-exit).
2692 *
2693 * @param pVCpu The cross context virtual CPU structure.
2694 */
2695static int hmR0VmxInitUpdatedGuestStateMask(PVMCPU pVCpu)
2696{
2697 /* Initially the guest-state is up-to-date as there is nothing in the VMCS. */
2698 HMVMXCPU_GST_RESET_TO(pVCpu, HMVMX_UPDATED_GUEST_ALL);
2699 return VINF_SUCCESS;
2700}
2701
2702
2703/**
2704 * Does per-VM VT-x initialization.
2705 *
2706 * @returns VBox status code.
2707 * @param pVM The cross context VM structure.
2708 */
2709VMMR0DECL(int) VMXR0InitVM(PVM pVM)
2710{
2711 LogFlowFunc(("pVM=%p\n", pVM));
2712
2713 int rc = hmR0VmxStructsAlloc(pVM);
2714 if (RT_FAILURE(rc))
2715 {
2716 LogRel(("VMXR0InitVM: hmR0VmxStructsAlloc failed! rc=%Rrc\n", rc));
2717 return rc;
2718 }
2719
2720 return VINF_SUCCESS;
2721}
2722
2723
2724/**
2725 * Does per-VM VT-x termination.
2726 *
2727 * @returns VBox status code.
2728 * @param pVM The cross context VM structure.
2729 */
2730VMMR0DECL(int) VMXR0TermVM(PVM pVM)
2731{
2732 LogFlowFunc(("pVM=%p\n", pVM));
2733
2734#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2735 if (pVM->hm.s.vmx.hMemObjScratch != NIL_RTR0MEMOBJ)
2736 ASMMemZero32(pVM->hm.s.vmx.pvScratch, PAGE_SIZE);
2737#endif
2738 hmR0VmxStructsFree(pVM);
2739 return VINF_SUCCESS;
2740}
2741
2742
2743/**
2744 * Sets up the VM for execution under VT-x.
2745 * This function is only called once per-VM during initialization.
2746 *
2747 * @returns VBox status code.
2748 * @param pVM The cross context VM structure.
2749 */
2750VMMR0DECL(int) VMXR0SetupVM(PVM pVM)
2751{
2752 AssertPtrReturn(pVM, VERR_INVALID_PARAMETER);
2753 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2754
2755 LogFlowFunc(("pVM=%p\n", pVM));
2756
2757 /*
2758 * Without UnrestrictedGuest, pRealModeTSS and pNonPagingModeEPTPageTable *must* always be allocated.
2759 * We no longer support the highly unlikely case of UnrestrictedGuest without pRealModeTSS. See hmR3InitFinalizeR0Intel().
2760 */
2761 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
2762 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
2763 || !pVM->hm.s.vmx.pRealModeTSS))
2764 {
2765 LogRel(("VMXR0SetupVM: Invalid real-on-v86 state.\n"));
2766 return VERR_INTERNAL_ERROR;
2767 }
2768
2769 /* Initialize these always, see hmR3InitFinalizeR0().*/
2770 pVM->hm.s.vmx.enmFlushEpt = VMXFLUSHEPT_NONE;
2771 pVM->hm.s.vmx.enmFlushVpid = VMXFLUSHVPID_NONE;
2772
2773 /* Setup the tagged-TLB flush handlers. */
2774 int rc = hmR0VmxSetupTaggedTlb(pVM);
2775 if (RT_FAILURE(rc))
2776 {
2777 LogRel(("VMXR0SetupVM: hmR0VmxSetupTaggedTlb failed! rc=%Rrc\n", rc));
2778 return rc;
2779 }
2780
2781 /* Check if we can use the VMCS controls for swapping the EFER MSR. */
2782 Assert(!pVM->hm.s.vmx.fSupportsVmcsEfer);
2783#if HC_ARCH_BITS == 64
2784 if ( (pVM->hm.s.vmx.Msrs.VmxEntry.n.allowed1 & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR)
2785 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR)
2786 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR))
2787 {
2788 pVM->hm.s.vmx.fSupportsVmcsEfer = true;
2789 }
2790#endif
2791
2792 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
2793 RTCCUINTREG uHostCR4 = ASMGetCR4();
2794 if (RT_UNLIKELY(!(uHostCR4 & X86_CR4_VMXE)))
2795 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
2796
2797 for (VMCPUID i = 0; i < pVM->cCpus; i++)
2798 {
2799 PVMCPU pVCpu = &pVM->aCpus[i];
2800 AssertPtr(pVCpu);
2801 AssertPtr(pVCpu->hm.s.vmx.pvVmcs);
2802
2803 /* Log the VCPU pointers, useful for debugging SMP VMs. */
2804 Log4(("VMXR0SetupVM: pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
2805
2806 /* Initialize the VM-exit history array with end-of-array markers (UINT16_MAX). */
2807 Assert(!pVCpu->hm.s.idxExitHistoryFree);
2808 HMCPU_EXIT_HISTORY_RESET(pVCpu);
2809
2810 /* Set revision dword at the beginning of the VMCS structure. */
2811 *(uint32_t *)pVCpu->hm.s.vmx.pvVmcs = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.Msrs.u64BasicInfo);
2812
2813 /* Initialize our VMCS region in memory, set the VMCS launch state to "clear". */
2814 rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2815 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVmcs failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2816 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2817
2818 /* Load this VMCS as the current VMCS. */
2819 rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2820 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXActivateVmcs failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2821 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2822
2823 rc = hmR0VmxSetupPinCtls(pVM, pVCpu);
2824 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupPinCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2825 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2826
2827 rc = hmR0VmxSetupProcCtls(pVM, pVCpu);
2828 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupProcCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2829 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2830
2831 rc = hmR0VmxSetupMiscCtls(pVM, pVCpu);
2832 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupMiscCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2833 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2834
2835 rc = hmR0VmxInitXcptBitmap(pVM, pVCpu);
2836 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitXcptBitmap failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2837 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2838
2839 rc = hmR0VmxInitUpdatedGuestStateMask(pVCpu);
2840 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitUpdatedGuestStateMask failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2841 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2842
2843#if HC_ARCH_BITS == 32
2844 rc = hmR0VmxInitVmcsReadCache(pVM, pVCpu);
2845 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitVmcsReadCache failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2846 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2847#endif
2848
2849 /* Re-sync the CPU's internal data into our VMCS memory region & reset the launch state to "clear". */
2850 rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
2851 AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVmcs(2) failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
2852 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc), rc);
2853
2854 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
2855
2856 hmR0VmxUpdateErrorRecord(pVM, pVCpu, rc);
2857 }
2858
2859 return VINF_SUCCESS;
2860}
2861
2862
2863/**
2864 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
2865 * the VMCS.
2866 *
2867 * @returns VBox status code.
2868 * @param pVM The cross context VM structure.
2869 * @param pVCpu The cross context virtual CPU structure.
2870 */
2871DECLINLINE(int) hmR0VmxSaveHostControlRegs(PVM pVM, PVMCPU pVCpu)
2872{
2873 NOREF(pVM); NOREF(pVCpu);
2874
2875 RTCCUINTREG uReg = ASMGetCR0();
2876 int rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR0, uReg);
2877 AssertRCReturn(rc, rc);
2878
2879 uReg = ASMGetCR3();
2880 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR3, uReg);
2881 AssertRCReturn(rc, rc);
2882
2883 uReg = ASMGetCR4();
2884 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_CR4, uReg);
2885 AssertRCReturn(rc, rc);
2886 return rc;
2887}
2888
2889
2890#if HC_ARCH_BITS == 64
2891/**
2892 * Macro for adjusting host segment selectors to satisfy VT-x's VM-entry
2893 * requirements. See hmR0VmxSaveHostSegmentRegs().
2894 */
2895# define VMXLOCAL_ADJUST_HOST_SEG(seg, selValue) \
2896 if ((selValue) & (X86_SEL_RPL | X86_SEL_LDT)) \
2897 { \
2898 bool fValidSelector = true; \
2899 if ((selValue) & X86_SEL_LDT) \
2900 { \
2901 uint32_t uAttr = ASMGetSegAttr((selValue)); \
2902 fValidSelector = RT_BOOL(uAttr != UINT32_MAX && (uAttr & X86_DESC_P)); \
2903 } \
2904 if (fValidSelector) \
2905 { \
2906 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##seg; \
2907 pVCpu->hm.s.vmx.RestoreHost.uHostSel##seg = (selValue); \
2908 } \
2909 (selValue) = 0; \
2910 }
2911#endif
2912
2913
2914/**
2915 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
2916 * the host-state area in the VMCS.
2917 *
2918 * @returns VBox status code.
2919 * @param pVM The cross context VM structure.
2920 * @param pVCpu The cross context virtual CPU structure.
2921 */
2922DECLINLINE(int) hmR0VmxSaveHostSegmentRegs(PVM pVM, PVMCPU pVCpu)
2923{
2924 int rc = VERR_INTERNAL_ERROR_5;
2925
2926#if HC_ARCH_BITS == 64
2927 /*
2928 * If we've executed guest code using VT-x, the host-state bits will be messed up. We
2929 * should -not- save the messed up state without restoring the original host-state. See @bugref{7240}.
2930 *
2931 * This apparently can happen (most likely the FPU changes), deal with it rather than asserting.
2932 * Was observed booting Solaris10u10 32-bit guest.
2933 */
2934 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
2935 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
2936 {
2937 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags,
2938 pVCpu->idCpu));
2939 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
2940 }
2941 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
2942#else
2943 RT_NOREF(pVCpu);
2944#endif
2945
2946 /*
2947 * Host DS, ES, FS and GS segment registers.
2948 */
2949#if HC_ARCH_BITS == 64
2950 RTSEL uSelDS = ASMGetDS();
2951 RTSEL uSelES = ASMGetES();
2952 RTSEL uSelFS = ASMGetFS();
2953 RTSEL uSelGS = ASMGetGS();
2954#else
2955 RTSEL uSelDS = 0;
2956 RTSEL uSelES = 0;
2957 RTSEL uSelFS = 0;
2958 RTSEL uSelGS = 0;
2959#endif
2960
2961 /*
2962 * Host CS and SS segment registers.
2963 */
2964 RTSEL uSelCS = ASMGetCS();
2965 RTSEL uSelSS = ASMGetSS();
2966
2967 /*
2968 * Host TR segment register.
2969 */
2970 RTSEL uSelTR = ASMGetTR();
2971
2972#if HC_ARCH_BITS == 64
2973 /*
2974 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to gain VM-entry and restore them
2975 * before we get preempted. See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
2976 */
2977 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
2978 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
2979 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
2980 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
2981# undef VMXLOCAL_ADJUST_HOST_SEG
2982#endif
2983
2984 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
2985 Assert(!(uSelCS & X86_SEL_RPL)); Assert(!(uSelCS & X86_SEL_LDT));
2986 Assert(!(uSelSS & X86_SEL_RPL)); Assert(!(uSelSS & X86_SEL_LDT));
2987 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
2988 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
2989 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
2990 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
2991 Assert(!(uSelTR & X86_SEL_RPL)); Assert(!(uSelTR & X86_SEL_LDT));
2992 Assert(uSelCS);
2993 Assert(uSelTR);
2994
2995 /* Assertion is right but we would not have updated u32ExitCtls yet. */
2996#if 0
2997 if (!(pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE))
2998 Assert(uSelSS != 0);
2999#endif
3000
3001 /* Write these host selector fields into the host-state area in the VMCS. */
3002 rc = VMXWriteVmcs32(VMX_VMCS16_HOST_CS_SEL, uSelCS);
3003 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_SS_SEL, uSelSS);
3004#if HC_ARCH_BITS == 64
3005 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_DS_SEL, uSelDS);
3006 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_ES_SEL, uSelES);
3007 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_FS_SEL, uSelFS);
3008 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_GS_SEL, uSelGS);
3009#else
3010 NOREF(uSelDS);
3011 NOREF(uSelES);
3012 NOREF(uSelFS);
3013 NOREF(uSelGS);
3014#endif
3015 rc |= VMXWriteVmcs32(VMX_VMCS16_HOST_TR_SEL, uSelTR);
3016 AssertRCReturn(rc, rc);
3017
3018 /*
3019 * Host GDTR and IDTR.
3020 */
3021 RTGDTR Gdtr;
3022 RTIDTR Idtr;
3023 RT_ZERO(Gdtr);
3024 RT_ZERO(Idtr);
3025 ASMGetGDTR(&Gdtr);
3026 ASMGetIDTR(&Idtr);
3027 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_GDTR_BASE, Gdtr.pGdt);
3028 rc |= VMXWriteVmcsHstN(VMX_VMCS_HOST_IDTR_BASE, Idtr.pIdt);
3029 AssertRCReturn(rc, rc);
3030
3031#if HC_ARCH_BITS == 64
3032 /*
3033 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps them to the
3034 * maximum limit (0xffff) on every VM-exit.
3035 */
3036 if (Gdtr.cbGdt != 0xffff)
3037 {
3038 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
3039 AssertCompile(sizeof(Gdtr) == sizeof(X86XDTR64));
3040 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
3041 }
3042
3043 /*
3044 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT"
3045 * and Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit as 0xfff, VT-x
3046 * bloating the limit to 0xffff shouldn't cause any different CPU behavior. However, several hosts either insists
3047 * on 0xfff being the limit (Windows Patch Guard) or uses the limit for other purposes (darwin puts the CPU ID in there
3048 * but botches sidt alignment in at least one consumer). So, we're only allowing IDTR.LIMIT to be left at 0xffff on
3049 * hosts where we are pretty sure it won't cause trouble.
3050 */
3051# if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
3052 if (Idtr.cbIdt < 0x0fff)
3053# else
3054 if (Idtr.cbIdt != 0xffff)
3055# endif
3056 {
3057 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
3058 AssertCompile(sizeof(Idtr) == sizeof(X86XDTR64));
3059 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostIdtr, &Idtr, sizeof(X86XDTR64));
3060 }
3061#endif
3062
3063 /*
3064 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI and RPL bits
3065 * is effectively what the CPU does for "scaling by 8". TI is always 0 and RPL should be too in most cases.
3066 */
3067 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= Gdtr.cbGdt,
3068 ("hmR0VmxSaveHostSegmentRegs: TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, Gdtr.cbGdt),
3069 VERR_VMX_INVALID_HOST_STATE);
3070
3071 PCX86DESCHC pDesc = (PCX86DESCHC)(Gdtr.pGdt + (uSelTR & X86_SEL_MASK));
3072#if HC_ARCH_BITS == 64
3073 uintptr_t uTRBase = X86DESC64_BASE(pDesc);
3074
3075 /*
3076 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on all VM-exits.
3077 * The type is the same for 64-bit busy TSS[1]. The limit needs manual restoration if the host has something else.
3078 * Task switching is not supported in 64-bit mode[2], but the limit still matters as IOPM is supported in 64-bit mode.
3079 * Restoring the limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
3080 *
3081 * [1] See Intel spec. 3.5 "System Descriptor Types".
3082 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
3083 */
3084 Assert(pDesc->System.u4Type == 11);
3085 if ( pDesc->System.u16LimitLow != 0x67
3086 || pDesc->System.u4LimitHigh)
3087 {
3088 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
3089 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
3090 if (pVM->hm.s.fHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
3091 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
3092 pVCpu->hm.s.vmx.RestoreHost.uHostSelTR = uSelTR;
3093
3094 /* Store the GDTR here as we need it while restoring TR. */
3095 memcpy(&pVCpu->hm.s.vmx.RestoreHost.HostGdtr, &Gdtr, sizeof(X86XDTR64));
3096 }
3097#else
3098 NOREF(pVM);
3099 uintptr_t uTRBase = X86DESC_BASE(pDesc);
3100#endif
3101 rc = VMXWriteVmcsHstN(VMX_VMCS_HOST_TR_BASE, uTRBase);
3102 AssertRCReturn(rc, rc);
3103
3104 /*
3105 * Host FS base and GS base.
3106 */
3107#if HC_ARCH_BITS == 64
3108 uint64_t u64FSBase = ASMRdMsr(MSR_K8_FS_BASE);
3109 uint64_t u64GSBase = ASMRdMsr(MSR_K8_GS_BASE);
3110 rc = VMXWriteVmcs64(VMX_VMCS_HOST_FS_BASE, u64FSBase);
3111 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_GS_BASE, u64GSBase);
3112 AssertRCReturn(rc, rc);
3113
3114 /* Store the base if we have to restore FS or GS manually as we need to restore the base as well. */
3115 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_FS)
3116 pVCpu->hm.s.vmx.RestoreHost.uHostFSBase = u64FSBase;
3117 if (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_SEL_GS)
3118 pVCpu->hm.s.vmx.RestoreHost.uHostGSBase = u64GSBase;
3119#endif
3120 return rc;
3121}
3122
3123
3124/**
3125 * Saves certain host MSRs in the VM-exit MSR-load area and some in the
3126 * host-state area of the VMCS. Theses MSRs will be automatically restored on
3127 * the host after every successful VM-exit.
3128 *
3129 * @returns VBox status code.
3130 * @param pVM The cross context VM structure.
3131 * @param pVCpu The cross context virtual CPU structure.
3132 *
3133 * @remarks No-long-jump zone!!!
3134 */
3135DECLINLINE(int) hmR0VmxSaveHostMsrs(PVM pVM, PVMCPU pVCpu)
3136{
3137 NOREF(pVM);
3138
3139 AssertPtr(pVCpu);
3140 AssertPtr(pVCpu->hm.s.vmx.pvHostMsr);
3141
3142 /*
3143 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
3144 * rather than swapping them on every VM-entry.
3145 */
3146 hmR0VmxLazySaveHostMsrs(pVCpu);
3147
3148 /*
3149 * Host Sysenter MSRs.
3150 */
3151 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS));
3152#if HC_ARCH_BITS == 32
3153 rc |= VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP));
3154 rc |= VMXWriteVmcs32(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP));
3155#else
3156 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP));
3157 rc |= VMXWriteVmcs64(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP));
3158#endif
3159 AssertRCReturn(rc, rc);
3160
3161 /*
3162 * Host EFER MSR.
3163 * If the CPU supports the newer VMCS controls for managing EFER, use it.
3164 * Otherwise it's done as part of auto-load/store MSR area in the VMCS, see hmR0VmxLoadGuestMsrs().
3165 */
3166 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
3167 {
3168 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, pVM->hm.s.vmx.u64HostEfer);
3169 AssertRCReturn(rc, rc);
3170 }
3171
3172 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
3173 * hmR0VmxLoadGuestExitCtls() !! */
3174
3175 return rc;
3176}
3177
3178
3179/**
3180 * Figures out if we need to swap the EFER MSR which is particularly expensive.
3181 *
3182 * We check all relevant bits. For now, that's everything besides LMA/LME, as
3183 * these two bits are handled by VM-entry, see hmR0VmxLoadGuestExitCtls() and
3184 * hmR0VMxLoadGuestEntryCtls().
3185 *
3186 * @returns true if we need to load guest EFER, false otherwise.
3187 * @param pVCpu The cross context virtual CPU structure.
3188 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3189 * out-of-sync. Make sure to update the required fields
3190 * before using them.
3191 *
3192 * @remarks Requires EFER, CR4.
3193 * @remarks No-long-jump zone!!!
3194 */
3195static bool hmR0VmxShouldSwapEferMsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3196{
3197#ifdef HMVMX_ALWAYS_SWAP_EFER
3198 return true;
3199#endif
3200
3201#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
3202 /* For 32-bit hosts running 64-bit guests, we always swap EFER in the world-switcher. Nothing to do here. */
3203 if (CPUMIsGuestInLongMode(pVCpu))
3204 return false;
3205#endif
3206
3207 PVM pVM = pVCpu->CTX_SUFF(pVM);
3208 uint64_t u64HostEfer = pVM->hm.s.vmx.u64HostEfer;
3209 uint64_t u64GuestEfer = pMixedCtx->msrEFER;
3210
3211 /*
3212 * For 64-bit guests, if EFER.SCE bit differs, we need to swap to ensure that the
3213 * guest's SYSCALL behaviour isn't screwed. See @bugref{7386}.
3214 */
3215 if ( CPUMIsGuestInLongMode(pVCpu)
3216 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
3217 {
3218 return true;
3219 }
3220
3221 /*
3222 * If the guest uses PAE and EFER.NXE bit differs, we need to swap EFER as it
3223 * affects guest paging. 64-bit paging implies CR4.PAE as well.
3224 * See Intel spec. 4.5 "IA-32e Paging" and Intel spec. 4.1.1 "Three Paging Modes".
3225 */
3226 if ( (pMixedCtx->cr4 & X86_CR4_PAE)
3227 && (pMixedCtx->cr0 & X86_CR0_PG)
3228 && (u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
3229 {
3230 /* Assert that host is PAE capable. */
3231 Assert(pVM->hm.s.cpuid.u32AMDFeatureEDX & X86_CPUID_EXT_FEATURE_EDX_NX);
3232 return true;
3233 }
3234
3235 /** @todo Check the latest Intel spec. for any other bits,
3236 * like SMEP/SMAP? */
3237 return false;
3238}
3239
3240
3241/**
3242 * Sets up VM-entry controls in the VMCS. These controls can affect things done
3243 * on VM-exit; e.g. "load debug controls", see Intel spec. 24.8.1 "VM-entry
3244 * controls".
3245 *
3246 * @returns VBox status code.
3247 * @param pVCpu The cross context virtual CPU structure.
3248 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3249 * out-of-sync. Make sure to update the required fields
3250 * before using them.
3251 *
3252 * @remarks Requires EFER.
3253 * @remarks No-long-jump zone!!!
3254 */
3255DECLINLINE(int) hmR0VmxLoadGuestEntryCtls(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3256{
3257 int rc = VINF_SUCCESS;
3258 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_ENTRY_CTLS))
3259 {
3260 PVM pVM = pVCpu->CTX_SUFF(pVM);
3261 uint32_t val = pVM->hm.s.vmx.Msrs.VmxEntry.n.disallowed0; /* Bits set here must be set in the VMCS. */
3262 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxEntry.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3263
3264 /* Load debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x capable CPUs only supports the 1-setting of this bit. */
3265 val |= VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG;
3266
3267 /* Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry. */
3268 if (CPUMIsGuestInLongModeEx(pMixedCtx))
3269 {
3270 val |= VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST;
3271 Log4(("Load[%RU32]: VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST\n", pVCpu->idCpu));
3272 }
3273 else
3274 Assert(!(val & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST));
3275
3276 /* If the CPU supports the newer VMCS controls for managing guest/host EFER, use it. */
3277 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
3278 && hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
3279 {
3280 val |= VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR;
3281 Log4(("Load[%RU32]: VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR\n", pVCpu->idCpu));
3282 }
3283
3284 /*
3285 * The following should -not- be set (since we're not in SMM mode):
3286 * - VMX_VMCS_CTRL_ENTRY_ENTRY_SMM
3287 * - VMX_VMCS_CTRL_ENTRY_DEACTIVATE_DUALMON
3288 */
3289
3290 /** @todo VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PERF_MSR,
3291 * VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PAT_MSR. */
3292
3293 if ((val & zap) != val)
3294 {
3295 LogRel(("hmR0VmxLoadGuestEntryCtls: Invalid VM-entry controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
3296 pVM->hm.s.vmx.Msrs.VmxEntry.n.disallowed0, val, zap));
3297 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
3298 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3299 }
3300
3301 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, val);
3302 AssertRCReturn(rc, rc);
3303
3304 pVCpu->hm.s.vmx.u32EntryCtls = val;
3305 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_ENTRY_CTLS);
3306 }
3307 return rc;
3308}
3309
3310
3311/**
3312 * Sets up the VM-exit controls in the VMCS.
3313 *
3314 * @returns VBox status code.
3315 * @param pVCpu The cross context virtual CPU structure.
3316 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3317 * out-of-sync. Make sure to update the required fields
3318 * before using them.
3319 *
3320 * @remarks Requires EFER.
3321 */
3322DECLINLINE(int) hmR0VmxLoadGuestExitCtls(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3323{
3324 NOREF(pMixedCtx);
3325
3326 int rc = VINF_SUCCESS;
3327 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_EXIT_CTLS))
3328 {
3329 PVM pVM = pVCpu->CTX_SUFF(pVM);
3330 uint32_t val = pVM->hm.s.vmx.Msrs.VmxExit.n.disallowed0; /* Bits set here must be set in the VMCS. */
3331 uint32_t zap = pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3332
3333 /* Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only supported the 1-setting of this bit. */
3334 val |= VMX_VMCS_CTRL_EXIT_SAVE_DEBUG;
3335
3336 /*
3337 * Set the host long mode active (EFER.LMA) bit (which Intel calls "Host address-space size") if necessary.
3338 * On VM-exit, VT-x sets both the host EFER.LMA and EFER.LME bit to this value. See assertion in hmR0VmxSaveHostMsrs().
3339 */
3340#if HC_ARCH_BITS == 64
3341 val |= VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE;
3342 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE\n", pVCpu->idCpu));
3343#else
3344 Assert( pVCpu->hm.s.vmx.pfnStartVM == VMXR0SwitcherStartVM64
3345 || pVCpu->hm.s.vmx.pfnStartVM == VMXR0StartVM32);
3346 /* Set the host address-space size based on the switcher, not guest state. See @bugref{8432}. */
3347 if (pVCpu->hm.s.vmx.pfnStartVM == VMXR0SwitcherStartVM64)
3348 {
3349 /* The switcher returns to long mode, EFER is managed by the switcher. */
3350 val |= VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE;
3351 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE\n", pVCpu->idCpu));
3352 }
3353 else
3354 Assert(!(val & VMX_VMCS_CTRL_EXIT_HOST_ADDR_SPACE_SIZE));
3355#endif
3356
3357 /* If the newer VMCS fields for managing EFER exists, use it. */
3358 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
3359 && hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
3360 {
3361 val |= VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR
3362 | VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR;
3363 Log4(("Load[%RU32]: VMX_VMCS_CTRL_EXIT_SAVE_GUEST_EFER_MSR, VMX_VMCS_CTRL_EXIT_LOAD_HOST_EFER_MSR\n", pVCpu->idCpu));
3364 }
3365
3366 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
3367 Assert(!(val & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT));
3368
3369 /** @todo VMX_VMCS_CTRL_EXIT_LOAD_PERF_MSR,
3370 * VMX_VMCS_CTRL_EXIT_SAVE_GUEST_PAT_MSR,
3371 * VMX_VMCS_CTRL_EXIT_LOAD_HOST_PAT_MSR. */
3372
3373 if ( pVM->hm.s.vmx.fUsePreemptTimer
3374 && (pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1 & VMX_VMCS_CTRL_EXIT_SAVE_VMX_PREEMPT_TIMER))
3375 val |= VMX_VMCS_CTRL_EXIT_SAVE_VMX_PREEMPT_TIMER;
3376
3377 if ((val & zap) != val)
3378 {
3379 LogRel(("hmR0VmxSetupProcCtls: Invalid VM-exit controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
3380 pVM->hm.s.vmx.Msrs.VmxExit.n.disallowed0, val, zap));
3381 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
3382 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3383 }
3384
3385 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, val);
3386 AssertRCReturn(rc, rc);
3387
3388 pVCpu->hm.s.vmx.u32ExitCtls = val;
3389 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_EXIT_CTLS);
3390 }
3391 return rc;
3392}
3393
3394
3395/**
3396 * Sets the TPR threshold in the VMCS.
3397 *
3398 * @returns VBox status code.
3399 * @param pVCpu The cross context virtual CPU structure.
3400 * @param u32TprThreshold The TPR threshold (task-priority class only).
3401 */
3402DECLINLINE(int) hmR0VmxApicSetTprThreshold(PVMCPU pVCpu, uint32_t u32TprThreshold)
3403{
3404 Assert(!(u32TprThreshold & 0xfffffff0)); /* Bits 31:4 MBZ. */
3405 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW); RT_NOREF_PV(pVCpu);
3406 return VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
3407}
3408
3409
3410/**
3411 * Loads the guest APIC and related state.
3412 *
3413 * @returns VBox status code.
3414 * @param pVCpu The cross context virtual CPU structure.
3415 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3416 * out-of-sync. Make sure to update the required fields
3417 * before using them.
3418 *
3419 * @remarks No-long-jump zone!!!
3420 */
3421DECLINLINE(int) hmR0VmxLoadGuestApicState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3422{
3423 NOREF(pMixedCtx);
3424
3425 int rc = VINF_SUCCESS;
3426 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE))
3427 {
3428 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
3429 && APICIsEnabled(pVCpu))
3430 {
3431 /*
3432 * Setup TPR shadowing.
3433 */
3434 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
3435 {
3436 Assert(pVCpu->hm.s.vmx.HCPhysVirtApic);
3437
3438 bool fPendingIntr = false;
3439 uint8_t u8Tpr = 0;
3440 uint8_t u8PendingIntr = 0;
3441 rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
3442 AssertRCReturn(rc, rc);
3443
3444 /*
3445 * If there are interrupts pending but masked by the TPR, instruct VT-x to cause a TPR-below-threshold VM-exit
3446 * when the guest lowers its TPR below the priority of the pending interrupt so we can deliver the interrupt.
3447 * If there are no interrupts pending, set threshold to 0 to not cause any TPR-below-threshold VM-exits.
3448 */
3449 pVCpu->hm.s.vmx.pbVirtApic[XAPIC_OFF_TPR] = u8Tpr;
3450 uint32_t u32TprThreshold = 0;
3451 if (fPendingIntr)
3452 {
3453 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR (which is the Task-Priority Class). */
3454 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
3455 const uint8_t u8TprPriority = u8Tpr >> 4;
3456 if (u8PendingPriority <= u8TprPriority)
3457 u32TprThreshold = u8PendingPriority;
3458 }
3459
3460 rc = hmR0VmxApicSetTprThreshold(pVCpu, u32TprThreshold);
3461 AssertRCReturn(rc, rc);
3462 }
3463 }
3464 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
3465 }
3466
3467 return rc;
3468}
3469
3470
3471/**
3472 * Gets the guest's interruptibility-state ("interrupt shadow" as AMD calls it).
3473 *
3474 * @returns Guest's interruptibility-state.
3475 * @param pVCpu The cross context virtual CPU structure.
3476 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3477 * out-of-sync. Make sure to update the required fields
3478 * before using them.
3479 *
3480 * @remarks No-long-jump zone!!!
3481 */
3482DECLINLINE(uint32_t) hmR0VmxGetGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3483{
3484 /*
3485 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
3486 */
3487 uint32_t uIntrState = 0;
3488 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
3489 {
3490 /* If inhibition is active, RIP & RFLAGS should've been accessed (i.e. read previously from the VMCS or from ring-3). */
3491 AssertMsg(HMVMXCPU_GST_IS_SET(pVCpu, HMVMX_UPDATED_GUEST_RIP | HMVMX_UPDATED_GUEST_RFLAGS),
3492 ("%#x\n", HMVMXCPU_GST_VALUE(pVCpu)));
3493 if (pMixedCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
3494 {
3495 if (pMixedCtx->eflags.Bits.u1IF)
3496 uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
3497 else
3498 uIntrState = VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS;
3499 }
3500 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
3501 {
3502 /*
3503 * We can clear the inhibit force flag as even if we go back to the recompiler without executing guest code in
3504 * VT-x, the flag's condition to be cleared is met and thus the cleared state is correct.
3505 */
3506 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
3507 }
3508 }
3509
3510 /*
3511 * NMIs to the guest are blocked after an NMI is injected until the guest executes an IRET. We only
3512 * bother with virtual-NMI blocking when we have support for virtual NMIs in the CPU, otherwise
3513 * setting this would block host-NMIs and IRET will not clear the blocking.
3514 *
3515 * See Intel spec. 26.6.1 "Interruptibility state". See @bugref{7445}.
3516 */
3517 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS)
3518 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
3519 {
3520 uIntrState |= VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI;
3521 }
3522
3523 return uIntrState;
3524}
3525
3526
3527/**
3528 * Loads the guest's interruptibility-state into the guest-state area in the
3529 * VMCS.
3530 *
3531 * @returns VBox status code.
3532 * @param pVCpu The cross context virtual CPU structure.
3533 * @param uIntrState The interruptibility-state to set.
3534 */
3535static int hmR0VmxLoadGuestIntrState(PVMCPU pVCpu, uint32_t uIntrState)
3536{
3537 NOREF(pVCpu);
3538 AssertMsg(!(uIntrState & 0xfffffff0), ("%#x\n", uIntrState)); /* Bits 31:4 MBZ. */
3539 Assert((uIntrState & 0x3) != 0x3); /* Block-by-STI and MOV SS cannot be simultaneously set. */
3540 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, uIntrState);
3541 AssertRC(rc);
3542 return rc;
3543}
3544
3545
3546/**
3547 * Loads the exception intercepts required for guest execution in the VMCS.
3548 *
3549 * @returns VBox status code.
3550 * @param pVCpu The cross context virtual CPU structure.
3551 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3552 * out-of-sync. Make sure to update the required fields
3553 * before using them.
3554 */
3555static int hmR0VmxLoadGuestXcptIntercepts(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3556{
3557 NOREF(pMixedCtx);
3558 int rc = VINF_SUCCESS;
3559 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
3560 {
3561 /* The remaining exception intercepts are handled elsewhere, e.g. in hmR0VmxLoadSharedCR0(). */
3562 if (pVCpu->hm.s.fGIMTrapXcptUD)
3563 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_UD);
3564#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
3565 else
3566 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_UD);
3567#endif
3568
3569 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_AC));
3570 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
3571
3572 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
3573 AssertRCReturn(rc, rc);
3574
3575 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
3576 Log4(("Load[%RU32]: VMX_VMCS32_CTRL_EXCEPTION_BITMAP=%#RX64 fContextUseFlags=%#RX32\n", pVCpu->idCpu,
3577 pVCpu->hm.s.vmx.u32XcptBitmap, HMCPU_CF_VALUE(pVCpu)));
3578 }
3579 return rc;
3580}
3581
3582
3583/**
3584 * Loads the guest's RIP 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 hmR0VmxLoadGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3595{
3596 int rc = VINF_SUCCESS;
3597 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RIP))
3598 {
3599 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_RIP, pMixedCtx->rip);
3600 AssertRCReturn(rc, rc);
3601
3602 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RIP);
3603 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RIP=%#RX64 fContextUseFlags=%#RX32\n", pVCpu->idCpu, pMixedCtx->rip,
3604 HMCPU_CF_VALUE(pVCpu)));
3605 }
3606 return rc;
3607}
3608
3609
3610/**
3611 * Loads the guest's RSP into the guest-state area in the VMCS.
3612 *
3613 * @returns VBox status code.
3614 * @param pVCpu The cross context virtual CPU structure.
3615 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3616 * out-of-sync. Make sure to update the required fields
3617 * before using them.
3618 *
3619 * @remarks No-long-jump zone!!!
3620 */
3621static int hmR0VmxLoadGuestRsp(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3622{
3623 int rc = VINF_SUCCESS;
3624 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RSP))
3625 {
3626 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_RSP, pMixedCtx->rsp);
3627 AssertRCReturn(rc, rc);
3628
3629 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RSP);
3630 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RSP=%#RX64\n", pVCpu->idCpu, pMixedCtx->rsp));
3631 }
3632 return rc;
3633}
3634
3635
3636/**
3637 * Loads the guest's 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 */
3647static int hmR0VmxLoadGuestRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3648{
3649 int rc = VINF_SUCCESS;
3650 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RFLAGS))
3651 {
3652 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
3653 Let us assert it as such and use 32-bit VMWRITE. */
3654 Assert(!(pMixedCtx->rflags.u64 >> 32));
3655 X86EFLAGS Eflags = pMixedCtx->eflags;
3656 /** @todo r=bird: There shall be no need to OR in X86_EFL_1 here, nor
3657 * shall there be any reason for clearing bits 63:22, 15, 5 and 3.
3658 * These will never be cleared/set, unless some other part of the VMM
3659 * code is buggy - in which case we're better of finding and fixing
3660 * those bugs than hiding them. */
3661 Assert(Eflags.u32 & X86_EFL_RA1_MASK);
3662 Assert(!(Eflags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
3663 Eflags.u32 &= VMX_EFLAGS_RESERVED_0; /* Bits 22-31, 15, 5 & 3 MBZ. */
3664 Eflags.u32 |= VMX_EFLAGS_RESERVED_1; /* Bit 1 MB1. */
3665
3666 /*
3667 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so we can restore them on VM-exit.
3668 * Modify the real-mode guest's eflags so that VT-x can run the real-mode guest code under Virtual 8086 mode.
3669 */
3670 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3671 {
3672 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
3673 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
3674 pVCpu->hm.s.vmx.RealMode.Eflags.u32 = Eflags.u32; /* Save the original eflags of the real-mode guest. */
3675 Eflags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
3676 Eflags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
3677 }
3678
3679 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_RFLAGS, Eflags.u32);
3680 AssertRCReturn(rc, rc);
3681
3682 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RFLAGS);
3683 Log4(("Load[%RU32]: VMX_VMCS_GUEST_RFLAGS=%#RX32\n", pVCpu->idCpu, Eflags.u32));
3684 }
3685 return rc;
3686}
3687
3688
3689/**
3690 * Loads the guest RIP, RSP and RFLAGS into the guest-state area in the VMCS.
3691 *
3692 * @returns VBox status code.
3693 * @param pVCpu The cross context virtual CPU structure.
3694 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3695 * out-of-sync. Make sure to update the required fields
3696 * before using them.
3697 *
3698 * @remarks No-long-jump zone!!!
3699 */
3700DECLINLINE(int) hmR0VmxLoadGuestRipRspRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3701{
3702 int rc = hmR0VmxLoadGuestRip(pVCpu, pMixedCtx);
3703 rc |= hmR0VmxLoadGuestRsp(pVCpu, pMixedCtx);
3704 rc |= hmR0VmxLoadGuestRflags(pVCpu, pMixedCtx);
3705 AssertRCReturn(rc, rc);
3706 return rc;
3707}
3708
3709
3710/**
3711 * Loads the guest CR0 control register into the guest-state area in the VMCS.
3712 * CR0 is partially shared with the host and we have to consider the FPU bits.
3713 *
3714 * @returns VBox status code.
3715 * @param pVCpu The cross context virtual CPU structure.
3716 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3717 * out-of-sync. Make sure to update the required fields
3718 * before using them.
3719 *
3720 * @remarks No-long-jump zone!!!
3721 */
3722static int hmR0VmxLoadSharedCR0(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3723{
3724 /*
3725 * Guest CR0.
3726 * Guest FPU.
3727 */
3728 int rc = VINF_SUCCESS;
3729 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
3730 {
3731 Assert(!(pMixedCtx->cr0 >> 32));
3732 uint32_t u32GuestCR0 = pMixedCtx->cr0;
3733 PVM pVM = pVCpu->CTX_SUFF(pVM);
3734
3735 /* The guest's view (read access) of its CR0 is unblemished. */
3736 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_READ_SHADOW, u32GuestCR0);
3737 AssertRCReturn(rc, rc);
3738 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR0_READ_SHADOW=%#RX32\n", pVCpu->idCpu, u32GuestCR0));
3739
3740 /* Setup VT-x's view of the guest CR0. */
3741 /* Minimize VM-exits due to CR3 changes when we have NestedPaging. */
3742 if (pVM->hm.s.fNestedPaging)
3743 {
3744 if (CPUMIsGuestPagingEnabledEx(pMixedCtx))
3745 {
3746 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
3747 pVCpu->hm.s.vmx.u32ProcCtls &= ~( VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
3748 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT);
3749 }
3750 else
3751 {
3752 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
3753 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT
3754 | VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
3755 }
3756
3757 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
3758 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3759 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT;
3760
3761 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
3762 AssertRCReturn(rc, rc);
3763 }
3764 else
3765 u32GuestCR0 |= X86_CR0_WP; /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
3766
3767 /*
3768 * Guest FPU bits.
3769 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be set on the first
3770 * CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
3771 */
3772 u32GuestCR0 |= X86_CR0_NE;
3773 bool fInterceptNM = false;
3774 if (CPUMIsGuestFPUStateActive(pVCpu))
3775 {
3776 fInterceptNM = false; /* Guest FPU active, no need to VM-exit on #NM. */
3777 /* The guest should still get #NM exceptions when it expects it to, so we should not clear TS & MP bits here.
3778 We're only concerned about -us- not intercepting #NMs when the guest-FPU is active. Not the guest itself! */
3779 }
3780 else
3781 {
3782 fInterceptNM = true; /* Guest FPU inactive, VM-exit on #NM for lazy FPU loading. */
3783 u32GuestCR0 |= X86_CR0_TS /* Guest can task switch quickly and do lazy FPU syncing. */
3784 | X86_CR0_MP; /* FWAIT/WAIT should not ignore CR0.TS and should generate #NM. */
3785 }
3786
3787 /* Catch floating point exceptions if we need to report them to the guest in a different way. */
3788 bool fInterceptMF = false;
3789 if (!(pMixedCtx->cr0 & X86_CR0_NE))
3790 fInterceptMF = true;
3791
3792 /* Finally, intercept all exceptions as we cannot directly inject them in real-mode, see hmR0VmxInjectEventVmcs(). */
3793 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
3794 {
3795 Assert(PDMVmmDevHeapIsEnabled(pVM));
3796 Assert(pVM->hm.s.vmx.pRealModeTSS);
3797 pVCpu->hm.s.vmx.u32XcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
3798 fInterceptNM = true;
3799 fInterceptMF = true;
3800 }
3801 else
3802 {
3803 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
3804 pVCpu->hm.s.vmx.u32XcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
3805 }
3806 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
3807
3808 if (fInterceptNM)
3809 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_NM);
3810 else
3811 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_NM);
3812
3813 if (fInterceptMF)
3814 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_MF);
3815 else
3816 pVCpu->hm.s.vmx.u32XcptBitmap &= ~RT_BIT(X86_XCPT_MF);
3817
3818 /* Additional intercepts for debugging, define these yourself explicitly. */
3819#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
3820 pVCpu->hm.s.vmx.u32XcptBitmap |= 0
3821 | RT_BIT(X86_XCPT_BP)
3822 | RT_BIT(X86_XCPT_DE)
3823 | RT_BIT(X86_XCPT_NM)
3824 | RT_BIT(X86_XCPT_TS)
3825 | RT_BIT(X86_XCPT_UD)
3826 | RT_BIT(X86_XCPT_NP)
3827 | RT_BIT(X86_XCPT_SS)
3828 | RT_BIT(X86_XCPT_GP)
3829 | RT_BIT(X86_XCPT_PF)
3830 | RT_BIT(X86_XCPT_MF)
3831 ;
3832#elif defined(HMVMX_ALWAYS_TRAP_PF)
3833 pVCpu->hm.s.vmx.u32XcptBitmap |= RT_BIT(X86_XCPT_PF);
3834#endif
3835
3836 Assert(pVM->hm.s.fNestedPaging || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_PF)));
3837
3838 /* Set/clear the CR0 specific bits along with their exceptions (PE, PG, CD, NW). */
3839 uint32_t uSetCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
3840 uint32_t uZapCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
3841 if (pVM->hm.s.vmx.fUnrestrictedGuest) /* Exceptions for unrestricted-guests for fixed CR0 bits (PE, PG). */
3842 uSetCR0 &= ~(X86_CR0_PE | X86_CR0_PG);
3843 else
3844 Assert((uSetCR0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
3845
3846 u32GuestCR0 |= uSetCR0;
3847 u32GuestCR0 &= uZapCR0;
3848 u32GuestCR0 &= ~(X86_CR0_CD | X86_CR0_NW); /* Always enable caching. */
3849
3850 /* Write VT-x's view of the guest CR0 into the VMCS. */
3851 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_CR0, u32GuestCR0);
3852 AssertRCReturn(rc, rc);
3853 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR0=%#RX32 (uSetCR0=%#RX32 uZapCR0=%#RX32)\n", pVCpu->idCpu, u32GuestCR0, uSetCR0,
3854 uZapCR0));
3855
3856 /*
3857 * CR0 is shared between host and guest along with a CR0 read shadow. Therefore, certain bits must not be changed
3858 * by the guest because VT-x ignores saving/restoring them (namely CD, ET, NW) and for certain other bits
3859 * we want to be notified immediately of guest CR0 changes (e.g. PG to update our shadow page tables).
3860 */
3861 uint32_t u32CR0Mask = 0;
3862 u32CR0Mask = X86_CR0_PE
3863 | X86_CR0_NE
3864 | X86_CR0_WP
3865 | X86_CR0_PG
3866 | X86_CR0_ET /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.ET */
3867 | X86_CR0_CD /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.CD */
3868 | X86_CR0_NW; /* Bit ignored on VM-entry and VM-exit. Don't let the guest modify the host CR0.NW */
3869
3870 /** @todo Avoid intercepting CR0.PE with unrestricted guests. Fix PGM
3871 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
3872 * and @bugref{6944}. */
3873#if 0
3874 if (pVM->hm.s.vmx.fUnrestrictedGuest)
3875 u32CR0Mask &= ~X86_CR0_PE;
3876#endif
3877 if (pVM->hm.s.fNestedPaging)
3878 u32CR0Mask &= ~X86_CR0_WP;
3879
3880 /* If the guest FPU state is active, don't need to VM-exit on writes to FPU related bits in CR0. */
3881 if (fInterceptNM)
3882 {
3883 u32CR0Mask |= X86_CR0_TS
3884 | X86_CR0_MP;
3885 }
3886
3887 /* Write the CR0 mask into the VMCS and update the VCPU's copy of the current CR0 mask. */
3888 pVCpu->hm.s.vmx.u32CR0Mask = u32CR0Mask;
3889 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_MASK, u32CR0Mask);
3890 AssertRCReturn(rc, rc);
3891 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR0_MASK=%#RX32\n", pVCpu->idCpu, u32CR0Mask));
3892
3893 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR0);
3894 }
3895 return rc;
3896}
3897
3898
3899/**
3900 * Loads the guest control registers (CR3, CR4) into the guest-state area
3901 * in the VMCS.
3902 *
3903 * @returns VBox strict status code.
3904 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
3905 * without unrestricted guest access and the VMMDev is not presently
3906 * mapped (e.g. EFI32).
3907 *
3908 * @param pVCpu The cross context virtual CPU structure.
3909 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
3910 * out-of-sync. Make sure to update the required fields
3911 * before using them.
3912 *
3913 * @remarks No-long-jump zone!!!
3914 */
3915static VBOXSTRICTRC hmR0VmxLoadGuestCR3AndCR4(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
3916{
3917 int rc = VINF_SUCCESS;
3918 PVM pVM = pVCpu->CTX_SUFF(pVM);
3919
3920 /*
3921 * Guest CR2.
3922 * It's always loaded in the assembler code. Nothing to do here.
3923 */
3924
3925 /*
3926 * Guest CR3.
3927 */
3928 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR3))
3929 {
3930 RTGCPHYS GCPhysGuestCR3 = NIL_RTGCPHYS;
3931 if (pVM->hm.s.fNestedPaging)
3932 {
3933 pVCpu->hm.s.vmx.HCPhysEPTP = PGMGetHyperCR3(pVCpu);
3934
3935 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
3936 Assert(pVCpu->hm.s.vmx.HCPhysEPTP);
3937 Assert(!(pVCpu->hm.s.vmx.HCPhysEPTP & UINT64_C(0xfff0000000000000)));
3938 Assert(!(pVCpu->hm.s.vmx.HCPhysEPTP & 0xfff));
3939
3940 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
3941 pVCpu->hm.s.vmx.HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
3942 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
3943
3944 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
3945 AssertMsg( ((pVCpu->hm.s.vmx.HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
3946 && ((pVCpu->hm.s.vmx.HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
3947 ("EPTP %#RX64\n", pVCpu->hm.s.vmx.HCPhysEPTP));
3948 AssertMsg( !((pVCpu->hm.s.vmx.HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
3949 || (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
3950 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVCpu->hm.s.vmx.HCPhysEPTP));
3951
3952 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVCpu->hm.s.vmx.HCPhysEPTP);
3953 AssertRCReturn(rc, rc);
3954 Log4(("Load[%RU32]: VMX_VMCS64_CTRL_EPTP_FULL=%#RX64\n", pVCpu->idCpu, pVCpu->hm.s.vmx.HCPhysEPTP));
3955
3956 if ( pVM->hm.s.vmx.fUnrestrictedGuest
3957 || CPUMIsGuestPagingEnabledEx(pMixedCtx))
3958 {
3959 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
3960 if (CPUMIsGuestInPAEModeEx(pMixedCtx))
3961 {
3962 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
3963 AssertRCReturn(rc, rc);
3964 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u);
3965 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u);
3966 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u);
3967 rc |= VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u);
3968 AssertRCReturn(rc, rc);
3969 }
3970
3971 /* The guest's view of its CR3 is unblemished with Nested Paging when the guest is using paging or we
3972 have Unrestricted Execution to handle the guest when it's not using paging. */
3973 GCPhysGuestCR3 = pMixedCtx->cr3;
3974 }
3975 else
3976 {
3977 /*
3978 * The guest is not using paging, but the CPU (VT-x) has to. While the guest thinks it accesses physical memory
3979 * directly, we use our identity-mapped page table to map guest-linear to guest-physical addresses.
3980 * EPT takes care of translating it to host-physical addresses.
3981 */
3982 RTGCPHYS GCPhys;
3983 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
3984
3985 /* We obtain it here every time as the guest could have relocated this PCI region. */
3986 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
3987 if (RT_SUCCESS(rc))
3988 { /* likely */ }
3989 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
3990 {
3991 Log4(("Load[%RU32]: VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n", pVCpu->idCpu));
3992 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
3993 }
3994 else
3995 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
3996
3997 GCPhysGuestCR3 = GCPhys;
3998 }
3999
4000 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR3=%#RGp (GstN)\n", pVCpu->idCpu, GCPhysGuestCR3));
4001 rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_CR3, GCPhysGuestCR3);
4002 }
4003 else
4004 {
4005 /* Non-nested paging case, just use the hypervisor's CR3. */
4006 RTHCPHYS HCPhysGuestCR3 = PGMGetHyperCR3(pVCpu);
4007
4008 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR3=%#RHv (HstN)\n", pVCpu->idCpu, HCPhysGuestCR3));
4009 rc = VMXWriteVmcsHstN(VMX_VMCS_GUEST_CR3, HCPhysGuestCR3);
4010 }
4011 AssertRCReturn(rc, rc);
4012
4013 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR3);
4014 }
4015
4016 /*
4017 * Guest CR4.
4018 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
4019 */
4020 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR4))
4021 {
4022 Assert(!(pMixedCtx->cr4 >> 32));
4023 uint32_t u32GuestCR4 = pMixedCtx->cr4;
4024
4025 /* The guest's view of its CR4 is unblemished. */
4026 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_READ_SHADOW, u32GuestCR4);
4027 AssertRCReturn(rc, rc);
4028 Log4(("Load[%RU32]: VMX_VMCS_CTRL_CR4_READ_SHADOW=%#RX32\n", pVCpu->idCpu, u32GuestCR4));
4029
4030 /* Setup VT-x's view of the guest CR4. */
4031 /*
4032 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software interrupts to the 8086 program
4033 * interrupt handler. Clear the VME bit (the interrupt redirection bitmap is already all 0, see hmR3InitFinalizeR0())
4034 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
4035 */
4036 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4037 {
4038 Assert(pVM->hm.s.vmx.pRealModeTSS);
4039 Assert(PDMVmmDevHeapIsEnabled(pVM));
4040 u32GuestCR4 &= ~X86_CR4_VME;
4041 }
4042
4043 if (pVM->hm.s.fNestedPaging)
4044 {
4045 if ( !CPUMIsGuestPagingEnabledEx(pMixedCtx)
4046 && !pVM->hm.s.vmx.fUnrestrictedGuest)
4047 {
4048 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
4049 u32GuestCR4 |= X86_CR4_PSE;
4050 /* Our identity mapping is a 32-bit page directory. */
4051 u32GuestCR4 &= ~X86_CR4_PAE;
4052 }
4053 /* else use guest CR4.*/
4054 }
4055 else
4056 {
4057 /*
4058 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
4059 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
4060 */
4061 switch (pVCpu->hm.s.enmShadowMode)
4062 {
4063 case PGMMODE_REAL: /* Real-mode. */
4064 case PGMMODE_PROTECTED: /* Protected mode without paging. */
4065 case PGMMODE_32_BIT: /* 32-bit paging. */
4066 {
4067 u32GuestCR4 &= ~X86_CR4_PAE;
4068 break;
4069 }
4070
4071 case PGMMODE_PAE: /* PAE paging. */
4072 case PGMMODE_PAE_NX: /* PAE paging with NX. */
4073 {
4074 u32GuestCR4 |= X86_CR4_PAE;
4075 break;
4076 }
4077
4078 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
4079 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
4080#ifdef VBOX_ENABLE_64_BITS_GUESTS
4081 break;
4082#endif
4083 default:
4084 AssertFailed();
4085 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
4086 }
4087 }
4088
4089 /* We need to set and clear the CR4 specific bits here (mainly the X86_CR4_VMXE bit). */
4090 uint64_t uSetCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
4091 uint64_t uZapCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
4092 u32GuestCR4 |= uSetCR4;
4093 u32GuestCR4 &= uZapCR4;
4094
4095 /* Write VT-x's view of the guest CR4 into the VMCS. */
4096 Log4(("Load[%RU32]: VMX_VMCS_GUEST_CR4=%#RX32 (Set=%#RX32 Zap=%#RX32)\n", pVCpu->idCpu, u32GuestCR4, uSetCR4, uZapCR4));
4097 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_CR4, u32GuestCR4);
4098 AssertRCReturn(rc, rc);
4099
4100 /* Setup CR4 mask. CR4 flags owned by the host, if the guest attempts to change them, that would cause a VM-exit. */
4101 uint32_t u32CR4Mask = X86_CR4_VME
4102 | X86_CR4_PAE
4103 | X86_CR4_PGE
4104 | X86_CR4_PSE
4105 | X86_CR4_VMXE;
4106 if (pVM->cpum.ro.HostFeatures.fXSaveRstor)
4107 u32CR4Mask |= X86_CR4_OSXSAVE;
4108 pVCpu->hm.s.vmx.u32CR4Mask = u32CR4Mask;
4109 rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_MASK, u32CR4Mask);
4110 AssertRCReturn(rc, rc);
4111
4112 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
4113 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pMixedCtx->cr4 & X86_CR4_OSXSAVE) && pMixedCtx->aXcr[0] != ASMGetXcr0();
4114
4115 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR4);
4116 }
4117 return rc;
4118}
4119
4120
4121/**
4122 * Loads the guest debug registers into the guest-state area in the VMCS.
4123 *
4124 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
4125 *
4126 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
4127 *
4128 * @returns VBox status code.
4129 * @param pVCpu The cross context virtual CPU structure.
4130 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4131 * out-of-sync. Make sure to update the required fields
4132 * before using them.
4133 *
4134 * @remarks No-long-jump zone!!!
4135 */
4136static int hmR0VmxLoadSharedDebugState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4137{
4138 if (!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_DEBUG))
4139 return VINF_SUCCESS;
4140
4141#ifdef VBOX_STRICT
4142 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
4143 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
4144 {
4145 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
4146 Assert((pMixedCtx->dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0); /* Bits 63:32, 15, 14, 12, 11 are reserved. */
4147 Assert((pMixedCtx->dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK); /* Bit 10 is reserved (RA1). */
4148 }
4149#endif
4150
4151 int rc;
4152 PVM pVM = pVCpu->CTX_SUFF(pVM);
4153 bool fSteppingDB = false;
4154 bool fInterceptMovDRx = false;
4155 if (pVCpu->hm.s.fSingleInstruction)
4156 {
4157 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
4158 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG)
4159 {
4160 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG;
4161 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
4162 AssertRCReturn(rc, rc);
4163 Assert(fSteppingDB == false);
4164 }
4165 else
4166 {
4167 pMixedCtx->eflags.u32 |= X86_EFL_TF;
4168 pVCpu->hm.s.fClearTrapFlag = true;
4169 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
4170 fSteppingDB = true;
4171 }
4172 }
4173
4174 if ( fSteppingDB
4175 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
4176 {
4177 /*
4178 * Use the combined guest and host DRx values found in the hypervisor
4179 * register set because the debugger has breakpoints active or someone
4180 * is single stepping on the host side without a monitor trap flag.
4181 *
4182 * Note! DBGF expects a clean DR6 state before executing guest code.
4183 */
4184#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4185 if ( CPUMIsGuestInLongModeEx(pMixedCtx)
4186 && !CPUMIsHyperDebugStateActivePending(pVCpu))
4187 {
4188 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
4189 Assert(CPUMIsHyperDebugStateActivePending(pVCpu));
4190 Assert(!CPUMIsGuestDebugStateActivePending(pVCpu));
4191 }
4192 else
4193#endif
4194 if (!CPUMIsHyperDebugStateActive(pVCpu))
4195 {
4196 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
4197 Assert(CPUMIsHyperDebugStateActive(pVCpu));
4198 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
4199 }
4200
4201 /* Update DR7. (The other DRx values are handled by CPUM one way or the other.) */
4202 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, (uint32_t)CPUMGetHyperDR7(pVCpu));
4203 AssertRCReturn(rc, rc);
4204
4205 pVCpu->hm.s.fUsingHyperDR7 = true;
4206 fInterceptMovDRx = true;
4207 }
4208 else
4209 {
4210 /*
4211 * If the guest has enabled debug registers, we need to load them prior to
4212 * executing guest code so they'll trigger at the right time.
4213 */
4214 if (pMixedCtx->dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD)) /** @todo Why GD? */
4215 {
4216#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4217 if ( CPUMIsGuestInLongModeEx(pMixedCtx)
4218 && !CPUMIsGuestDebugStateActivePending(pVCpu))
4219 {
4220 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
4221 Assert(CPUMIsGuestDebugStateActivePending(pVCpu));
4222 Assert(!CPUMIsHyperDebugStateActivePending(pVCpu));
4223 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
4224 }
4225 else
4226#endif
4227 if (!CPUMIsGuestDebugStateActive(pVCpu))
4228 {
4229 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
4230 Assert(CPUMIsGuestDebugStateActive(pVCpu));
4231 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
4232 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
4233 }
4234 Assert(!fInterceptMovDRx);
4235 }
4236 /*
4237 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
4238 * must intercept #DB in order to maintain a correct DR6 guest value, and
4239 * because we need to intercept it to prevent nested #DBs from hanging the
4240 * CPU, we end up always having to intercept it. See hmR0VmxInitXcptBitmap.
4241 */
4242#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
4243 else if ( !CPUMIsGuestDebugStateActivePending(pVCpu)
4244 && !CPUMIsGuestDebugStateActive(pVCpu))
4245#else
4246 else if (!CPUMIsGuestDebugStateActive(pVCpu))
4247#endif
4248 {
4249 fInterceptMovDRx = true;
4250 }
4251
4252 /* Update guest DR7. */
4253 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, pMixedCtx->dr[7]);
4254 AssertRCReturn(rc, rc);
4255
4256 pVCpu->hm.s.fUsingHyperDR7 = false;
4257 }
4258
4259 /*
4260 * Update the processor-based VM-execution controls regarding intercepting MOV DRx instructions.
4261 */
4262 if (fInterceptMovDRx)
4263 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
4264 else
4265 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
4266 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
4267 AssertRCReturn(rc, rc);
4268
4269 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_DEBUG);
4270 return VINF_SUCCESS;
4271}
4272
4273
4274#ifdef VBOX_STRICT
4275/**
4276 * Strict function to validate segment registers.
4277 *
4278 * @remarks ASSUMES CR0 is up to date.
4279 */
4280static void hmR0VmxValidateSegmentRegs(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
4281{
4282 /* Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers". */
4283 /* NOTE: The reason we check for attribute value 0 and not just the unusable bit here is because hmR0VmxWriteSegmentReg()
4284 * only updates the VMCS' copy of the value with the unusable bit and doesn't change the guest-context value. */
4285 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
4286 && ( !CPUMIsGuestInRealModeEx(pCtx)
4287 && !CPUMIsGuestInV86ModeEx(pCtx)))
4288 {
4289 /* Protected mode checks */
4290 /* CS */
4291 Assert(pCtx->cs.Attr.n.u1Present);
4292 Assert(!(pCtx->cs.Attr.u & 0xf00));
4293 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
4294 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
4295 || !(pCtx->cs.Attr.n.u1Granularity));
4296 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
4297 || (pCtx->cs.Attr.n.u1Granularity));
4298 /* CS cannot be loaded with NULL in protected mode. */
4299 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
4300 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
4301 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
4302 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
4303 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
4304 else
4305 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
4306 /* SS */
4307 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
4308 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
4309 if ( !(pCtx->cr0 & X86_CR0_PE)
4310 || pCtx->cs.Attr.n.u4Type == 3)
4311 {
4312 Assert(!pCtx->ss.Attr.n.u2Dpl);
4313 }
4314 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
4315 {
4316 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
4317 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
4318 Assert(pCtx->ss.Attr.n.u1Present);
4319 Assert(!(pCtx->ss.Attr.u & 0xf00));
4320 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
4321 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
4322 || !(pCtx->ss.Attr.n.u1Granularity));
4323 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
4324 || (pCtx->ss.Attr.n.u1Granularity));
4325 }
4326 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxWriteSegmentReg(). */
4327 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
4328 {
4329 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4330 Assert(pCtx->ds.Attr.n.u1Present);
4331 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
4332 Assert(!(pCtx->ds.Attr.u & 0xf00));
4333 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
4334 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
4335 || !(pCtx->ds.Attr.n.u1Granularity));
4336 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
4337 || (pCtx->ds.Attr.n.u1Granularity));
4338 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4339 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
4340 }
4341 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
4342 {
4343 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4344 Assert(pCtx->es.Attr.n.u1Present);
4345 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
4346 Assert(!(pCtx->es.Attr.u & 0xf00));
4347 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
4348 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
4349 || !(pCtx->es.Attr.n.u1Granularity));
4350 Assert( !(pCtx->es.u32Limit & 0xfff00000)
4351 || (pCtx->es.Attr.n.u1Granularity));
4352 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4353 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
4354 }
4355 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
4356 {
4357 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4358 Assert(pCtx->fs.Attr.n.u1Present);
4359 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
4360 Assert(!(pCtx->fs.Attr.u & 0xf00));
4361 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
4362 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
4363 || !(pCtx->fs.Attr.n.u1Granularity));
4364 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
4365 || (pCtx->fs.Attr.n.u1Granularity));
4366 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4367 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
4368 }
4369 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
4370 {
4371 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
4372 Assert(pCtx->gs.Attr.n.u1Present);
4373 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
4374 Assert(!(pCtx->gs.Attr.u & 0xf00));
4375 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
4376 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
4377 || !(pCtx->gs.Attr.n.u1Granularity));
4378 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
4379 || (pCtx->gs.Attr.n.u1Granularity));
4380 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
4381 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
4382 }
4383 /* 64-bit capable CPUs. */
4384# if HC_ARCH_BITS == 64
4385 Assert(!(pCtx->cs.u64Base >> 32));
4386 Assert(!pCtx->ss.Attr.u || !(pCtx->ss.u64Base >> 32));
4387 Assert(!pCtx->ds.Attr.u || !(pCtx->ds.u64Base >> 32));
4388 Assert(!pCtx->es.Attr.u || !(pCtx->es.u64Base >> 32));
4389# endif
4390 }
4391 else if ( CPUMIsGuestInV86ModeEx(pCtx)
4392 || ( CPUMIsGuestInRealModeEx(pCtx)
4393 && !pVM->hm.s.vmx.fUnrestrictedGuest))
4394 {
4395 /* Real and v86 mode checks. */
4396 /* hmR0VmxWriteSegmentReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
4397 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
4398 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4399 {
4400 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3; u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
4401 }
4402 else
4403 {
4404 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
4405 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
4406 }
4407
4408 /* CS */
4409 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
4410 Assert(pCtx->cs.u32Limit == 0xffff);
4411 Assert(u32CSAttr == 0xf3);
4412 /* SS */
4413 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
4414 Assert(pCtx->ss.u32Limit == 0xffff);
4415 Assert(u32SSAttr == 0xf3);
4416 /* DS */
4417 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
4418 Assert(pCtx->ds.u32Limit == 0xffff);
4419 Assert(u32DSAttr == 0xf3);
4420 /* ES */
4421 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
4422 Assert(pCtx->es.u32Limit == 0xffff);
4423 Assert(u32ESAttr == 0xf3);
4424 /* FS */
4425 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
4426 Assert(pCtx->fs.u32Limit == 0xffff);
4427 Assert(u32FSAttr == 0xf3);
4428 /* GS */
4429 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
4430 Assert(pCtx->gs.u32Limit == 0xffff);
4431 Assert(u32GSAttr == 0xf3);
4432 /* 64-bit capable CPUs. */
4433# if HC_ARCH_BITS == 64
4434 Assert(!(pCtx->cs.u64Base >> 32));
4435 Assert(!u32SSAttr || !(pCtx->ss.u64Base >> 32));
4436 Assert(!u32DSAttr || !(pCtx->ds.u64Base >> 32));
4437 Assert(!u32ESAttr || !(pCtx->es.u64Base >> 32));
4438# endif
4439 }
4440}
4441#endif /* VBOX_STRICT */
4442
4443
4444/**
4445 * Writes a guest segment register into the guest-state area in the VMCS.
4446 *
4447 * @returns VBox status code.
4448 * @param pVCpu The cross context virtual CPU structure.
4449 * @param idxSel Index of the selector in the VMCS.
4450 * @param idxLimit Index of the segment limit in the VMCS.
4451 * @param idxBase Index of the segment base in the VMCS.
4452 * @param idxAccess Index of the access rights of the segment in the VMCS.
4453 * @param pSelReg Pointer to the segment selector.
4454 *
4455 * @remarks No-long-jump zone!!!
4456 */
4457static int hmR0VmxWriteSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase,
4458 uint32_t idxAccess, PCPUMSELREG pSelReg)
4459{
4460 int rc = VMXWriteVmcs32(idxSel, pSelReg->Sel); /* 16-bit guest selector field. */
4461 rc |= VMXWriteVmcs32(idxLimit, pSelReg->u32Limit); /* 32-bit guest segment limit field. */
4462 rc |= VMXWriteVmcsGstN(idxBase, pSelReg->u64Base); /* Natural width guest segment base field.*/
4463 AssertRCReturn(rc, rc);
4464
4465 uint32_t u32Access = pSelReg->Attr.u;
4466 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4467 {
4468 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
4469 u32Access = 0xf3;
4470 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
4471 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
4472 }
4473 else
4474 {
4475 /*
4476 * The way to differentiate between whether this is really a null selector or was just a selector loaded with 0 in
4477 * real-mode is using the segment attributes. A selector loaded in real-mode with the value 0 is valid and usable in
4478 * protected-mode and we should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures NULL selectors
4479 * loaded in protected-mode have their attribute as 0.
4480 */
4481 if (!u32Access)
4482 u32Access = X86DESCATTR_UNUSABLE;
4483 }
4484
4485 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
4486 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
4487 ("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
4488
4489 rc = VMXWriteVmcs32(idxAccess, u32Access); /* 32-bit guest segment access-rights field. */
4490 AssertRCReturn(rc, rc);
4491 return rc;
4492}
4493
4494
4495/**
4496 * Loads the guest segment registers, GDTR, IDTR, LDTR, (TR, FS and GS bases)
4497 * into the guest-state area in the VMCS.
4498 *
4499 * @returns VBox status code.
4500 * @param pVCpu The cross context virtual CPU structure.
4501 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4502 * out-of-sync. Make sure to update the required fields
4503 * before using them.
4504 *
4505 * @remarks ASSUMES pMixedCtx->cr0 is up to date (strict builds validation).
4506 * @remarks No-long-jump zone!!!
4507 */
4508static int hmR0VmxLoadGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4509{
4510 int rc = VERR_INTERNAL_ERROR_5;
4511 PVM pVM = pVCpu->CTX_SUFF(pVM);
4512
4513 /*
4514 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
4515 */
4516 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS))
4517 {
4518 /* Save the segment attributes for real-on-v86 mode hack, so we can restore them on VM-exit. */
4519 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4520 {
4521 pVCpu->hm.s.vmx.RealMode.AttrCS.u = pMixedCtx->cs.Attr.u;
4522 pVCpu->hm.s.vmx.RealMode.AttrSS.u = pMixedCtx->ss.Attr.u;
4523 pVCpu->hm.s.vmx.RealMode.AttrDS.u = pMixedCtx->ds.Attr.u;
4524 pVCpu->hm.s.vmx.RealMode.AttrES.u = pMixedCtx->es.Attr.u;
4525 pVCpu->hm.s.vmx.RealMode.AttrFS.u = pMixedCtx->fs.Attr.u;
4526 pVCpu->hm.s.vmx.RealMode.AttrGS.u = pMixedCtx->gs.Attr.u;
4527 }
4528
4529#ifdef VBOX_WITH_REM
4530 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
4531 {
4532 Assert(pVM->hm.s.vmx.pRealModeTSS);
4533 AssertCompile(PGMMODE_REAL < PGMMODE_PROTECTED);
4534 if ( pVCpu->hm.s.vmx.fWasInRealMode
4535 && PGMGetGuestMode(pVCpu) >= PGMMODE_PROTECTED)
4536 {
4537 /* Signal that the recompiler must flush its code-cache as the guest -may- rewrite code it will later execute
4538 in real-mode (e.g. OpenBSD 4.0) */
4539 REMFlushTBs(pVM);
4540 Log4(("Load[%RU32]: Switch to protected mode detected!\n", pVCpu->idCpu));
4541 pVCpu->hm.s.vmx.fWasInRealMode = false;
4542 }
4543 }
4544#endif
4545 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_CS_SEL, VMX_VMCS32_GUEST_CS_LIMIT, VMX_VMCS_GUEST_CS_BASE,
4546 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS, &pMixedCtx->cs);
4547 AssertRCReturn(rc, rc);
4548 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_SS_SEL, VMX_VMCS32_GUEST_SS_LIMIT, VMX_VMCS_GUEST_SS_BASE,
4549 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS, &pMixedCtx->ss);
4550 AssertRCReturn(rc, rc);
4551 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_DS_SEL, VMX_VMCS32_GUEST_DS_LIMIT, VMX_VMCS_GUEST_DS_BASE,
4552 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS, &pMixedCtx->ds);
4553 AssertRCReturn(rc, rc);
4554 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_ES_SEL, VMX_VMCS32_GUEST_ES_LIMIT, VMX_VMCS_GUEST_ES_BASE,
4555 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS, &pMixedCtx->es);
4556 AssertRCReturn(rc, rc);
4557 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FS_SEL, VMX_VMCS32_GUEST_FS_LIMIT, VMX_VMCS_GUEST_FS_BASE,
4558 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS, &pMixedCtx->fs);
4559 AssertRCReturn(rc, rc);
4560 rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_GS_SEL, VMX_VMCS32_GUEST_GS_LIMIT, VMX_VMCS_GUEST_GS_BASE,
4561 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS, &pMixedCtx->gs);
4562 AssertRCReturn(rc, rc);
4563
4564#ifdef VBOX_STRICT
4565 /* Validate. */
4566 hmR0VmxValidateSegmentRegs(pVM, pVCpu, pMixedCtx);
4567#endif
4568
4569 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS);
4570 Log4(("Load[%RU32]: CS=%#RX16 Base=%#RX64 Limit=%#RX32 Attr=%#RX32\n", pVCpu->idCpu, pMixedCtx->cs.Sel,
4571 pMixedCtx->cs.u64Base, pMixedCtx->cs.u32Limit, pMixedCtx->cs.Attr.u));
4572 }
4573
4574 /*
4575 * Guest TR.
4576 */
4577 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_TR))
4578 {
4579 /*
4580 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is achieved
4581 * using the interrupt redirection bitmap (all bits cleared to let the guest handle INT-n's) in the TSS.
4582 * See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
4583 */
4584 uint16_t u16Sel = 0;
4585 uint32_t u32Limit = 0;
4586 uint64_t u64Base = 0;
4587 uint32_t u32AccessRights = 0;
4588
4589 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
4590 {
4591 u16Sel = pMixedCtx->tr.Sel;
4592 u32Limit = pMixedCtx->tr.u32Limit;
4593 u64Base = pMixedCtx->tr.u64Base;
4594 u32AccessRights = pMixedCtx->tr.Attr.u;
4595 }
4596 else
4597 {
4598 Assert(pVM->hm.s.vmx.pRealModeTSS);
4599 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMR3CanExecuteGuest() -XXX- what about inner loop changes? */
4600
4601 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
4602 RTGCPHYS GCPhys;
4603 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
4604 AssertRCReturn(rc, rc);
4605
4606 X86DESCATTR DescAttr;
4607 DescAttr.u = 0;
4608 DescAttr.n.u1Present = 1;
4609 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
4610
4611 u16Sel = 0;
4612 u32Limit = HM_VTX_TSS_SIZE;
4613 u64Base = GCPhys; /* in real-mode phys = virt. */
4614 u32AccessRights = DescAttr.u;
4615 }
4616
4617 /* Validate. */
4618 Assert(!(u16Sel & RT_BIT(2)));
4619 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
4620 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
4621 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
4622 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
4623 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
4624 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
4625 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
4626 Assert( (u32Limit & 0xfff) == 0xfff
4627 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
4628 Assert( !(pMixedCtx->tr.u32Limit & 0xfff00000)
4629 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
4630
4631 rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_TR_SEL, u16Sel);
4632 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit);
4633 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_TR_BASE, u64Base);
4634 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights);
4635 AssertRCReturn(rc, rc);
4636
4637 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_TR);
4638 Log4(("Load[%RU32]: VMX_VMCS_GUEST_TR_BASE=%#RX64\n", pVCpu->idCpu, u64Base));
4639 }
4640
4641 /*
4642 * Guest GDTR.
4643 */
4644 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_GDTR))
4645 {
4646 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pMixedCtx->gdtr.cbGdt);
4647 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_GDTR_BASE, pMixedCtx->gdtr.pGdt);
4648 AssertRCReturn(rc, rc);
4649
4650 /* Validate. */
4651 Assert(!(pMixedCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
4652
4653 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_GDTR);
4654 Log4(("Load[%RU32]: VMX_VMCS_GUEST_GDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->gdtr.pGdt));
4655 }
4656
4657 /*
4658 * Guest LDTR.
4659 */
4660 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LDTR))
4661 {
4662 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
4663 uint32_t u32Access = 0;
4664 if (!pMixedCtx->ldtr.Attr.u)
4665 u32Access = X86DESCATTR_UNUSABLE;
4666 else
4667 u32Access = pMixedCtx->ldtr.Attr.u;
4668
4669 rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_LDTR_SEL, pMixedCtx->ldtr.Sel);
4670 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pMixedCtx->ldtr.u32Limit);
4671 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_LDTR_BASE, pMixedCtx->ldtr.u64Base);
4672 rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access);
4673 AssertRCReturn(rc, rc);
4674
4675 /* Validate. */
4676 if (!(u32Access & X86DESCATTR_UNUSABLE))
4677 {
4678 Assert(!(pMixedCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
4679 Assert(pMixedCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
4680 Assert(!pMixedCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
4681 Assert(pMixedCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
4682 Assert(!pMixedCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
4683 Assert(!(pMixedCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
4684 Assert( (pMixedCtx->ldtr.u32Limit & 0xfff) == 0xfff
4685 || !pMixedCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
4686 Assert( !(pMixedCtx->ldtr.u32Limit & 0xfff00000)
4687 || pMixedCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
4688 }
4689
4690 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_LDTR);
4691 Log4(("Load[%RU32]: VMX_VMCS_GUEST_LDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->ldtr.u64Base));
4692 }
4693
4694 /*
4695 * Guest IDTR.
4696 */
4697 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_IDTR))
4698 {
4699 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pMixedCtx->idtr.cbIdt);
4700 rc |= VMXWriteVmcsGstN(VMX_VMCS_GUEST_IDTR_BASE, pMixedCtx->idtr.pIdt);
4701 AssertRCReturn(rc, rc);
4702
4703 /* Validate. */
4704 Assert(!(pMixedCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
4705
4706 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_IDTR);
4707 Log4(("Load[%RU32]: VMX_VMCS_GUEST_IDTR_BASE=%#RX64\n", pVCpu->idCpu, pMixedCtx->idtr.pIdt));
4708 }
4709
4710 return VINF_SUCCESS;
4711}
4712
4713
4714/**
4715 * Loads certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
4716 * areas.
4717 *
4718 * These MSRs will automatically be loaded to the host CPU on every successful
4719 * VM-entry and stored from the host CPU on every successful VM-exit. This also
4720 * creates/updates MSR slots for the host MSRs. The actual host MSR values are
4721 * -not- updated here for performance reasons. See hmR0VmxSaveHostMsrs().
4722 *
4723 * Also loads the sysenter MSRs into the guest-state area in the VMCS.
4724 *
4725 * @returns VBox status code.
4726 * @param pVCpu The cross context virtual CPU structure.
4727 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4728 * out-of-sync. Make sure to update the required fields
4729 * before using them.
4730 *
4731 * @remarks No-long-jump zone!!!
4732 */
4733static int hmR0VmxLoadGuestMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4734{
4735 AssertPtr(pVCpu);
4736 AssertPtr(pVCpu->hm.s.vmx.pvGuestMsr);
4737
4738 /*
4739 * MSRs that we use the auto-load/store MSR area in the VMCS.
4740 */
4741 PVM pVM = pVCpu->CTX_SUFF(pVM);
4742 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS))
4743 {
4744 /* For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(). */
4745#if HC_ARCH_BITS == 32
4746 if (pVM->hm.s.fAllow64BitGuests)
4747 {
4748 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_LSTAR, pMixedCtx->msrLSTAR, false, NULL);
4749 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K6_STAR, pMixedCtx->msrSTAR, false, NULL);
4750 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_SF_MASK, pMixedCtx->msrSFMASK, false, NULL);
4751 rc |= hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_KERNEL_GS_BASE, pMixedCtx->msrKERNELGSBASE, false, NULL);
4752 AssertRCReturn(rc, rc);
4753# ifdef LOG_ENABLED
4754 PVMXAUTOMSR pMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
4755 for (uint32_t i = 0; i < pVCpu->hm.s.vmx.cMsrs; i++, pMsr++)
4756 {
4757 Log4(("Load[%RU32]: MSR[%RU32]: u32Msr=%#RX32 u64Value=%#RX64\n", pVCpu->idCpu, i, pMsr->u32Msr,
4758 pMsr->u64Value));
4759 }
4760# endif
4761 }
4762#endif
4763 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
4764 }
4765
4766 /*
4767 * Guest Sysenter MSRs.
4768 * These flags are only set when MSR-bitmaps are not supported by the CPU and we cause
4769 * VM-exits on WRMSRs for these MSRs.
4770 */
4771 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR))
4772 {
4773 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pMixedCtx->SysEnter.cs); AssertRCReturn(rc, rc);
4774 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR);
4775 }
4776
4777 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR))
4778 {
4779 int rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, pMixedCtx->SysEnter.eip); AssertRCReturn(rc, rc);
4780 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
4781 }
4782
4783 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR))
4784 {
4785 int rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, pMixedCtx->SysEnter.esp); AssertRCReturn(rc, rc);
4786 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
4787 }
4788
4789 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_EFER_MSR))
4790 {
4791 if (hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
4792 {
4793 /*
4794 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
4795 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
4796 */
4797 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
4798 {
4799 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pMixedCtx->msrEFER);
4800 AssertRCReturn(rc,rc);
4801 Log4(("Load[%RU32]: VMX_VMCS64_GUEST_EFER_FULL=%#RX64\n", pVCpu->idCpu, pMixedCtx->msrEFER));
4802 }
4803 else
4804 {
4805 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K6_EFER, pMixedCtx->msrEFER, false /* fUpdateHostMsr */,
4806 NULL /* pfAddedAndUpdated */);
4807 AssertRCReturn(rc, rc);
4808
4809 /* We need to intercept reads too, see @bugref{7386#c16}. */
4810 if (pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
4811 hmR0VmxSetMsrPermission(pVCpu, MSR_K6_EFER, VMXMSREXIT_INTERCEPT_READ, VMXMSREXIT_INTERCEPT_WRITE);
4812 Log4(("Load[%RU32]: MSR[--]: u32Msr=%#RX32 u64Value=%#RX64 cMsrs=%u\n", pVCpu->idCpu, MSR_K6_EFER,
4813 pMixedCtx->msrEFER, pVCpu->hm.s.vmx.cMsrs));
4814 }
4815 }
4816 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
4817 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, MSR_K6_EFER);
4818 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_EFER_MSR);
4819 }
4820
4821 return VINF_SUCCESS;
4822}
4823
4824
4825/**
4826 * Loads the guest activity state into the guest-state area in the VMCS.
4827 *
4828 * @returns VBox status code.
4829 * @param pVCpu The cross context virtual CPU structure.
4830 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4831 * out-of-sync. Make sure to update the required fields
4832 * before using them.
4833 *
4834 * @remarks No-long-jump zone!!!
4835 */
4836static int hmR0VmxLoadGuestActivityState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4837{
4838 NOREF(pMixedCtx);
4839 /** @todo See if we can make use of other states, e.g.
4840 * VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN or HLT. */
4841 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_ACTIVITY_STATE))
4842 {
4843 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, VMX_VMCS_GUEST_ACTIVITY_ACTIVE);
4844 AssertRCReturn(rc, rc);
4845
4846 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_VMX_GUEST_ACTIVITY_STATE);
4847 }
4848 return VINF_SUCCESS;
4849}
4850
4851
4852#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
4853/**
4854 * Check if guest state allows safe use of 32-bit switcher again.
4855 *
4856 * Segment bases and protected mode structures must be 32-bit addressable
4857 * because the 32-bit switcher will ignore high dword when writing these VMCS
4858 * fields. See @bugref{8432} for details.
4859 *
4860 * @returns true if safe, false if must continue to use the 64-bit switcher.
4861 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4862 * out-of-sync. Make sure to update the required fields
4863 * before using them.
4864 *
4865 * @remarks No-long-jump zone!!!
4866 */
4867static bool hmR0VmxIs32BitSwitcherSafe(PCPUMCTX pMixedCtx)
4868{
4869 if (pMixedCtx->gdtr.pGdt & UINT64_C(0xffffffff00000000))
4870 return false;
4871 if (pMixedCtx->idtr.pIdt & UINT64_C(0xffffffff00000000))
4872 return false;
4873 if (pMixedCtx->ldtr.u64Base & UINT64_C(0xffffffff00000000))
4874 return false;
4875 if (pMixedCtx->tr.u64Base & UINT64_C(0xffffffff00000000))
4876 return false;
4877 if (pMixedCtx->es.u64Base & UINT64_C(0xffffffff00000000))
4878 return false;
4879 if (pMixedCtx->cs.u64Base & UINT64_C(0xffffffff00000000))
4880 return false;
4881 if (pMixedCtx->ss.u64Base & UINT64_C(0xffffffff00000000))
4882 return false;
4883 if (pMixedCtx->ds.u64Base & UINT64_C(0xffffffff00000000))
4884 return false;
4885 if (pMixedCtx->fs.u64Base & UINT64_C(0xffffffff00000000))
4886 return false;
4887 if (pMixedCtx->gs.u64Base & UINT64_C(0xffffffff00000000))
4888 return false;
4889 /* All good, bases are 32-bit. */
4890 return true;
4891}
4892#endif
4893
4894
4895/**
4896 * Sets up the appropriate function to run guest code.
4897 *
4898 * @returns VBox status code.
4899 * @param pVCpu The cross context virtual CPU structure.
4900 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
4901 * out-of-sync. Make sure to update the required fields
4902 * before using them.
4903 *
4904 * @remarks No-long-jump zone!!!
4905 */
4906static int hmR0VmxSetupVMRunHandler(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
4907{
4908 if (CPUMIsGuestInLongModeEx(pMixedCtx))
4909 {
4910#ifndef VBOX_ENABLE_64_BITS_GUESTS
4911 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
4912#endif
4913 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
4914#if HC_ARCH_BITS == 32
4915 /* 32-bit host. We need to switch to 64-bit before running the 64-bit guest. */
4916 if (pVCpu->hm.s.vmx.pfnStartVM != VMXR0SwitcherStartVM64)
4917 {
4918 if (pVCpu->hm.s.vmx.pfnStartVM != NULL) /* Very first entry would have saved host-state already, ignore it. */
4919 {
4920 /* Currently, all mode changes sends us back to ring-3, so these should be set. See @bugref{6944}. */
4921 AssertMsg(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_VMX_EXIT_CTLS
4922 | HM_CHANGED_VMX_ENTRY_CTLS
4923 | HM_CHANGED_GUEST_EFER_MSR), ("flags=%#x\n", HMCPU_CF_VALUE(pVCpu)));
4924 }
4925 pVCpu->hm.s.vmx.pfnStartVM = VMXR0SwitcherStartVM64;
4926
4927 /* Mark that we've switched to 64-bit handler, we can't safely switch back to 32-bit for
4928 the rest of the VM run (until VM reset). See @bugref{8432#c7}. */
4929 pVCpu->hm.s.vmx.fSwitchedTo64on32 = true;
4930 Log4(("Load[%RU32]: hmR0VmxSetupVMRunHandler: selected 64-bit switcher\n", pVCpu->idCpu));
4931 }
4932#else
4933 /* 64-bit host. */
4934 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM64;
4935#endif
4936 }
4937 else
4938 {
4939 /* Guest is not in long mode, use the 32-bit handler. */
4940#if HC_ARCH_BITS == 32
4941 if ( pVCpu->hm.s.vmx.pfnStartVM != VMXR0StartVM32
4942 && !pVCpu->hm.s.vmx.fSwitchedTo64on32 /* If set, guest mode change does not imply switcher change. */
4943 && pVCpu->hm.s.vmx.pfnStartVM != NULL) /* Very first entry would have saved host-state already, ignore it. */
4944 {
4945 /* Currently, all mode changes sends us back to ring-3, so these should be set. See @bugref{6944}. */
4946 AssertMsg(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_VMX_EXIT_CTLS
4947 | HM_CHANGED_VMX_ENTRY_CTLS
4948 | HM_CHANGED_GUEST_EFER_MSR), ("flags=%#x\n", HMCPU_CF_VALUE(pVCpu)));
4949 }
4950# ifdef VBOX_ENABLE_64_BITS_GUESTS
4951 /*
4952 * Keep using the 64-bit switcher even though we're in 32-bit because of bad Intel design, see @bugref{8432#c7}.
4953 * If real-on-v86 mode is active, clear the 64-bit switcher flag because now we know the guest is in a sane
4954 * state where it's safe to use the 32-bit switcher. Otherwise check the guest state if it's safe to use
4955 * the much faster 32-bit switcher again.
4956 */
4957 if (!pVCpu->hm.s.vmx.fSwitchedTo64on32)
4958 {
4959 if (pVCpu->hm.s.vmx.pfnStartVM != VMXR0StartVM32)
4960 Log4(("Load[%RU32]: hmR0VmxSetupVMRunHandler: selected 32-bit switcher\n", pVCpu->idCpu));
4961 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4962 }
4963 else
4964 {
4965 Assert(pVCpu->hm.s.vmx.pfnStartVM == VMXR0SwitcherStartVM64);
4966 if ( pVCpu->hm.s.vmx.RealMode.fRealOnV86Active
4967 || hmR0VmxIs32BitSwitcherSafe(pMixedCtx))
4968 {
4969 pVCpu->hm.s.vmx.fSwitchedTo64on32 = false;
4970 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4971 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_EFER_MSR
4972 | HM_CHANGED_VMX_ENTRY_CTLS
4973 | HM_CHANGED_VMX_EXIT_CTLS
4974 | HM_CHANGED_HOST_CONTEXT);
4975 Log4(("Load[%RU32]: hmR0VmxSetupVMRunHandler: selected 32-bit switcher (safe)\n", pVCpu->idCpu));
4976 }
4977 }
4978# else
4979 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4980# endif
4981#else
4982 pVCpu->hm.s.vmx.pfnStartVM = VMXR0StartVM32;
4983#endif
4984 }
4985 Assert(pVCpu->hm.s.vmx.pfnStartVM);
4986 return VINF_SUCCESS;
4987}
4988
4989
4990/**
4991 * Wrapper for running the guest code in VT-x.
4992 *
4993 * @returns VBox status code, no informational status codes.
4994 * @param pVM The cross context VM structure.
4995 * @param pVCpu The cross context virtual CPU structure.
4996 * @param pCtx Pointer to the guest-CPU context.
4997 *
4998 * @remarks No-long-jump zone!!!
4999 */
5000DECLINLINE(int) hmR0VmxRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
5001{
5002 /*
5003 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses floating-point operations
5004 * using SSE instructions. Some XMM registers (XMM6-XMM15) are callee-saved and thus the need for this XMM wrapper.
5005 * Refer MSDN docs. "Configuring Programs for 64-bit / x64 Software Conventions / Register Usage" for details.
5006 */
5007 bool const fResumeVM = RT_BOOL(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_LAUNCHED);
5008 /** @todo Add stats for resume vs launch. */
5009#ifdef VBOX_WITH_KERNEL_USING_XMM
5010 int rc = hmR0VMXStartVMWrapXMM(fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu, pVCpu->hm.s.vmx.pfnStartVM);
5011#else
5012 int rc = pVCpu->hm.s.vmx.pfnStartVM(fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu);
5013#endif
5014 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
5015 return rc;
5016}
5017
5018
5019/**
5020 * Reports world-switch error and dumps some useful debug info.
5021 *
5022 * @param pVM The cross context VM structure.
5023 * @param pVCpu The cross context virtual CPU structure.
5024 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
5025 * @param pCtx Pointer to the guest-CPU context.
5026 * @param pVmxTransient Pointer to the VMX transient structure (only
5027 * exitReason updated).
5028 */
5029static void hmR0VmxReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, int rcVMRun, PCPUMCTX pCtx, PVMXTRANSIENT pVmxTransient)
5030{
5031 Assert(pVM);
5032 Assert(pVCpu);
5033 Assert(pCtx);
5034 Assert(pVmxTransient);
5035 HMVMX_ASSERT_PREEMPT_SAFE();
5036
5037 Log4(("VM-entry failure: %Rrc\n", rcVMRun));
5038 switch (rcVMRun)
5039 {
5040 case VERR_VMX_INVALID_VMXON_PTR:
5041 AssertFailed();
5042 break;
5043 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
5044 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
5045 {
5046 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
5047 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
5048 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
5049 AssertRC(rc);
5050
5051 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
5052 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
5053 Cannot do it here as we may have been long preempted. */
5054
5055#ifdef VBOX_STRICT
5056 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
5057 pVmxTransient->uExitReason));
5058 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQualification));
5059 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
5060 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
5061 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
5062 else
5063 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
5064 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
5065 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
5066
5067 /* VMX control bits. */
5068 uint32_t u32Val;
5069 uint64_t u64Val;
5070 RTHCUINTREG uHCReg;
5071 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val); AssertRC(rc);
5072 Log4(("VMX_VMCS32_CTRL_PIN_EXEC %#RX32\n", u32Val));
5073 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val); AssertRC(rc);
5074 Log4(("VMX_VMCS32_CTRL_PROC_EXEC %#RX32\n", u32Val));
5075 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
5076 {
5077 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val); AssertRC(rc);
5078 Log4(("VMX_VMCS32_CTRL_PROC_EXEC2 %#RX32\n", u32Val));
5079 }
5080 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val); AssertRC(rc);
5081 Log4(("VMX_VMCS32_CTRL_ENTRY %#RX32\n", u32Val));
5082 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val); AssertRC(rc);
5083 Log4(("VMX_VMCS32_CTRL_EXIT %#RX32\n", u32Val));
5084 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_CR3_TARGET_COUNT, &u32Val); AssertRC(rc);
5085 Log4(("VMX_VMCS32_CTRL_CR3_TARGET_COUNT %#RX32\n", u32Val));
5086 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32Val); AssertRC(rc);
5087 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", u32Val));
5088 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &u32Val); AssertRC(rc);
5089 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", u32Val));
5090 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &u32Val); AssertRC(rc);
5091 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %u\n", u32Val));
5092 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, &u32Val); AssertRC(rc);
5093 Log4(("VMX_VMCS32_CTRL_TPR_THRESHOLD %u\n", u32Val));
5094 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &u32Val); AssertRC(rc);
5095 Log4(("VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT %u (guest MSRs)\n", u32Val));
5096 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &u32Val); AssertRC(rc);
5097 Log4(("VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT %u (host MSRs)\n", u32Val));
5098 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &u32Val); AssertRC(rc);
5099 Log4(("VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT %u (guest MSRs)\n", u32Val));
5100 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val); AssertRC(rc);
5101 Log4(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP %#RX32\n", u32Val));
5102 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, &u32Val); AssertRC(rc);
5103 Log4(("VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK %#RX32\n", u32Val));
5104 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, &u32Val); AssertRC(rc);
5105 Log4(("VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH %#RX32\n", u32Val));
5106 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
5107 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
5108 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
5109 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
5110 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
5111 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
5112 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
5113 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
5114 if (pVM->hm.s.fNestedPaging)
5115 {
5116 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
5117 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
5118 }
5119
5120 /* Guest bits. */
5121 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RIP, &u64Val); AssertRC(rc);
5122 Log4(("Old Guest Rip %#RX64 New %#RX64\n", pCtx->rip, u64Val));
5123 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RSP, &u64Val); AssertRC(rc);
5124 Log4(("Old Guest Rsp %#RX64 New %#RX64\n", pCtx->rsp, u64Val));
5125 rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &u32Val); AssertRC(rc);
5126 Log4(("Old Guest Rflags %#RX32 New %#RX32\n", pCtx->eflags.u32, u32Val));
5127 if (pVM->hm.s.vmx.fVpid)
5128 {
5129 rc = VMXReadVmcs32(VMX_VMCS16_VPID, &u32Val); AssertRC(rc);
5130 Log4(("VMX_VMCS16_VPID %u\n", u32Val));
5131 }
5132
5133 /* Host bits. */
5134 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR0, &uHCReg); AssertRC(rc);
5135 Log4(("Host CR0 %#RHr\n", uHCReg));
5136 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR3, &uHCReg); AssertRC(rc);
5137 Log4(("Host CR3 %#RHr\n", uHCReg));
5138 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_CR4, &uHCReg); AssertRC(rc);
5139 Log4(("Host CR4 %#RHr\n", uHCReg));
5140
5141 RTGDTR HostGdtr;
5142 PCX86DESCHC pDesc;
5143 ASMGetGDTR(&HostGdtr);
5144 rc = VMXReadVmcs32(VMX_VMCS16_HOST_CS_SEL, &u32Val); AssertRC(rc);
5145 Log4(("Host CS %#08x\n", u32Val));
5146 if (u32Val < HostGdtr.cbGdt)
5147 {
5148 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5149 hmR0DumpDescriptor(pDesc, u32Val, "CS: ");
5150 }
5151
5152 rc = VMXReadVmcs32(VMX_VMCS16_HOST_DS_SEL, &u32Val); AssertRC(rc);
5153 Log4(("Host DS %#08x\n", u32Val));
5154 if (u32Val < HostGdtr.cbGdt)
5155 {
5156 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5157 hmR0DumpDescriptor(pDesc, u32Val, "DS: ");
5158 }
5159
5160 rc = VMXReadVmcs32(VMX_VMCS16_HOST_ES_SEL, &u32Val); AssertRC(rc);
5161 Log4(("Host ES %#08x\n", u32Val));
5162 if (u32Val < HostGdtr.cbGdt)
5163 {
5164 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5165 hmR0DumpDescriptor(pDesc, u32Val, "ES: ");
5166 }
5167
5168 rc = VMXReadVmcs32(VMX_VMCS16_HOST_FS_SEL, &u32Val); AssertRC(rc);
5169 Log4(("Host FS %#08x\n", u32Val));
5170 if (u32Val < HostGdtr.cbGdt)
5171 {
5172 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5173 hmR0DumpDescriptor(pDesc, u32Val, "FS: ");
5174 }
5175
5176 rc = VMXReadVmcs32(VMX_VMCS16_HOST_GS_SEL, &u32Val); AssertRC(rc);
5177 Log4(("Host GS %#08x\n", u32Val));
5178 if (u32Val < HostGdtr.cbGdt)
5179 {
5180 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5181 hmR0DumpDescriptor(pDesc, u32Val, "GS: ");
5182 }
5183
5184 rc = VMXReadVmcs32(VMX_VMCS16_HOST_SS_SEL, &u32Val); AssertRC(rc);
5185 Log4(("Host SS %#08x\n", u32Val));
5186 if (u32Val < HostGdtr.cbGdt)
5187 {
5188 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5189 hmR0DumpDescriptor(pDesc, u32Val, "SS: ");
5190 }
5191
5192 rc = VMXReadVmcs32(VMX_VMCS16_HOST_TR_SEL, &u32Val); AssertRC(rc);
5193 Log4(("Host TR %#08x\n", u32Val));
5194 if (u32Val < HostGdtr.cbGdt)
5195 {
5196 pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u32Val & X86_SEL_MASK));
5197 hmR0DumpDescriptor(pDesc, u32Val, "TR: ");
5198 }
5199
5200 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_TR_BASE, &uHCReg); AssertRC(rc);
5201 Log4(("Host TR Base %#RHv\n", uHCReg));
5202 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_GDTR_BASE, &uHCReg); AssertRC(rc);
5203 Log4(("Host GDTR Base %#RHv\n", uHCReg));
5204 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_IDTR_BASE, &uHCReg); AssertRC(rc);
5205 Log4(("Host IDTR Base %#RHv\n", uHCReg));
5206 rc = VMXReadVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, &u32Val); AssertRC(rc);
5207 Log4(("Host SYSENTER CS %#08x\n", u32Val));
5208 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_SYSENTER_EIP, &uHCReg); AssertRC(rc);
5209 Log4(("Host SYSENTER EIP %#RHv\n", uHCReg));
5210 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_SYSENTER_ESP, &uHCReg); AssertRC(rc);
5211 Log4(("Host SYSENTER ESP %#RHv\n", uHCReg));
5212 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_RSP, &uHCReg); AssertRC(rc);
5213 Log4(("Host RSP %#RHv\n", uHCReg));
5214 rc = VMXReadVmcsHstN(VMX_VMCS_HOST_RIP, &uHCReg); AssertRC(rc);
5215 Log4(("Host RIP %#RHv\n", uHCReg));
5216# if HC_ARCH_BITS == 64
5217 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
5218 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
5219 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
5220 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
5221 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
5222 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
5223# endif
5224#endif /* VBOX_STRICT */
5225 break;
5226 }
5227
5228 default:
5229 /* Impossible */
5230 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
5231 break;
5232 }
5233 NOREF(pVM); NOREF(pCtx);
5234}
5235
5236
5237#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
5238#ifndef VMX_USE_CACHED_VMCS_ACCESSES
5239# error "VMX_USE_CACHED_VMCS_ACCESSES not defined when it should be!"
5240#endif
5241#ifdef VBOX_STRICT
5242static bool hmR0VmxIsValidWriteField(uint32_t idxField)
5243{
5244 switch (idxField)
5245 {
5246 case VMX_VMCS_GUEST_RIP:
5247 case VMX_VMCS_GUEST_RSP:
5248 case VMX_VMCS_GUEST_SYSENTER_EIP:
5249 case VMX_VMCS_GUEST_SYSENTER_ESP:
5250 case VMX_VMCS_GUEST_GDTR_BASE:
5251 case VMX_VMCS_GUEST_IDTR_BASE:
5252 case VMX_VMCS_GUEST_CS_BASE:
5253 case VMX_VMCS_GUEST_DS_BASE:
5254 case VMX_VMCS_GUEST_ES_BASE:
5255 case VMX_VMCS_GUEST_FS_BASE:
5256 case VMX_VMCS_GUEST_GS_BASE:
5257 case VMX_VMCS_GUEST_SS_BASE:
5258 case VMX_VMCS_GUEST_LDTR_BASE:
5259 case VMX_VMCS_GUEST_TR_BASE:
5260 case VMX_VMCS_GUEST_CR3:
5261 return true;
5262 }
5263 return false;
5264}
5265
5266static bool hmR0VmxIsValidReadField(uint32_t idxField)
5267{
5268 switch (idxField)
5269 {
5270 /* Read-only fields. */
5271 case VMX_VMCS_RO_EXIT_QUALIFICATION:
5272 return true;
5273 }
5274 /* Remaining readable fields should also be writable. */
5275 return hmR0VmxIsValidWriteField(idxField);
5276}
5277#endif /* VBOX_STRICT */
5278
5279
5280/**
5281 * Executes the specified handler in 64-bit mode.
5282 *
5283 * @returns VBox status code (no informational status codes).
5284 * @param pVM The cross context VM structure.
5285 * @param pVCpu The cross context virtual CPU structure.
5286 * @param pCtx Pointer to the guest CPU context.
5287 * @param enmOp The operation to perform.
5288 * @param cParams Number of parameters.
5289 * @param paParam Array of 32-bit parameters.
5290 */
5291VMMR0DECL(int) VMXR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, HM64ON32OP enmOp,
5292 uint32_t cParams, uint32_t *paParam)
5293{
5294 NOREF(pCtx);
5295
5296 AssertReturn(pVM->hm.s.pfnHost32ToGuest64R0, VERR_HM_NO_32_TO_64_SWITCHER);
5297 Assert(enmOp > HM64ON32OP_INVALID && enmOp < HM64ON32OP_END);
5298 Assert(pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Write.aField));
5299 Assert(pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Read.aField));
5300
5301#ifdef VBOX_STRICT
5302 for (uint32_t i = 0; i < pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries; i++)
5303 Assert(hmR0VmxIsValidWriteField(pVCpu->hm.s.vmx.VMCSCache.Write.aField[i]));
5304
5305 for (uint32_t i = 0; i <pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries; i++)
5306 Assert(hmR0VmxIsValidReadField(pVCpu->hm.s.vmx.VMCSCache.Read.aField[i]));
5307#endif
5308
5309 /* Disable interrupts. */
5310 RTCCUINTREG fOldEFlags = ASMIntDisableFlags();
5311
5312#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
5313 RTCPUID idHostCpu = RTMpCpuId();
5314 CPUMR0SetLApic(pVCpu, idHostCpu);
5315#endif
5316
5317 PHMGLOBALCPUINFO pCpu = hmR0GetCurrentCpu();
5318 RTHCPHYS HCPhysCpuPage = pCpu->HCPhysMemObj;
5319
5320 /* Clear VMCS. Marking it inactive, clearing implementation-specific data and writing VMCS data back to memory. */
5321 VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
5322 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
5323
5324 /* Leave VMX Root Mode. */
5325 VMXDisable();
5326
5327 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
5328
5329 CPUMSetHyperESP(pVCpu, VMMGetStackRC(pVCpu));
5330 CPUMSetHyperEIP(pVCpu, enmOp);
5331 for (int i = (int)cParams - 1; i >= 0; i--)
5332 CPUMPushHyper(pVCpu, paParam[i]);
5333
5334 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatWorldSwitch3264, z);
5335
5336 /* Call the switcher. */
5337 int rc = pVM->hm.s.pfnHost32ToGuest64R0(pVM, RT_OFFSETOF(VM, aCpus[pVCpu->idCpu].cpum) - RT_OFFSETOF(VM, cpum));
5338 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatWorldSwitch3264, z);
5339
5340 /** @todo replace with hmR0VmxEnterRootMode() and hmR0VmxLeaveRootMode(). */
5341 /* Make sure the VMX instructions don't cause #UD faults. */
5342 SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
5343
5344 /* Re-enter VMX Root Mode */
5345 int rc2 = VMXEnable(HCPhysCpuPage);
5346 if (RT_FAILURE(rc2))
5347 {
5348 SUPR0ChangeCR4(0, ~X86_CR4_VMXE);
5349 ASMSetFlags(fOldEFlags);
5350 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
5351 return rc2;
5352 }
5353
5354 rc2 = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
5355 AssertRC(rc2);
5356 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
5357 Assert(!(ASMGetFlags() & X86_EFL_IF));
5358 ASMSetFlags(fOldEFlags);
5359 return rc;
5360}
5361
5362
5363/**
5364 * Prepares for and executes VMLAUNCH (64-bit guests) for 32-bit hosts
5365 * supporting 64-bit guests.
5366 *
5367 * @returns VBox status code.
5368 * @param fResume Whether to VMLAUNCH or VMRESUME.
5369 * @param pCtx Pointer to the guest-CPU context.
5370 * @param pCache Pointer to the VMCS cache.
5371 * @param pVM The cross context VM structure.
5372 * @param pVCpu The cross context virtual CPU structure.
5373 */
5374DECLASM(int) VMXR0SwitcherStartVM64(RTHCUINT fResume, PCPUMCTX pCtx, PVMCSCACHE pCache, PVM pVM, PVMCPU pVCpu)
5375{
5376 NOREF(fResume);
5377
5378 PHMGLOBALCPUINFO pCpu = hmR0GetCurrentCpu();
5379 RTHCPHYS HCPhysCpuPage = pCpu->HCPhysMemObj;
5380
5381#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5382 pCache->uPos = 1;
5383 pCache->interPD = PGMGetInterPaeCR3(pVM);
5384 pCache->pSwitcher = (uint64_t)pVM->hm.s.pfnHost32ToGuest64R0;
5385#endif
5386
5387#if defined(DEBUG) && defined(VMX_USE_CACHED_VMCS_ACCESSES)
5388 pCache->TestIn.HCPhysCpuPage = 0;
5389 pCache->TestIn.HCPhysVmcs = 0;
5390 pCache->TestIn.pCache = 0;
5391 pCache->TestOut.HCPhysVmcs = 0;
5392 pCache->TestOut.pCache = 0;
5393 pCache->TestOut.pCtx = 0;
5394 pCache->TestOut.eflags = 0;
5395#else
5396 NOREF(pCache);
5397#endif
5398
5399 uint32_t aParam[10];
5400 aParam[0] = (uint32_t)(HCPhysCpuPage); /* Param 1: VMXON physical address - Lo. */
5401 aParam[1] = (uint32_t)(HCPhysCpuPage >> 32); /* Param 1: VMXON physical address - Hi. */
5402 aParam[2] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs); /* Param 2: VMCS physical address - Lo. */
5403 aParam[3] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs >> 32); /* Param 2: VMCS physical address - Hi. */
5404 aParam[4] = VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache);
5405 aParam[5] = 0;
5406 aParam[6] = VM_RC_ADDR(pVM, pVM);
5407 aParam[7] = 0;
5408 aParam[8] = VM_RC_ADDR(pVM, pVCpu);
5409 aParam[9] = 0;
5410
5411#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5412 pCtx->dr[4] = pVM->hm.s.vmx.pScratchPhys + 16 + 8;
5413 *(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) = 1;
5414#endif
5415 int rc = VMXR0Execute64BitsHandler(pVM, pVCpu, pCtx, HM64ON32OP_VMXRCStartVM64, RT_ELEMENTS(aParam), &aParam[0]);
5416
5417#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5418 Assert(*(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) == 5);
5419 Assert(pCtx->dr[4] == 10);
5420 *(uint32_t *)(pVM->hm.s.vmx.pScratch + 16 + 8) = 0xff;
5421#endif
5422
5423#if defined(DEBUG) && defined(VMX_USE_CACHED_VMCS_ACCESSES)
5424 AssertMsg(pCache->TestIn.HCPhysCpuPage == HCPhysCpuPage, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysCpuPage, HCPhysCpuPage));
5425 AssertMsg(pCache->TestIn.HCPhysVmcs == pVCpu->hm.s.vmx.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
5426 pVCpu->hm.s.vmx.HCPhysVmcs));
5427 AssertMsg(pCache->TestIn.HCPhysVmcs == pCache->TestOut.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
5428 pCache->TestOut.HCPhysVmcs));
5429 AssertMsg(pCache->TestIn.pCache == pCache->TestOut.pCache, ("%RGv vs %RGv\n", pCache->TestIn.pCache,
5430 pCache->TestOut.pCache));
5431 AssertMsg(pCache->TestIn.pCache == VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache),
5432 ("%RGv vs %RGv\n", pCache->TestIn.pCache, VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache)));
5433 AssertMsg(pCache->TestIn.pCtx == pCache->TestOut.pCtx, ("%RGv vs %RGv\n", pCache->TestIn.pCtx,
5434 pCache->TestOut.pCtx));
5435 Assert(!(pCache->TestOut.eflags & X86_EFL_IF));
5436#endif
5437 return rc;
5438}
5439
5440
5441/**
5442 * Initialize the VMCS-Read cache.
5443 *
5444 * The VMCS cache is used for 32-bit hosts running 64-bit guests (except 32-bit
5445 * Darwin which runs with 64-bit paging in 32-bit mode) for 64-bit fields that
5446 * cannot be accessed in 32-bit mode. Some 64-bit fields -can- be accessed
5447 * (those that have a 32-bit FULL & HIGH part).
5448 *
5449 * @returns VBox status code.
5450 * @param pVM The cross context VM structure.
5451 * @param pVCpu The cross context virtual CPU structure.
5452 */
5453static int hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu)
5454{
5455#define VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, idxField) \
5456{ \
5457 Assert(pCache->Read.aField[idxField##_CACHE_IDX] == 0); \
5458 pCache->Read.aField[idxField##_CACHE_IDX] = idxField; \
5459 pCache->Read.aFieldVal[idxField##_CACHE_IDX] = 0; \
5460 ++cReadFields; \
5461}
5462
5463 AssertPtr(pVM);
5464 AssertPtr(pVCpu);
5465 PVMCSCACHE pCache = &pVCpu->hm.s.vmx.VMCSCache;
5466 uint32_t cReadFields = 0;
5467
5468 /*
5469 * Don't remove the #if 0'd fields in this code. They're listed here for consistency
5470 * and serve to indicate exceptions to the rules.
5471 */
5472
5473 /* Guest-natural selector base fields. */
5474#if 0
5475 /* These are 32-bit in practice. See Intel spec. 2.5 "Control Registers". */
5476 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR0);
5477 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR4);
5478#endif
5479 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_ES_BASE);
5480 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CS_BASE);
5481 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SS_BASE);
5482 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_DS_BASE);
5483 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_FS_BASE);
5484 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_GS_BASE);
5485 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_LDTR_BASE);
5486 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_TR_BASE);
5487 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_GDTR_BASE);
5488 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_IDTR_BASE);
5489 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_RSP);
5490 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_RIP);
5491#if 0
5492 /* Unused natural width guest-state fields. */
5493 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS);
5494 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR3); /* Handled in Nested Paging case */
5495#endif
5496 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SYSENTER_ESP);
5497 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_SYSENTER_EIP);
5498
5499 /* 64-bit guest-state fields; unused as we use two 32-bit VMREADs for these 64-bit fields (using "FULL" and "HIGH" fields). */
5500#if 0
5501 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL);
5502 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_DEBUGCTL_FULL);
5503 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PAT_FULL);
5504 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_EFER_FULL);
5505 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL);
5506 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE0_FULL);
5507 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE1_FULL);
5508 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE2_FULL);
5509 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS64_GUEST_PDPTE3_FULL);
5510#endif
5511
5512 /* Natural width guest-state fields. */
5513 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_RO_EXIT_QUALIFICATION);
5514#if 0
5515 /* Currently unused field. */
5516 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_RO_EXIT_GUEST_LINEAR_ADDR);
5517#endif
5518
5519 if (pVM->hm.s.fNestedPaging)
5520 {
5521 VMXLOCAL_INIT_READ_CACHE_FIELD(pCache, VMX_VMCS_GUEST_CR3);
5522 AssertMsg(cReadFields == VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields,
5523 VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX));
5524 pCache->Read.cValidEntries = VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX;
5525 }
5526 else
5527 {
5528 AssertMsg(cReadFields == VMX_VMCS_MAX_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields, VMX_VMCS_MAX_CACHE_IDX));
5529 pCache->Read.cValidEntries = VMX_VMCS_MAX_CACHE_IDX;
5530 }
5531
5532#undef VMXLOCAL_INIT_READ_CACHE_FIELD
5533 return VINF_SUCCESS;
5534}
5535
5536
5537/**
5538 * Writes a field into the VMCS. This can either directly invoke a VMWRITE or
5539 * queue up the VMWRITE by using the VMCS write cache (on 32-bit hosts, except
5540 * darwin, running 64-bit guests).
5541 *
5542 * @returns VBox status code.
5543 * @param pVCpu The cross context virtual CPU structure.
5544 * @param idxField The VMCS field encoding.
5545 * @param u64Val 16, 32 or 64-bit value.
5546 */
5547VMMR0DECL(int) VMXWriteVmcs64Ex(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
5548{
5549 int rc;
5550 switch (idxField)
5551 {
5552 /*
5553 * These fields consists of a "FULL" and a "HIGH" part which can be written to individually.
5554 */
5555 /* 64-bit Control fields. */
5556 case VMX_VMCS64_CTRL_IO_BITMAP_A_FULL:
5557 case VMX_VMCS64_CTRL_IO_BITMAP_B_FULL:
5558 case VMX_VMCS64_CTRL_MSR_BITMAP_FULL:
5559 case VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL:
5560 case VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL:
5561 case VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL:
5562 case VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL:
5563 case VMX_VMCS64_CTRL_TSC_OFFSET_FULL:
5564 case VMX_VMCS64_CTRL_VAPIC_PAGEADDR_FULL:
5565 case VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL:
5566 case VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL:
5567 case VMX_VMCS64_CTRL_EPTP_FULL:
5568 case VMX_VMCS64_CTRL_EPTP_LIST_FULL:
5569 /* 64-bit Guest-state fields. */
5570 case VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL:
5571 case VMX_VMCS64_GUEST_DEBUGCTL_FULL:
5572 case VMX_VMCS64_GUEST_PAT_FULL:
5573 case VMX_VMCS64_GUEST_EFER_FULL:
5574 case VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL:
5575 case VMX_VMCS64_GUEST_PDPTE0_FULL:
5576 case VMX_VMCS64_GUEST_PDPTE1_FULL:
5577 case VMX_VMCS64_GUEST_PDPTE2_FULL:
5578 case VMX_VMCS64_GUEST_PDPTE3_FULL:
5579 /* 64-bit Host-state fields. */
5580 case VMX_VMCS64_HOST_PAT_FULL:
5581 case VMX_VMCS64_HOST_EFER_FULL:
5582 case VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL:
5583 {
5584 rc = VMXWriteVmcs32(idxField, u64Val);
5585 rc |= VMXWriteVmcs32(idxField + 1, (uint32_t)(u64Val >> 32));
5586 break;
5587 }
5588
5589 /*
5590 * These fields do not have high and low parts. Queue up the VMWRITE by using the VMCS write-cache (for 64-bit
5591 * values). When we switch the host to 64-bit mode for running 64-bit guests, these VMWRITEs get executed then.
5592 */
5593 /* Natural-width Guest-state fields. */
5594 case VMX_VMCS_GUEST_CR3:
5595 case VMX_VMCS_GUEST_ES_BASE:
5596 case VMX_VMCS_GUEST_CS_BASE:
5597 case VMX_VMCS_GUEST_SS_BASE:
5598 case VMX_VMCS_GUEST_DS_BASE:
5599 case VMX_VMCS_GUEST_FS_BASE:
5600 case VMX_VMCS_GUEST_GS_BASE:
5601 case VMX_VMCS_GUEST_LDTR_BASE:
5602 case VMX_VMCS_GUEST_TR_BASE:
5603 case VMX_VMCS_GUEST_GDTR_BASE:
5604 case VMX_VMCS_GUEST_IDTR_BASE:
5605 case VMX_VMCS_GUEST_RSP:
5606 case VMX_VMCS_GUEST_RIP:
5607 case VMX_VMCS_GUEST_SYSENTER_ESP:
5608 case VMX_VMCS_GUEST_SYSENTER_EIP:
5609 {
5610 if (!(u64Val >> 32))
5611 {
5612 /* If this field is 64-bit, VT-x will zero out the top bits. */
5613 rc = VMXWriteVmcs32(idxField, (uint32_t)u64Val);
5614 }
5615 else
5616 {
5617 /* Assert that only the 32->64 switcher case should ever come here. */
5618 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests);
5619 rc = VMXWriteCachedVmcsEx(pVCpu, idxField, u64Val);
5620 }
5621 break;
5622 }
5623
5624 default:
5625 {
5626 AssertMsgFailed(("VMXWriteVmcs64Ex: Invalid field %#RX32 (pVCpu=%p u64Val=%#RX64)\n", idxField, pVCpu, u64Val));
5627 rc = VERR_INVALID_PARAMETER;
5628 break;
5629 }
5630 }
5631 AssertRCReturn(rc, rc);
5632 return rc;
5633}
5634
5635
5636/**
5637 * Queue up a VMWRITE by using the VMCS write cache.
5638 * This is only used on 32-bit hosts (except darwin) for 64-bit guests.
5639 *
5640 * @param pVCpu The cross context virtual CPU structure.
5641 * @param idxField The VMCS field encoding.
5642 * @param u64Val 16, 32 or 64-bit value.
5643 */
5644VMMR0DECL(int) VMXWriteCachedVmcsEx(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
5645{
5646 AssertPtr(pVCpu);
5647 PVMCSCACHE pCache = &pVCpu->hm.s.vmx.VMCSCache;
5648
5649 AssertMsgReturn(pCache->Write.cValidEntries < VMCSCACHE_MAX_ENTRY - 1,
5650 ("entries=%u\n", pCache->Write.cValidEntries), VERR_ACCESS_DENIED);
5651
5652 /* Make sure there are no duplicates. */
5653 for (uint32_t i = 0; i < pCache->Write.cValidEntries; i++)
5654 {
5655 if (pCache->Write.aField[i] == idxField)
5656 {
5657 pCache->Write.aFieldVal[i] = u64Val;
5658 return VINF_SUCCESS;
5659 }
5660 }
5661
5662 pCache->Write.aField[pCache->Write.cValidEntries] = idxField;
5663 pCache->Write.aFieldVal[pCache->Write.cValidEntries] = u64Val;
5664 pCache->Write.cValidEntries++;
5665 return VINF_SUCCESS;
5666}
5667#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) */
5668
5669
5670/**
5671 * Sets up the usage of TSC-offsetting and updates the VMCS.
5672 *
5673 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
5674 * VMX preemption timer.
5675 *
5676 * @returns VBox status code.
5677 * @param pVM The cross context VM structure.
5678 * @param pVCpu The cross context virtual CPU structure.
5679 *
5680 * @remarks No-long-jump zone!!!
5681 */
5682static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVM pVM, PVMCPU pVCpu)
5683{
5684 int rc;
5685 bool fOffsettedTsc;
5686 bool fParavirtTsc;
5687 if (pVM->hm.s.vmx.fUsePreemptTimer)
5688 {
5689 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset,
5690 &fOffsettedTsc, &fParavirtTsc);
5691
5692 /* Make sure the returned values have sane upper and lower boundaries. */
5693 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
5694 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
5695 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
5696 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
5697
5698 uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
5699 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_PREEMPT_TIMER_VALUE, cPreemptionTickCount); AssertRC(rc);
5700 }
5701 else
5702 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset, &fParavirtTsc);
5703
5704 /** @todo later optimize this to be done elsewhere and not before every
5705 * VM-entry. */
5706 if (fParavirtTsc)
5707 {
5708 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
5709 information before every VM-entry, hence disable it for performance sake. */
5710#if 0
5711 rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
5712 AssertRC(rc);
5713#endif
5714 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
5715 }
5716
5717 if (fOffsettedTsc && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
5718 {
5719 /* Note: VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT takes precedence over TSC_OFFSET, applies to RDTSCP too. */
5720 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, pVCpu->hm.s.vmx.u64TSCOffset); AssertRC(rc);
5721
5722 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
5723 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
5724 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
5725 }
5726 else
5727 {
5728 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
5729 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
5730 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls); AssertRC(rc);
5731 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
5732 }
5733}
5734
5735
5736#if 0
5737/**
5738 * Determines if an exception is a contributory exception.
5739 *
5740 * Contributory exceptions are ones which can cause double-faults unless the
5741 * original exception was a benign exception. Page-fault is intentionally not
5742 * included here as it's a conditional contributory exception.
5743 *
5744 * @returns true if the exception is contributory, false otherwise.
5745 * @param uVector The exception vector.
5746 */
5747DECLINLINE(bool) hmR0VmxIsContributoryXcpt(const uint32_t uVector)
5748{
5749 switch (uVector)
5750 {
5751 case X86_XCPT_GP:
5752 case X86_XCPT_SS:
5753 case X86_XCPT_NP:
5754 case X86_XCPT_TS:
5755 case X86_XCPT_DE:
5756 return true;
5757 default:
5758 break;
5759 }
5760 return false;
5761}
5762#endif
5763
5764/**
5765 * Sets an event as a pending event to be injected into the guest.
5766 *
5767 * @param pVCpu The cross context virtual CPU structure.
5768 * @param u32IntInfo The VM-entry interruption-information field.
5769 * @param cbInstr The VM-entry instruction length in bytes (for software
5770 * interrupts, exceptions and privileged software
5771 * exceptions).
5772 * @param u32ErrCode The VM-entry exception error code.
5773 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
5774 * page-fault.
5775 *
5776 * @remarks Statistics counter assumes this is a guest event being injected or
5777 * re-injected into the guest, i.e. 'StatInjectPendingReflect' is
5778 * always incremented.
5779 */
5780DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
5781 RTGCUINTPTR GCPtrFaultAddress)
5782{
5783 Assert(!pVCpu->hm.s.Event.fPending);
5784 pVCpu->hm.s.Event.fPending = true;
5785 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
5786 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
5787 pVCpu->hm.s.Event.cbInstr = cbInstr;
5788 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
5789}
5790
5791
5792/**
5793 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
5794 *
5795 * @param pVCpu The cross context virtual CPU structure.
5796 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5797 * out-of-sync. Make sure to update the required fields
5798 * before using them.
5799 */
5800DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
5801{
5802 NOREF(pMixedCtx);
5803 uint32_t u32IntInfo = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
5804 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
5805 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
5806 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
5807}
5808
5809
5810/**
5811 * Gets the IEM exception flags for the specified vector and IDT vectoring /
5812 * VM-exit interruption info type.
5813 *
5814 * @returns The IEM exception flags.
5815 * @param uVector The event vector.
5816 * @param uVmxVectorType The VMX event type.
5817 */
5818static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxVectorType)
5819{
5820 uint32_t fIemXcptFlags;
5821 switch (uVmxVectorType)
5822 {
5823 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
5824 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
5825 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
5826 break;
5827
5828 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
5829 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
5830 break;
5831
5832 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
5833 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
5834 break;
5835
5836 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
5837 {
5838 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
5839 if (uVector == X86_XCPT_BP)
5840 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
5841 else if (uVector == X86_XCPT_OF)
5842 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
5843 else
5844 {
5845 fIemXcptFlags = 0;
5846 AssertMsgFailed(("Unexpected vector for software int. uVector=%#x", uVector));
5847 }
5848 break;
5849 }
5850
5851 default:
5852 fIemXcptFlags = 0;
5853 AssertMsgFailed(("Unexpected vector type! uVmxVectorType=%#x uVector=%#x", uVmxVectorType, uVector));
5854 break;
5855 }
5856 return fIemXcptFlags;
5857}
5858
5859
5860/**
5861 * Handle a condition that occurred while delivering an event through the guest
5862 * IDT.
5863 *
5864 * @returns Strict VBox status code (i.e. informational status codes too).
5865 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
5866 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
5867 * to continue execution of the guest which will delivery the \#DF.
5868 * @retval VINF_EM_RESET if we detected a triple-fault condition.
5869 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
5870 *
5871 * @param pVCpu The cross context virtual CPU structure.
5872 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
5873 * out-of-sync. Make sure to update the required fields
5874 * before using them.
5875 * @param pVmxTransient Pointer to the VMX transient structure.
5876 *
5877 * @remarks No-long-jump zone!!!
5878 */
5879static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
5880{
5881 uint32_t const uExitVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
5882
5883 int rc2 = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient); AssertRCReturn(rc2, rc2);
5884 rc2 = hmR0VmxReadExitIntInfoVmcs(pVmxTransient); AssertRCReturn(rc2, rc2);
5885
5886 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
5887 if (VMX_IDT_VECTORING_INFO_VALID(pVmxTransient->uIdtVectoringInfo))
5888 {
5889 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
5890 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
5891#if 1
5892 /* See Intel spec. 30.7.1.1 "Reflecting Exceptions to Guest Software". */
5893 IEMXCPTRAISE enmRaise;
5894 IEMXCPTRAISEINFO fRaiseInfo;
5895 if (VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo))
5896 {
5897 uint32_t const uExitVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uExitIntInfo);
5898 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
5899 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
5900 AssertMsg( uExitVectorType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
5901 || uExitVectorType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI,
5902 ("hmR0VmxCheckExitDueToEventDelivery: Unexpected VM-exit interruption info. type %#x!\n", uExitVectorType));
5903 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector,
5904 &fRaiseInfo);
5905 }
5906 else
5907 {
5908 /*
5909 * If event delivery caused an EPT violation/misconfig or APIC access VM-exit, then the VM-exit
5910 * interruption-information will not be valid as it's not an exception and we end up here.
5911 *
5912 * If the event was an external interrupt or hardare exception (incl. NMI) it is sufficient to
5913 * reflect this event to the guest after handling the VM-exit.
5914 *
5915 * If the event was a software interrupt (generated with INT n) or a software exception (generated
5916 * by INT3/INTO) or a privileged software exception (generated by INT1), we can handle the VM-exit
5917 * and continue guest execution which will re-execute the instruction rather than re-injecting the
5918 * event, as that can cause premature trips to ring-3 before injection and involve TRPM which
5919 * currently has no way of storing that the exceptions were caused by these special instructions.
5920 */
5921 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
5922 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
5923 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT)
5924 enmRaise = IEMXCPTRAISE_PREV_EVENT;
5925 else
5926 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
5927 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
5928 }
5929
5930 /*
5931 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
5932 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
5933 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
5934 * subsequent VM-entry would fail.
5935 *
5936 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception". See @bugref{7445}.
5937 */
5938 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS)
5939 && uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
5940 && ( enmRaise == IEMXCPTRAISE_PREV_EVENT
5941 || fRaiseInfo == IEMXCPTRAISEINFO_NMI_PF)
5942 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
5943 {
5944 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
5945 }
5946
5947 switch (enmRaise)
5948 {
5949 case IEMXCPTRAISE_CURRENT_XCPT:
5950 {
5951 /*
5952 * Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF().
5953 */
5954 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
5955 pVmxTransient->fVectoringPF = true;
5956
5957 /*
5958 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
5959 * second #PF as a guest #PF (and not a nested #PF) and needs to be converted into a #DF.
5960 */
5961 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
5962 pVmxTransient->fVectoringDoublePF = true;
5963
5964 Assert(rcStrict == VINF_SUCCESS);
5965 break;
5966 }
5967
5968 case IEMXCPTRAISE_PREV_EVENT:
5969 {
5970 /*
5971 * Re-raise the previous (first) exception/interrupt as delivery caused a premature VM-exit.
5972 */
5973 Assert( uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT
5974 && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
5975 && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT);
5976
5977 uint32_t u32ErrCode;
5978 if (VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo))
5979 {
5980 rc2 = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
5981 AssertRCReturn(rc2, rc2);
5982 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
5983 }
5984 else
5985 u32ErrCode = 0;
5986
5987 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
5988 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
5989 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
5990 0 /* cbInstr */, u32ErrCode, pMixedCtx->cr2);
5991
5992 Log4(("IDT: vcpu[%RU32] Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
5993 pVCpu->hm.s.Event.u32ErrCode));
5994 Assert(rcStrict == VINF_SUCCESS);
5995 break;
5996 }
5997
5998 case IEMXCPTRAISE_DOUBLE_FAULT:
5999 {
6000 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
6001 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
6002
6003 Log4(("IDT: vcpu[%RU32] Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->idCpu,
6004 pVCpu->hm.s.Event.u64IntInfo, uIdtVector, uExitVector));
6005 rcStrict = VINF_HM_DOUBLE_FAULT;
6006 break;
6007 }
6008
6009 case IEMXCPTRAISE_TRIPLE_FAULT:
6010 {
6011 Log4(("IDT: vcpu[%RU32] Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", pVCpu->idCpu, uIdtVector,
6012 uExitVector));
6013 rcStrict = VINF_EM_RESET;
6014 break;
6015 }
6016
6017 case IEMXCPTRAISE_CPU_HANG:
6018 {
6019 Log4(("IDT: vcpu[%RU32] Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", pVCpu->idCpu, fRaiseInfo));
6020 rcStrict = VERR_EM_GUEST_CPU_HANG;
6021 break;
6022 }
6023
6024 case IEMXCPTRAISE_REEXEC_INSTR:
6025 Assert(rcStrict == VINF_SUCCESS);
6026 break;
6027
6028 default:
6029 {
6030 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
6031 rcStrict = VERR_VMX_IPE_2;
6032 break;
6033 }
6034 }
6035#else
6036 typedef enum
6037 {
6038 VMXREFLECTXCPT_XCPT, /* Reflect the exception to the guest or for further evaluation by VMM. */
6039 VMXREFLECTXCPT_DF, /* Reflect the exception as a double-fault to the guest. */
6040 VMXREFLECTXCPT_TF, /* Indicate a triple faulted state to the VMM. */
6041 VMXREFLECTXCPT_HANG, /* Indicate bad VM trying to deadlock the CPU. */
6042 VMXREFLECTXCPT_NONE /* Nothing to reflect. */
6043 } VMXREFLECTXCPT;
6044
6045 /* See Intel spec. 30.7.1.1 "Reflecting Exceptions to Guest Software". */
6046 VMXREFLECTXCPT enmReflect = VMXREFLECTXCPT_NONE;
6047 if (VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo))
6048 {
6049 if (uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT)
6050 {
6051 enmReflect = VMXREFLECTXCPT_XCPT;
6052#ifdef VBOX_STRICT
6053 if ( hmR0VmxIsContributoryXcpt(uIdtVector)
6054 && uExitVector == X86_XCPT_PF)
6055 {
6056 Log4(("IDT: vcpu[%RU32] Contributory #PF uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
6057 }
6058#endif
6059 if ( uExitVector == X86_XCPT_PF
6060 && uIdtVector == X86_XCPT_PF)
6061 {
6062 pVmxTransient->fVectoringDoublePF = true;
6063 Log4(("IDT: vcpu[%RU32] Vectoring Double #PF uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
6064 }
6065 else if ( uExitVector == X86_XCPT_AC
6066 && uIdtVector == X86_XCPT_AC)
6067 {
6068 enmReflect = VMXREFLECTXCPT_HANG;
6069 Log4(("IDT: Nested #AC - Bad guest\n"));
6070 }
6071 else if ( (pVCpu->hm.s.vmx.u32XcptBitmap & HMVMX_CONTRIBUTORY_XCPT_MASK)
6072 && hmR0VmxIsContributoryXcpt(uExitVector)
6073 && ( hmR0VmxIsContributoryXcpt(uIdtVector)
6074 || uIdtVector == X86_XCPT_PF))
6075 {
6076 enmReflect = VMXREFLECTXCPT_DF;
6077 }
6078 else if (uIdtVector == X86_XCPT_DF)
6079 enmReflect = VMXREFLECTXCPT_TF;
6080 }
6081 else if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT
6082 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI)
6083 {
6084 /*
6085 * Ignore software interrupts (INT n), software exceptions (#BP, #OF) and
6086 * privileged software exception (#DB from ICEBP) as they reoccur when restarting the instruction.
6087 */
6088 enmReflect = VMXREFLECTXCPT_XCPT;
6089
6090 if (uExitVector == X86_XCPT_PF)
6091 {
6092 pVmxTransient->fVectoringPF = true;
6093 Log4(("IDT: vcpu[%RU32] Vectoring #PF due to Ext-Int/NMI. uCR2=%#RX64\n", pVCpu->idCpu, pMixedCtx->cr2));
6094 }
6095 }
6096 }
6097 else if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
6098 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT
6099 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI)
6100 {
6101 /*
6102 * If event delivery caused an EPT violation/misconfig or APIC access VM-exit, then the VM-exit
6103 * interruption-information will not be valid as it's not an exception and we end up here. In such cases,
6104 * it is sufficient to reflect the original exception to the guest after handling the VM-exit.
6105 */
6106 enmReflect = VMXREFLECTXCPT_XCPT;
6107 }
6108
6109 /*
6110 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig etc.) occurred
6111 * while delivering the NMI, we need to clear the block-by-NMI field in the guest interruptibility-state before
6112 * re-delivering the NMI after handling the VM-exit. Otherwise the subsequent VM-entry would fail.
6113 *
6114 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception". See @bugref{7445}.
6115 */
6116 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
6117 && enmReflect == VMXREFLECTXCPT_XCPT
6118 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
6119 && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6120 {
6121 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
6122 }
6123
6124 switch (enmReflect)
6125 {
6126 case VMXREFLECTXCPT_XCPT:
6127 {
6128 Assert( uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT
6129 && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
6130 && uIdtVectorType != VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT);
6131
6132 uint32_t u32ErrCode = 0;
6133 if (VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo))
6134 {
6135 rc2 = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
6136 AssertRCReturn(rc2, rc2);
6137 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
6138 }
6139
6140 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF. See hmR0VmxExitXcptPF(). */
6141 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
6142 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
6143 0 /* cbInstr */, u32ErrCode, pMixedCtx->cr2);
6144 rcStrict = VINF_SUCCESS;
6145 Log4(("IDT: vcpu[%RU32] Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->idCpu,
6146 pVCpu->hm.s.Event.u64IntInfo, pVCpu->hm.s.Event.u32ErrCode));
6147
6148 break;
6149 }
6150
6151 case VMXREFLECTXCPT_DF:
6152 {
6153 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
6154 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
6155 rcStrict = VINF_HM_DOUBLE_FAULT;
6156 Log4(("IDT: vcpu[%RU32] Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->idCpu,
6157 pVCpu->hm.s.Event.u64IntInfo, uIdtVector, uExitVector));
6158
6159 break;
6160 }
6161
6162 case VMXREFLECTXCPT_TF:
6163 {
6164 rcStrict = VINF_EM_RESET;
6165 Log4(("IDT: vcpu[%RU32] Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", pVCpu->idCpu, uIdtVector,
6166 uExitVector));
6167 break;
6168 }
6169
6170 case VMXREFLECTXCPT_HANG:
6171 {
6172 rcStrict = VERR_EM_GUEST_CPU_HANG;
6173 break;
6174 }
6175
6176 default:
6177 Assert(rcStrict == VINF_SUCCESS);
6178 break;
6179 }
6180#endif
6181 }
6182 else if ( VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo)
6183 && VMX_EXIT_INTERRUPTION_INFO_NMI_UNBLOCK_IRET(pVmxTransient->uExitIntInfo)
6184 && uExitVector != X86_XCPT_DF
6185 && (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI))
6186 {
6187 /*
6188 * Execution of IRET caused this fault when NMI blocking was in effect (i.e we're in the guest NMI handler).
6189 * We need to set the block-by-NMI field so that NMIs remain blocked until the IRET execution is restarted.
6190 * See Intel spec. 30.7.1.2 "Resuming guest software after handling an exception".
6191 */
6192 if (!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6193 {
6194 Log4(("hmR0VmxCheckExitDueToEventDelivery: vcpu[%RU32] Setting VMCPU_FF_BLOCK_NMIS. Valid=%RTbool uExitReason=%u\n",
6195 pVCpu->idCpu, VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo), pVmxTransient->uExitReason));
6196 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
6197 }
6198 }
6199
6200 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
6201 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
6202 return rcStrict;
6203}
6204
6205
6206/**
6207 * Saves the guest's CR0 register from the VMCS into the guest-CPU context.
6208 *
6209 * @returns VBox status code.
6210 * @param pVCpu The cross context virtual CPU structure.
6211 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6212 * out-of-sync. Make sure to update the required fields
6213 * before using them.
6214 *
6215 * @remarks No-long-jump zone!!!
6216 */
6217static int hmR0VmxSaveGuestCR0(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6218{
6219 NOREF(pMixedCtx);
6220
6221 /*
6222 * While in the middle of saving guest-CR0, we could get preempted and re-invoked from the preemption hook,
6223 * see hmR0VmxLeave(). Safer to just make this code non-preemptible.
6224 */
6225 VMMRZCallRing3Disable(pVCpu);
6226 HM_DISABLE_PREEMPT();
6227
6228 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0))
6229 {
6230#ifndef DEBUG_bird /** @todo this triggers running bs3-cpu-generated-1.img with --debug-command-line
6231 * and 'dbgc-init' containing:
6232 * sxe "xcpt_de"
6233 * sxe "xcpt_bp"
6234 * sxi "xcpt_gp"
6235 * sxi "xcpt_ss"
6236 * sxi "xcpt_np"
6237 */
6238 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0));
6239#endif
6240 uint32_t uVal = 0;
6241 uint32_t uShadow = 0;
6242 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &uVal);
6243 rc |= VMXReadVmcs32(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uShadow);
6244 AssertRCReturn(rc, rc);
6245
6246 uVal = (uShadow & pVCpu->hm.s.vmx.u32CR0Mask) | (uVal & ~pVCpu->hm.s.vmx.u32CR0Mask);
6247 CPUMSetGuestCR0(pVCpu, uVal);
6248 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0);
6249 }
6250
6251 HM_RESTORE_PREEMPT();
6252 VMMRZCallRing3Enable(pVCpu);
6253 return VINF_SUCCESS;
6254}
6255
6256
6257/**
6258 * Saves the guest's CR4 register from the VMCS into the guest-CPU context.
6259 *
6260 * @returns VBox status code.
6261 * @param pVCpu The cross context virtual CPU structure.
6262 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6263 * out-of-sync. Make sure to update the required fields
6264 * before using them.
6265 *
6266 * @remarks No-long-jump zone!!!
6267 */
6268static int hmR0VmxSaveGuestCR4(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6269{
6270 NOREF(pMixedCtx);
6271
6272 int rc = VINF_SUCCESS;
6273 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4))
6274 {
6275 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR4));
6276 uint32_t uVal = 0;
6277 uint32_t uShadow = 0;
6278 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &uVal);
6279 rc |= VMXReadVmcs32(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uShadow);
6280 AssertRCReturn(rc, rc);
6281
6282 uVal = (uShadow & pVCpu->hm.s.vmx.u32CR4Mask) | (uVal & ~pVCpu->hm.s.vmx.u32CR4Mask);
6283 CPUMSetGuestCR4(pVCpu, uVal);
6284 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4);
6285 }
6286 return rc;
6287}
6288
6289
6290/**
6291 * Saves the guest's RIP register from the VMCS into the guest-CPU context.
6292 *
6293 * @returns VBox status code.
6294 * @param pVCpu The cross context virtual CPU structure.
6295 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6296 * out-of-sync. Make sure to update the required fields
6297 * before using them.
6298 *
6299 * @remarks No-long-jump zone!!!
6300 */
6301static int hmR0VmxSaveGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6302{
6303 int rc = VINF_SUCCESS;
6304 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP))
6305 {
6306 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RIP));
6307 uint64_t u64Val = 0;
6308 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RIP, &u64Val);
6309 AssertRCReturn(rc, rc);
6310
6311 pMixedCtx->rip = u64Val;
6312 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP);
6313 }
6314 return rc;
6315}
6316
6317
6318/**
6319 * Saves the guest's RSP register from the VMCS into the guest-CPU context.
6320 *
6321 * @returns VBox status code.
6322 * @param pVCpu The cross context virtual CPU structure.
6323 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6324 * out-of-sync. Make sure to update the required fields
6325 * before using them.
6326 *
6327 * @remarks No-long-jump zone!!!
6328 */
6329static int hmR0VmxSaveGuestRsp(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6330{
6331 int rc = VINF_SUCCESS;
6332 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RSP))
6333 {
6334 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RSP));
6335 uint64_t u64Val = 0;
6336 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_RSP, &u64Val);
6337 AssertRCReturn(rc, rc);
6338
6339 pMixedCtx->rsp = u64Val;
6340 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RSP);
6341 }
6342 return rc;
6343}
6344
6345
6346/**
6347 * Saves the guest's RFLAGS from the VMCS into the guest-CPU context.
6348 *
6349 * @returns VBox status code.
6350 * @param pVCpu The cross context virtual CPU structure.
6351 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6352 * out-of-sync. Make sure to update the required fields
6353 * before using them.
6354 *
6355 * @remarks No-long-jump zone!!!
6356 */
6357static int hmR0VmxSaveGuestRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6358{
6359 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS))
6360 {
6361 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RFLAGS));
6362 uint32_t uVal = 0;
6363 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &uVal);
6364 AssertRCReturn(rc, rc);
6365
6366 pMixedCtx->eflags.u32 = uVal;
6367 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active) /* Undo our real-on-v86-mode changes to eflags if necessary. */
6368 {
6369 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6370 Log4(("Saving real-mode EFLAGS VT-x view=%#RX32\n", pMixedCtx->eflags.u32));
6371
6372 pMixedCtx->eflags.Bits.u1VM = 0;
6373 pMixedCtx->eflags.Bits.u2IOPL = pVCpu->hm.s.vmx.RealMode.Eflags.Bits.u2IOPL;
6374 }
6375
6376 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS);
6377 }
6378 return VINF_SUCCESS;
6379}
6380
6381
6382/**
6383 * Wrapper for saving the guest's RIP, RSP and RFLAGS from the VMCS into the
6384 * guest-CPU context.
6385 */
6386DECLINLINE(int) hmR0VmxSaveGuestRipRspRflags(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6387{
6388 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6389 rc |= hmR0VmxSaveGuestRsp(pVCpu, pMixedCtx);
6390 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
6391 return rc;
6392}
6393
6394
6395/**
6396 * Saves the guest's interruptibility-state ("interrupt shadow" as AMD calls it)
6397 * from the guest-state area in the VMCS.
6398 *
6399 * @param pVCpu The cross context virtual CPU structure.
6400 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6401 * out-of-sync. Make sure to update the required fields
6402 * before using them.
6403 *
6404 * @remarks No-long-jump zone!!!
6405 */
6406static void hmR0VmxSaveGuestIntrState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6407{
6408 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_INTR_STATE))
6409 {
6410 uint32_t uIntrState = 0;
6411 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
6412 AssertRC(rc);
6413
6414 if (!uIntrState)
6415 {
6416 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
6417 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
6418
6419 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6420 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
6421 }
6422 else
6423 {
6424 if (uIntrState & ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS
6425 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI))
6426 {
6427 rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
6428 AssertRC(rc);
6429 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx); /* for hmR0VmxGetGuestIntrState(). */
6430 AssertRC(rc);
6431
6432 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
6433 Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
6434 }
6435 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
6436 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
6437
6438 if (uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI)
6439 {
6440 if (!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6441 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
6442 }
6443 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
6444 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
6445 }
6446
6447 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_INTR_STATE);
6448 }
6449}
6450
6451
6452/**
6453 * Saves the guest's activity state.
6454 *
6455 * @returns VBox status code.
6456 * @param pVCpu The cross context virtual CPU structure.
6457 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6458 * out-of-sync. Make sure to update the required fields
6459 * before using them.
6460 *
6461 * @remarks No-long-jump zone!!!
6462 */
6463static int hmR0VmxSaveGuestActivityState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6464{
6465 NOREF(pMixedCtx);
6466 /* Nothing to do for now until we make use of different guest-CPU activity state. Just update the flag. */
6467 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_ACTIVITY_STATE);
6468 return VINF_SUCCESS;
6469}
6470
6471
6472/**
6473 * Saves the guest SYSENTER MSRs (SYSENTER_CS, SYSENTER_EIP, SYSENTER_ESP) from
6474 * the current VMCS into the guest-CPU context.
6475 *
6476 * @returns VBox status code.
6477 * @param pVCpu The cross context virtual CPU structure.
6478 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6479 * out-of-sync. Make sure to update the required fields
6480 * before using them.
6481 *
6482 * @remarks No-long-jump zone!!!
6483 */
6484static int hmR0VmxSaveGuestSysenterMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6485{
6486 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR))
6487 {
6488 Assert(!HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR));
6489 uint32_t u32Val = 0;
6490 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRCReturn(rc, rc);
6491 pMixedCtx->SysEnter.cs = u32Val;
6492 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR);
6493 }
6494
6495 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR))
6496 {
6497 Assert(!HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR));
6498 uint64_t u64Val = 0;
6499 int rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, &u64Val); AssertRCReturn(rc, rc);
6500 pMixedCtx->SysEnter.eip = u64Val;
6501 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR);
6502 }
6503 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR))
6504 {
6505 Assert(!HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR));
6506 uint64_t u64Val = 0;
6507 int rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, &u64Val); AssertRCReturn(rc, rc);
6508 pMixedCtx->SysEnter.esp = u64Val;
6509 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR);
6510 }
6511 return VINF_SUCCESS;
6512}
6513
6514
6515/**
6516 * Saves the set of guest MSRs (that we restore lazily while leaving VT-x) from
6517 * the CPU back into the guest-CPU context.
6518 *
6519 * @returns VBox status code.
6520 * @param pVCpu The cross context virtual CPU structure.
6521 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6522 * out-of-sync. Make sure to update the required fields
6523 * before using them.
6524 *
6525 * @remarks No-long-jump zone!!!
6526 */
6527static int hmR0VmxSaveGuestLazyMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6528{
6529 /* Since this can be called from our preemption hook it's safer to make the guest-MSRs update non-preemptible. */
6530 VMMRZCallRing3Disable(pVCpu);
6531 HM_DISABLE_PREEMPT();
6532
6533 /* Doing the check here ensures we don't overwrite already-saved guest MSRs from a preemption hook. */
6534 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS))
6535 {
6536 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS));
6537 hmR0VmxLazySaveGuestMsrs(pVCpu, pMixedCtx);
6538 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS);
6539 }
6540
6541 HM_RESTORE_PREEMPT();
6542 VMMRZCallRing3Enable(pVCpu);
6543
6544 return VINF_SUCCESS;
6545}
6546
6547
6548/**
6549 * Saves the auto load/store'd guest MSRs from the current VMCS into
6550 * the guest-CPU context.
6551 *
6552 * @returns VBox status code.
6553 * @param pVCpu The cross context virtual CPU structure.
6554 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6555 * out-of-sync. Make sure to update the required fields
6556 * before using them.
6557 *
6558 * @remarks No-long-jump zone!!!
6559 */
6560static int hmR0VmxSaveGuestAutoLoadStoreMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6561{
6562 if (HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS))
6563 return VINF_SUCCESS;
6564
6565 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS));
6566 PVMXAUTOMSR pMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
6567 uint32_t cMsrs = pVCpu->hm.s.vmx.cMsrs;
6568 Log4(("hmR0VmxSaveGuestAutoLoadStoreMsrs: cMsrs=%u\n", cMsrs));
6569 for (uint32_t i = 0; i < cMsrs; i++, pMsr++)
6570 {
6571 switch (pMsr->u32Msr)
6572 {
6573 case MSR_K8_TSC_AUX: CPUMR0SetGuestTscAux(pVCpu, pMsr->u64Value); break;
6574 case MSR_K8_LSTAR: pMixedCtx->msrLSTAR = pMsr->u64Value; break;
6575 case MSR_K6_STAR: pMixedCtx->msrSTAR = pMsr->u64Value; break;
6576 case MSR_K8_SF_MASK: pMixedCtx->msrSFMASK = pMsr->u64Value; break;
6577 case MSR_K8_KERNEL_GS_BASE: pMixedCtx->msrKERNELGSBASE = pMsr->u64Value; break;
6578 case MSR_K6_EFER: /* Nothing to do here since we intercept writes, see hmR0VmxLoadGuestMsrs(). */
6579 break;
6580
6581 default:
6582 {
6583 AssertMsgFailed(("Unexpected MSR in auto-load/store area. uMsr=%#RX32 cMsrs=%u\n", pMsr->u32Msr, cMsrs));
6584 pVCpu->hm.s.u32HMError = pMsr->u32Msr;
6585 return VERR_HM_UNEXPECTED_LD_ST_MSR;
6586 }
6587 }
6588 }
6589
6590 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS);
6591 return VINF_SUCCESS;
6592}
6593
6594
6595/**
6596 * Saves the guest control registers from the current VMCS into the guest-CPU
6597 * context.
6598 *
6599 * @returns VBox status code.
6600 * @param pVCpu The cross context virtual CPU structure.
6601 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6602 * out-of-sync. Make sure to update the required fields
6603 * before using them.
6604 *
6605 * @remarks No-long-jump zone!!!
6606 */
6607static int hmR0VmxSaveGuestControlRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6608{
6609 /* Guest CR0. Guest FPU. */
6610 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6611 AssertRCReturn(rc, rc);
6612
6613 /* Guest CR4. */
6614 rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
6615 AssertRCReturn(rc, rc);
6616
6617 /* Guest CR2 - updated always during the world-switch or in #PF. */
6618 /* Guest CR3. Only changes with Nested Paging. This must be done -after- saving CR0 and CR4 from the guest! */
6619 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR3))
6620 {
6621 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR3));
6622 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
6623 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR4));
6624
6625 PVM pVM = pVCpu->CTX_SUFF(pVM);
6626 if ( pVM->hm.s.vmx.fUnrestrictedGuest
6627 || ( pVM->hm.s.fNestedPaging
6628 && CPUMIsGuestPagingEnabledEx(pMixedCtx)))
6629 {
6630 uint64_t u64Val = 0;
6631 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_CR3, &u64Val);
6632 if (pMixedCtx->cr3 != u64Val)
6633 {
6634 CPUMSetGuestCR3(pVCpu, u64Val);
6635 if (VMMRZCallRing3IsEnabled(pVCpu))
6636 {
6637 PGMUpdateCR3(pVCpu, u64Val);
6638 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6639 }
6640 else
6641 {
6642 /* Set the force flag to inform PGM about it when necessary. It is cleared by PGMUpdateCR3().*/
6643 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
6644 }
6645 }
6646
6647 /* If the guest is in PAE mode, sync back the PDPE's into the guest state. */
6648 if (CPUMIsGuestInPAEModeEx(pMixedCtx)) /* Reads CR0, CR4 and EFER MSR (EFER is always up-to-date). */
6649 {
6650 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u);
6651 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u);
6652 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u);
6653 rc |= VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u);
6654 AssertRCReturn(rc, rc);
6655
6656 if (VMMRZCallRing3IsEnabled(pVCpu))
6657 {
6658 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6659 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6660 }
6661 else
6662 {
6663 /* Set the force flag to inform PGM about it when necessary. It is cleared by PGMGstUpdatePaePdpes(). */
6664 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
6665 }
6666 }
6667 }
6668
6669 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR3);
6670 }
6671
6672 /*
6673 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
6674 * -> VMMRZCallRing3Disable() -> hmR0VmxSaveGuestState() -> Set VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
6675 * -> continue with VM-exit handling -> hmR0VmxSaveGuestControlRegs() and here we are.
6676 *
6677 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
6678 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
6679 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
6680 * -NOT- check if HMVMX_UPDATED_GUEST_CR3 is already set or not!
6681 *
6682 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
6683 */
6684 if (VMMRZCallRing3IsEnabled(pVCpu))
6685 {
6686 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
6687 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
6688
6689 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
6690 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
6691
6692 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
6693 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
6694 }
6695
6696 return rc;
6697}
6698
6699
6700/**
6701 * Reads a guest segment register from the current VMCS into the guest-CPU
6702 * context.
6703 *
6704 * @returns VBox status code.
6705 * @param pVCpu The cross context virtual CPU structure.
6706 * @param idxSel Index of the selector in the VMCS.
6707 * @param idxLimit Index of the segment limit in the VMCS.
6708 * @param idxBase Index of the segment base in the VMCS.
6709 * @param idxAccess Index of the access rights of the segment in the VMCS.
6710 * @param pSelReg Pointer to the segment selector.
6711 *
6712 * @remarks No-long-jump zone!!!
6713 * @remarks Never call this function directly!!! Use the VMXLOCAL_READ_SEG()
6714 * macro as that takes care of whether to read from the VMCS cache or
6715 * not.
6716 */
6717DECLINLINE(int) hmR0VmxReadSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase, uint32_t idxAccess,
6718 PCPUMSELREG pSelReg)
6719{
6720 NOREF(pVCpu);
6721
6722 uint32_t u32Val = 0;
6723 int rc = VMXReadVmcs32(idxSel, &u32Val);
6724 AssertRCReturn(rc, rc);
6725 pSelReg->Sel = (uint16_t)u32Val;
6726 pSelReg->ValidSel = (uint16_t)u32Val;
6727 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
6728
6729 rc = VMXReadVmcs32(idxLimit, &u32Val);
6730 AssertRCReturn(rc, rc);
6731 pSelReg->u32Limit = u32Val;
6732
6733 uint64_t u64Val = 0;
6734 rc = VMXReadVmcsGstNByIdxVal(idxBase, &u64Val);
6735 AssertRCReturn(rc, rc);
6736 pSelReg->u64Base = u64Val;
6737
6738 rc = VMXReadVmcs32(idxAccess, &u32Val);
6739 AssertRCReturn(rc, rc);
6740 pSelReg->Attr.u = u32Val;
6741
6742 /*
6743 * If VT-x marks the segment as unusable, most other bits remain undefined:
6744 * - For CS the L, D and G bits have meaning.
6745 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
6746 * - For the remaining data segments no bits are defined.
6747 *
6748 * The present bit and the unusable bit has been observed to be set at the
6749 * same time (the selector was supposed to be invalid as we started executing
6750 * a V8086 interrupt in ring-0).
6751 *
6752 * What should be important for the rest of the VBox code, is that the P bit is
6753 * cleared. Some of the other VBox code recognizes the unusable bit, but
6754 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
6755 * safe side here, we'll strip off P and other bits we don't care about. If
6756 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
6757 *
6758 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
6759 */
6760 if (pSelReg->Attr.u & X86DESCATTR_UNUSABLE)
6761 {
6762 Assert(idxSel != VMX_VMCS16_GUEST_TR_SEL); /* TR is the only selector that can never be unusable. */
6763
6764 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
6765 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
6766 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
6767
6768 Log4(("hmR0VmxReadSegmentReg: Unusable idxSel=%#x attr=%#x -> %#x\n", idxSel, u32Val, pSelReg->Attr.u));
6769#ifdef DEBUG_bird
6770 AssertMsg((u32Val & ~X86DESCATTR_P) == pSelReg->Attr.u,
6771 ("%#x: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
6772 idxSel, u32Val, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
6773#endif
6774 }
6775 return VINF_SUCCESS;
6776}
6777
6778
6779#ifdef VMX_USE_CACHED_VMCS_ACCESSES
6780# define VMXLOCAL_READ_SEG(Sel, CtxSel) \
6781 hmR0VmxReadSegmentReg(pVCpu, VMX_VMCS16_GUEST_##Sel##_SEL, VMX_VMCS32_GUEST_##Sel##_LIMIT, \
6782 VMX_VMCS_GUEST_##Sel##_BASE_CACHE_IDX, VMX_VMCS32_GUEST_##Sel##_ACCESS_RIGHTS, &pMixedCtx->CtxSel)
6783#else
6784# define VMXLOCAL_READ_SEG(Sel, CtxSel) \
6785 hmR0VmxReadSegmentReg(pVCpu, VMX_VMCS16_GUEST_##Sel##_SEL, VMX_VMCS32_GUEST_##Sel##_LIMIT, \
6786 VMX_VMCS_GUEST_##Sel##_BASE, VMX_VMCS32_GUEST_##Sel##_ACCESS_RIGHTS, &pMixedCtx->CtxSel)
6787#endif
6788
6789
6790/**
6791 * Saves the guest segment registers from the current VMCS into the guest-CPU
6792 * context.
6793 *
6794 * @returns VBox status code.
6795 * @param pVCpu The cross context virtual CPU structure.
6796 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6797 * out-of-sync. Make sure to update the required fields
6798 * before using them.
6799 *
6800 * @remarks No-long-jump zone!!!
6801 */
6802static int hmR0VmxSaveGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6803{
6804 /* Guest segment registers. */
6805 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SEGMENT_REGS))
6806 {
6807 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS));
6808 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6809 AssertRCReturn(rc, rc);
6810
6811 rc = VMXLOCAL_READ_SEG(CS, cs);
6812 rc |= VMXLOCAL_READ_SEG(SS, ss);
6813 rc |= VMXLOCAL_READ_SEG(DS, ds);
6814 rc |= VMXLOCAL_READ_SEG(ES, es);
6815 rc |= VMXLOCAL_READ_SEG(FS, fs);
6816 rc |= VMXLOCAL_READ_SEG(GS, gs);
6817 AssertRCReturn(rc, rc);
6818
6819 /* Restore segment attributes for real-on-v86 mode hack. */
6820 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
6821 {
6822 pMixedCtx->cs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrCS.u;
6823 pMixedCtx->ss.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrSS.u;
6824 pMixedCtx->ds.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrDS.u;
6825 pMixedCtx->es.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrES.u;
6826 pMixedCtx->fs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrFS.u;
6827 pMixedCtx->gs.Attr.u = pVCpu->hm.s.vmx.RealMode.AttrGS.u;
6828 }
6829 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SEGMENT_REGS);
6830 }
6831
6832 return VINF_SUCCESS;
6833}
6834
6835
6836/**
6837 * Saves the guest descriptor table registers and task register from the current
6838 * VMCS into the guest-CPU context.
6839 *
6840 * @returns VBox status code.
6841 * @param pVCpu The cross context virtual CPU structure.
6842 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6843 * out-of-sync. Make sure to update the required fields
6844 * before using them.
6845 *
6846 * @remarks No-long-jump zone!!!
6847 */
6848static int hmR0VmxSaveGuestTableRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6849{
6850 int rc = VINF_SUCCESS;
6851
6852 /* Guest LDTR. */
6853 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LDTR))
6854 {
6855 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LDTR));
6856 rc = VMXLOCAL_READ_SEG(LDTR, ldtr);
6857 AssertRCReturn(rc, rc);
6858 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LDTR);
6859 }
6860
6861 /* Guest GDTR. */
6862 uint64_t u64Val = 0;
6863 uint32_t u32Val = 0;
6864 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_GDTR))
6865 {
6866 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_GDTR));
6867 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
6868 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRCReturn(rc, rc);
6869 pMixedCtx->gdtr.pGdt = u64Val;
6870 pMixedCtx->gdtr.cbGdt = u32Val;
6871 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_GDTR);
6872 }
6873
6874 /* Guest IDTR. */
6875 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_IDTR))
6876 {
6877 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_IDTR));
6878 rc = VMXReadVmcsGstN(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
6879 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRCReturn(rc, rc);
6880 pMixedCtx->idtr.pIdt = u64Val;
6881 pMixedCtx->idtr.cbIdt = u32Val;
6882 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_IDTR);
6883 }
6884
6885 /* Guest TR. */
6886 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_TR))
6887 {
6888 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_TR));
6889 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
6890 AssertRCReturn(rc, rc);
6891
6892 /* For real-mode emulation using virtual-8086 mode we have the fake TSS (pRealModeTSS) in TR, don't save the fake one. */
6893 if (!pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
6894 {
6895 rc = VMXLOCAL_READ_SEG(TR, tr);
6896 AssertRCReturn(rc, rc);
6897 }
6898 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_TR);
6899 }
6900 return rc;
6901}
6902
6903#undef VMXLOCAL_READ_SEG
6904
6905
6906/**
6907 * Saves the guest debug-register DR7 from the current VMCS into the guest-CPU
6908 * context.
6909 *
6910 * @returns VBox status code.
6911 * @param pVCpu The cross context virtual CPU structure.
6912 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6913 * out-of-sync. Make sure to update the required fields
6914 * before using them.
6915 *
6916 * @remarks No-long-jump zone!!!
6917 */
6918static int hmR0VmxSaveGuestDR7(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6919{
6920 if (!HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_DR7))
6921 {
6922 if (!pVCpu->hm.s.fUsingHyperDR7)
6923 {
6924 /* Upper 32-bits are always zero. See Intel spec. 2.7.3 "Loading and Storing Debug Registers". */
6925 uint32_t u32Val;
6926 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_DR7, &u32Val); AssertRCReturn(rc, rc);
6927 pMixedCtx->dr[7] = u32Val;
6928 }
6929
6930 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_DR7);
6931 }
6932 return VINF_SUCCESS;
6933}
6934
6935
6936/**
6937 * Saves the guest APIC state from the current VMCS into the guest-CPU context.
6938 *
6939 * @returns VBox status code.
6940 * @param pVCpu The cross context virtual CPU structure.
6941 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
6942 * out-of-sync. Make sure to update the required fields
6943 * before using them.
6944 *
6945 * @remarks No-long-jump zone!!!
6946 */
6947static int hmR0VmxSaveGuestApicState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6948{
6949 NOREF(pMixedCtx);
6950
6951 /* Updating TPR is already done in hmR0VmxPostRunGuest(). Just update the flag. */
6952 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_APIC_STATE);
6953 return VINF_SUCCESS;
6954}
6955
6956
6957/**
6958 * Saves the entire guest state from the currently active VMCS into the
6959 * guest-CPU context.
6960 *
6961 * This essentially VMREADs all guest-data.
6962 *
6963 * @returns VBox status code.
6964 * @param pVCpu The cross context virtual CPU structure.
6965 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
6966 * out-of-sync. Make sure to update the required fields
6967 * before using them.
6968 */
6969static int hmR0VmxSaveGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
6970{
6971 Assert(pVCpu);
6972 Assert(pMixedCtx);
6973
6974 if (HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL)
6975 return VINF_SUCCESS;
6976
6977 /* Though we can longjmp to ring-3 due to log-flushes here and get recalled
6978 again on the ring-3 callback path, there is no real need to. */
6979 if (VMMRZCallRing3IsEnabled(pVCpu))
6980 VMMR0LogFlushDisable(pVCpu);
6981 else
6982 Assert(VMMR0IsLogFlushDisabled(pVCpu));
6983 Log4Func(("vcpu[%RU32]\n", pVCpu->idCpu));
6984
6985 int rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
6986 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestRipRspRflags failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6987
6988 rc = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
6989 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestControlRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6990
6991 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
6992 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSegmentRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6993
6994 rc = hmR0VmxSaveGuestTableRegs(pVCpu, pMixedCtx);
6995 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestTableRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6996
6997 rc = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
6998 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestDR7 failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
6999
7000 rc = hmR0VmxSaveGuestSysenterMsrs(pVCpu, pMixedCtx);
7001 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSysenterMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
7002
7003 rc = hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
7004 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestLazyMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
7005
7006 rc = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
7007 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestAutoLoadStoreMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
7008
7009 rc = hmR0VmxSaveGuestActivityState(pVCpu, pMixedCtx);
7010 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestActivityState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
7011
7012 rc = hmR0VmxSaveGuestApicState(pVCpu, pMixedCtx);
7013 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestApicState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
7014
7015 AssertMsg(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL,
7016 ("Missed guest state bits while saving state; missing %RX32 (got %RX32, want %RX32) - check log for any previous errors!\n",
7017 HMVMX_UPDATED_GUEST_ALL ^ HMVMXCPU_GST_VALUE(pVCpu), HMVMXCPU_GST_VALUE(pVCpu), HMVMX_UPDATED_GUEST_ALL));
7018
7019 if (VMMRZCallRing3IsEnabled(pVCpu))
7020 VMMR0LogFlushEnable(pVCpu);
7021
7022 return VINF_SUCCESS;
7023}
7024
7025
7026/**
7027 * Saves basic guest registers needed for IEM instruction execution.
7028 *
7029 * @returns VBox status code (OR-able).
7030 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
7031 * @param pMixedCtx Pointer to the CPU context of the guest.
7032 * @param fMemory Whether the instruction being executed operates on
7033 * memory or not. Only CR0 is synced up if clear.
7034 * @param fNeedRsp Need RSP (any instruction working on GPRs or stack).
7035 */
7036static int hmR0VmxSaveGuestRegsForIemExec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fMemory, bool fNeedRsp)
7037{
7038 /*
7039 * We assume all general purpose registers other than RSP are available.
7040 *
7041 * - RIP is a must, as it will be incremented or otherwise changed.
7042 * - RFLAGS are always required to figure the CPL.
7043 * - RSP isn't always required, however it's a GPR, so frequently required.
7044 * - SS and CS are the only segment register needed if IEM doesn't do memory
7045 * access (CPL + 16/32/64-bit mode), but we can only get all segment registers.
7046 * - CR0 is always required by IEM for the CPL, while CR3 and CR4 will only
7047 * be required for memory accesses.
7048 *
7049 * Note! Before IEM dispatches an exception, it will call us to sync in everything.
7050 */
7051 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
7052 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7053 if (fNeedRsp)
7054 rc |= hmR0VmxSaveGuestRsp(pVCpu, pMixedCtx);
7055 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
7056 if (!fMemory)
7057 rc |= hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7058 else
7059 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
7060 AssertRCReturn(rc, rc);
7061 return rc;
7062}
7063
7064
7065/**
7066 * Ensures that we've got a complete basic guest-context.
7067 *
7068 * This excludes the FPU, SSE, AVX, and similar extended state. The interface
7069 * is for the interpreter.
7070 *
7071 * @returns VBox status code.
7072 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
7073 * @param pMixedCtx Pointer to the guest-CPU context which may have data
7074 * needing to be synced in.
7075 * @thread EMT(pVCpu)
7076 */
7077VMMR0_INT_DECL(int) HMR0EnsureCompleteBasicContext(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7078{
7079 /* Note! Since this is only applicable to VT-x, the implementation is placed
7080 in the VT-x part of the sources instead of the generic stuff. */
7081 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported)
7082 {
7083 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
7084 /*
7085 * For now, imply that the caller might change everything too. Do this after
7086 * saving the guest state so as to not trigger assertions.
7087 */
7088 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
7089 return rc;
7090 }
7091 return VINF_SUCCESS;
7092}
7093
7094
7095/**
7096 * Check per-VM and per-VCPU force flag actions that require us to go back to
7097 * ring-3 for one reason or another.
7098 *
7099 * @returns Strict VBox status code (i.e. informational status codes too)
7100 * @retval VINF_SUCCESS if we don't have any actions that require going back to
7101 * ring-3.
7102 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
7103 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
7104 * interrupts)
7105 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
7106 * all EMTs to be in ring-3.
7107 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
7108 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
7109 * to the EM loop.
7110 *
7111 * @param pVM The cross context VM structure.
7112 * @param pVCpu The cross context virtual CPU structure.
7113 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7114 * out-of-sync. Make sure to update the required fields
7115 * before using them.
7116 * @param fStepping Running in hmR0VmxRunGuestCodeStep().
7117 */
7118static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fStepping)
7119{
7120 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7121
7122 /*
7123 * Anything pending? Should be more likely than not if we're doing a good job.
7124 */
7125 if ( !fStepping
7126 ? !VM_FF_IS_PENDING(pVM, VM_FF_HP_R0_PRE_HM_MASK)
7127 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
7128 : !VM_FF_IS_PENDING(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
7129 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
7130 return VINF_SUCCESS;
7131
7132 /* We need the control registers now, make sure the guest-CPU context is updated. */
7133 int rc3 = hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
7134 AssertRCReturn(rc3, rc3);
7135
7136 /* Pending HM CR3 sync. */
7137 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
7138 {
7139 int rc2 = PGMUpdateCR3(pVCpu, pMixedCtx->cr3);
7140 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
7141 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
7142 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
7143 }
7144
7145 /* Pending HM PAE PDPEs. */
7146 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
7147 {
7148 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
7149 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
7150 }
7151
7152 /* Pending PGM C3 sync. */
7153 if (VMCPU_FF_IS_PENDING(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
7154 {
7155 VBOXSTRICTRC rcStrict2 = PGMSyncCR3(pVCpu, pMixedCtx->cr0, pMixedCtx->cr3, pMixedCtx->cr4,
7156 VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
7157 if (rcStrict2 != VINF_SUCCESS)
7158 {
7159 AssertRC(VBOXSTRICTRC_VAL(rcStrict2));
7160 Log4(("hmR0VmxCheckForceFlags: PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict2)));
7161 return rcStrict2;
7162 }
7163 }
7164
7165 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
7166 if ( VM_FF_IS_PENDING(pVM, VM_FF_HM_TO_R3_MASK)
7167 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
7168 {
7169 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
7170 int rc2 = RT_UNLIKELY(VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_NO_MEMORY : VINF_EM_RAW_TO_R3;
7171 Log4(("hmR0VmxCheckForceFlags: HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc2));
7172 return rc2;
7173 }
7174
7175 /* Pending VM request packets, such as hardware interrupts. */
7176 if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST)
7177 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
7178 {
7179 Log4(("hmR0VmxCheckForceFlags: Pending VM request forcing us back to ring-3\n"));
7180 return VINF_EM_PENDING_REQUEST;
7181 }
7182
7183 /* Pending PGM pool flushes. */
7184 if (VM_FF_IS_PENDING(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
7185 {
7186 Log4(("hmR0VmxCheckForceFlags: PGM pool flush pending forcing us back to ring-3\n"));
7187 return VINF_PGM_POOL_FLUSH_PENDING;
7188 }
7189
7190 /* Pending DMA requests. */
7191 if (VM_FF_IS_PENDING(pVM, VM_FF_PDM_DMA))
7192 {
7193 Log4(("hmR0VmxCheckForceFlags: Pending DMA request forcing us back to ring-3\n"));
7194 return VINF_EM_RAW_TO_R3;
7195 }
7196
7197 return VINF_SUCCESS;
7198}
7199
7200
7201/**
7202 * Converts any TRPM trap into a pending HM event. This is typically used when
7203 * entering from ring-3 (not longjmp returns).
7204 *
7205 * @param pVCpu The cross context virtual CPU structure.
7206 */
7207static void hmR0VmxTrpmTrapToPendingEvent(PVMCPU pVCpu)
7208{
7209 Assert(TRPMHasTrap(pVCpu));
7210 Assert(!pVCpu->hm.s.Event.fPending);
7211
7212 uint8_t uVector;
7213 TRPMEVENT enmTrpmEvent;
7214 RTGCUINT uErrCode;
7215 RTGCUINTPTR GCPtrFaultAddress;
7216 uint8_t cbInstr;
7217
7218 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
7219 AssertRC(rc);
7220
7221 /* Refer Intel spec. 24.8.3 "VM-entry Controls for Event Injection" for the format of u32IntInfo. */
7222 uint32_t u32IntInfo = uVector | VMX_EXIT_INTERRUPTION_INFO_VALID;
7223 if (enmTrpmEvent == TRPM_TRAP)
7224 {
7225 switch (uVector)
7226 {
7227 case X86_XCPT_NMI:
7228 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7229 break;
7230
7231 case X86_XCPT_BP:
7232 case X86_XCPT_OF:
7233 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7234 break;
7235
7236 case X86_XCPT_PF:
7237 case X86_XCPT_DF:
7238 case X86_XCPT_TS:
7239 case X86_XCPT_NP:
7240 case X86_XCPT_SS:
7241 case X86_XCPT_GP:
7242 case X86_XCPT_AC:
7243 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
7244 /* fall thru */
7245 default:
7246 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7247 break;
7248 }
7249 }
7250 else if (enmTrpmEvent == TRPM_HARDWARE_INT)
7251 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7252 else if (enmTrpmEvent == TRPM_SOFTWARE_INT)
7253 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7254 else
7255 AssertMsgFailed(("Invalid TRPM event type %d\n", enmTrpmEvent));
7256
7257 rc = TRPMResetTrap(pVCpu);
7258 AssertRC(rc);
7259 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
7260 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
7261
7262 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
7263}
7264
7265
7266/**
7267 * Converts the pending HM event into a TRPM trap.
7268 *
7269 * @param pVCpu The cross context virtual CPU structure.
7270 */
7271static void hmR0VmxPendingEventToTrpmTrap(PVMCPU pVCpu)
7272{
7273 Assert(pVCpu->hm.s.Event.fPending);
7274
7275 uint32_t uVectorType = VMX_IDT_VECTORING_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
7276 uint32_t uVector = VMX_IDT_VECTORING_INFO_VECTOR(pVCpu->hm.s.Event.u64IntInfo);
7277 bool fErrorCodeValid = VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVCpu->hm.s.Event.u64IntInfo);
7278 uint32_t uErrorCode = pVCpu->hm.s.Event.u32ErrCode;
7279
7280 /* If a trap was already pending, we did something wrong! */
7281 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
7282
7283 TRPMEVENT enmTrapType;
7284 switch (uVectorType)
7285 {
7286 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
7287 enmTrapType = TRPM_HARDWARE_INT;
7288 break;
7289
7290 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
7291 enmTrapType = TRPM_SOFTWARE_INT;
7292 break;
7293
7294 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
7295 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
7296 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT: /* #BP and #OF */
7297 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
7298 enmTrapType = TRPM_TRAP;
7299 break;
7300
7301 default:
7302 AssertMsgFailed(("Invalid trap type %#x\n", uVectorType));
7303 enmTrapType = TRPM_32BIT_HACK;
7304 break;
7305 }
7306
7307 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
7308
7309 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
7310 AssertRC(rc);
7311
7312 if (fErrorCodeValid)
7313 TRPMSetErrorCode(pVCpu, uErrorCode);
7314
7315 if ( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
7316 && uVector == X86_XCPT_PF)
7317 {
7318 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
7319 }
7320 else if ( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
7321 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
7322 || uVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
7323 {
7324 AssertMsg( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
7325 || (uVector == X86_XCPT_BP || uVector == X86_XCPT_OF),
7326 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
7327 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
7328 }
7329
7330 /* Clear any pending events from the VMCS. */
7331 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
7332 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, 0); AssertRC(rc);
7333
7334 /* We're now done converting the pending event. */
7335 pVCpu->hm.s.Event.fPending = false;
7336}
7337
7338
7339/**
7340 * Does the necessary state syncing before returning to ring-3 for any reason
7341 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
7342 *
7343 * @returns VBox status code.
7344 * @param pVCpu The cross context virtual CPU structure.
7345 * @param pMixedCtx Pointer to the guest-CPU context. The data may
7346 * be out-of-sync. Make sure to update the required
7347 * fields before using them.
7348 * @param fSaveGuestState Whether to save the guest state or not.
7349 *
7350 * @remarks No-long-jmp zone!!!
7351 */
7352static int hmR0VmxLeave(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fSaveGuestState)
7353{
7354 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7355 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7356
7357 RTCPUID idCpu = RTMpCpuId();
7358 Log4Func(("HostCpuId=%u\n", idCpu));
7359
7360 /*
7361 * !!! IMPORTANT !!!
7362 * If you modify code here, check whether hmR0VmxCallRing3Callback() needs to be updated too.
7363 */
7364
7365 /* Save the guest state if necessary. */
7366 if ( fSaveGuestState
7367 && HMVMXCPU_GST_VALUE(pVCpu) != HMVMX_UPDATED_GUEST_ALL)
7368 {
7369 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
7370 AssertRCReturn(rc, rc);
7371 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
7372 }
7373
7374 /* Restore host FPU state if necessary and resync on next R0 reentry .*/
7375 if (CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu))
7376 {
7377 /* We shouldn't reload CR0 without saving it first. */
7378 if (!fSaveGuestState)
7379 {
7380 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
7381 AssertRCReturn(rc, rc);
7382 }
7383 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
7384 }
7385
7386 /* Restore host debug registers if necessary and resync on next R0 reentry. */
7387#ifdef VBOX_STRICT
7388 if (CPUMIsHyperDebugStateActive(pVCpu))
7389 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT);
7390#endif
7391 if (CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */))
7392 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
7393 Assert(!CPUMIsGuestDebugStateActive(pVCpu) && !CPUMIsGuestDebugStateActivePending(pVCpu));
7394 Assert(!CPUMIsHyperDebugStateActive(pVCpu) && !CPUMIsHyperDebugStateActivePending(pVCpu));
7395
7396#if HC_ARCH_BITS == 64
7397 /* Restore host-state bits that VT-x only restores partially. */
7398 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7399 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7400 {
7401 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
7402 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7403 }
7404 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7405#endif
7406
7407 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7408 if (pVCpu->hm.s.vmx.fLazyMsrs)
7409 {
7410 /* We shouldn't reload the guest MSRs without saving it first. */
7411 if (!fSaveGuestState)
7412 {
7413 int rc = hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
7414 AssertRCReturn(rc, rc);
7415 }
7416 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_LAZY_MSRS));
7417 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7418 Assert(!pVCpu->hm.s.vmx.fLazyMsrs);
7419 }
7420
7421 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7422 pVCpu->hm.s.vmx.fUpdatedHostMsrs = false;
7423
7424 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
7425 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatLoadGuestState);
7426 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExit1);
7427 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExit2);
7428 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
7429 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
7430 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
7431 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7432
7433 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7434
7435 /** @todo This partially defeats the purpose of having preemption hooks.
7436 * The problem is, deregistering the hooks should be moved to a place that
7437 * lasts until the EMT is about to be destroyed not everytime while leaving HM
7438 * context.
7439 */
7440 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_ACTIVE)
7441 {
7442 int rc = VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
7443 AssertRCReturn(rc, rc);
7444
7445 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
7446 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
7447 }
7448 Assert(!(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_LAUNCHED));
7449 NOREF(idCpu);
7450
7451 return VINF_SUCCESS;
7452}
7453
7454
7455/**
7456 * Leaves the VT-x session.
7457 *
7458 * @returns VBox status code.
7459 * @param pVCpu The cross context virtual CPU structure.
7460 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7461 * out-of-sync. Make sure to update the required fields
7462 * before using them.
7463 *
7464 * @remarks No-long-jmp zone!!!
7465 */
7466DECLINLINE(int) hmR0VmxLeaveSession(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7467{
7468 HM_DISABLE_PREEMPT();
7469 HMVMX_ASSERT_CPU_SAFE();
7470 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
7471 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
7472
7473 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
7474 and done this from the VMXR0ThreadCtxCallback(). */
7475 if (!pVCpu->hm.s.fLeaveDone)
7476 {
7477 int rc2 = hmR0VmxLeave(pVCpu, pMixedCtx, true /* fSaveGuestState */);
7478 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
7479 pVCpu->hm.s.fLeaveDone = true;
7480 }
7481 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
7482
7483 /*
7484 * !!! IMPORTANT !!!
7485 * If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
7486 */
7487
7488 /* Deregister hook now that we've left HM context before re-enabling preemption. */
7489 /** @todo Deregistering here means we need to VMCLEAR always
7490 * (longjmp/exit-to-r3) in VT-x which is not efficient. */
7491 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
7492 VMMR0ThreadCtxHookDisable(pVCpu);
7493
7494 /* Leave HM context. This takes care of local init (term). */
7495 int rc = HMR0LeaveCpu(pVCpu);
7496
7497 HM_RESTORE_PREEMPT();
7498 return rc;
7499}
7500
7501
7502/**
7503 * Does the necessary state syncing before doing a longjmp to ring-3.
7504 *
7505 * @returns VBox status code.
7506 * @param pVCpu The cross context virtual CPU structure.
7507 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7508 * out-of-sync. Make sure to update the required fields
7509 * before using them.
7510 *
7511 * @remarks No-long-jmp zone!!!
7512 */
7513DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7514{
7515 return hmR0VmxLeaveSession(pVCpu, pMixedCtx);
7516}
7517
7518
7519/**
7520 * Take necessary actions before going back to ring-3.
7521 *
7522 * An action requires us to go back to ring-3. This function does the necessary
7523 * steps before we can safely return to ring-3. This is not the same as longjmps
7524 * to ring-3, this is voluntary and prepares the guest so it may continue
7525 * executing outside HM (recompiler/IEM).
7526 *
7527 * @returns VBox status code.
7528 * @param pVM The cross context VM structure.
7529 * @param pVCpu The cross context virtual CPU structure.
7530 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7531 * out-of-sync. Make sure to update the required fields
7532 * before using them.
7533 * @param rcExit The reason for exiting to ring-3. Can be
7534 * VINF_VMM_UNKNOWN_RING3_CALL.
7535 */
7536static int hmR0VmxExitToRing3(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, VBOXSTRICTRC rcExit)
7537{
7538 Assert(pVM);
7539 Assert(pVCpu);
7540 Assert(pMixedCtx);
7541 HMVMX_ASSERT_PREEMPT_SAFE();
7542
7543 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
7544 {
7545 VMXGetActivatedVmcs(&pVCpu->hm.s.vmx.LastError.u64VMCSPhys);
7546 pVCpu->hm.s.vmx.LastError.u32VMCSRevision = *(uint32_t *)pVCpu->hm.s.vmx.pvVmcs;
7547 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hm.s.idEnteredCpu;
7548 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
7549 }
7550
7551 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
7552 VMMRZCallRing3Disable(pVCpu);
7553 Log4(("hmR0VmxExitToRing3: pVCpu=%p idCpu=%RU32 rcExit=%d\n", pVCpu, pVCpu->idCpu, VBOXSTRICTRC_VAL(rcExit)));
7554
7555 /* We need to do this only while truly exiting the "inner loop" back to ring-3 and -not- for any longjmp to ring3. */
7556 if (pVCpu->hm.s.Event.fPending)
7557 {
7558 hmR0VmxPendingEventToTrpmTrap(pVCpu);
7559 Assert(!pVCpu->hm.s.Event.fPending);
7560 }
7561
7562 /* Clear interrupt-window and NMI-window controls as we re-evaluate it when we return from ring-3. */
7563 hmR0VmxClearIntNmiWindowsVmcs(pVCpu);
7564
7565 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
7566 and if we're injecting an event we should have a TRPM trap pending. */
7567 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
7568#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a tripple fault in progress. */
7569 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
7570#endif
7571
7572 /* Save guest state and restore host state bits. */
7573 int rc = hmR0VmxLeaveSession(pVCpu, pMixedCtx);
7574 AssertRCReturn(rc, rc);
7575 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
7576 /* Thread-context hooks are unregistered at this point!!! */
7577
7578 /* Sync recompiler state. */
7579 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
7580 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
7581 | CPUM_CHANGED_LDTR
7582 | CPUM_CHANGED_GDTR
7583 | CPUM_CHANGED_IDTR
7584 | CPUM_CHANGED_TR
7585 | CPUM_CHANGED_HIDDEN_SEL_REGS);
7586 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
7587 if ( pVM->hm.s.fNestedPaging
7588 && CPUMIsGuestPagingEnabledEx(pMixedCtx))
7589 {
7590 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
7591 }
7592
7593 Assert(!pVCpu->hm.s.fClearTrapFlag);
7594
7595 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
7596 if (rcExit != VINF_EM_RAW_INTERRUPT)
7597 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
7598
7599 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
7600
7601 /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
7602 VMMRZCallRing3RemoveNotification(pVCpu);
7603 VMMRZCallRing3Enable(pVCpu);
7604
7605 return rc;
7606}
7607
7608
7609/**
7610 * VMMRZCallRing3() callback wrapper which saves the guest state before we
7611 * longjump to ring-3 and possibly get preempted.
7612 *
7613 * @returns VBox status code.
7614 * @param pVCpu The cross context virtual CPU structure.
7615 * @param enmOperation The operation causing the ring-3 longjump.
7616 * @param pvUser Opaque pointer to the guest-CPU context. The data
7617 * may be out-of-sync. Make sure to update the required
7618 * fields before using them.
7619 */
7620static DECLCALLBACK(int) hmR0VmxCallRing3Callback(PVMCPU pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
7621{
7622 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
7623 {
7624 /*
7625 * !!! IMPORTANT !!!
7626 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
7627 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
7628 */
7629 VMMRZCallRing3RemoveNotification(pVCpu);
7630 VMMRZCallRing3Disable(pVCpu);
7631 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
7632 RTThreadPreemptDisable(&PreemptState);
7633
7634 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
7635 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
7636
7637#if HC_ARCH_BITS == 64
7638 /* Restore host-state bits that VT-x only restores partially. */
7639 if ( (pVCpu->hm.s.vmx.fRestoreHostFlags & VMX_RESTORE_HOST_REQUIRED)
7640 && (pVCpu->hm.s.vmx.fRestoreHostFlags & ~VMX_RESTORE_HOST_REQUIRED))
7641 VMXRestoreHostState(pVCpu->hm.s.vmx.fRestoreHostFlags, &pVCpu->hm.s.vmx.RestoreHost);
7642 pVCpu->hm.s.vmx.fRestoreHostFlags = 0;
7643#endif
7644 /* Restore the lazy host MSRs as we're leaving VT-x context. */
7645 if (pVCpu->hm.s.vmx.fLazyMsrs)
7646 hmR0VmxLazyRestoreHostMsrs(pVCpu);
7647
7648 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
7649 pVCpu->hm.s.vmx.fUpdatedHostMsrs = false;
7650 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
7651 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_ACTIVE)
7652 {
7653 VMXClearVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
7654 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_CLEAR;
7655 }
7656
7657 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
7658 VMMR0ThreadCtxHookDisable(pVCpu);
7659 HMR0LeaveCpu(pVCpu);
7660 RTThreadPreemptRestore(&PreemptState);
7661 return VINF_SUCCESS;
7662 }
7663
7664 Assert(pVCpu);
7665 Assert(pvUser);
7666 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7667 HMVMX_ASSERT_PREEMPT_SAFE();
7668
7669 VMMRZCallRing3Disable(pVCpu);
7670 Assert(VMMR0IsLogFlushDisabled(pVCpu));
7671
7672 Log4(("hmR0VmxCallRing3Callback->hmR0VmxLongJmpToRing3 pVCpu=%p idCpu=%RU32 enmOperation=%d\n", pVCpu, pVCpu->idCpu,
7673 enmOperation));
7674
7675 int rc = hmR0VmxLongJmpToRing3(pVCpu, (PCPUMCTX)pvUser);
7676 AssertRCReturn(rc, rc);
7677
7678 VMMRZCallRing3Enable(pVCpu);
7679 return VINF_SUCCESS;
7680}
7681
7682
7683/**
7684 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
7685 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
7686 *
7687 * @param pVCpu The cross context virtual CPU structure.
7688 */
7689DECLINLINE(void) hmR0VmxSetIntWindowExitVmcs(PVMCPU pVCpu)
7690{
7691 if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
7692 {
7693 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
7694 {
7695 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT;
7696 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7697 AssertRC(rc);
7698 Log4(("Setup interrupt-window exiting\n"));
7699 }
7700 } /* else we will deliver interrupts whenever the guest exits next and is in a state to receive events. */
7701}
7702
7703
7704/**
7705 * Clears the interrupt-window exiting control in the VMCS.
7706 *
7707 * @param pVCpu The cross context virtual CPU structure.
7708 */
7709DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMCPU pVCpu)
7710{
7711 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT);
7712 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT;
7713 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7714 AssertRC(rc);
7715 Log4(("Cleared interrupt-window exiting\n"));
7716}
7717
7718
7719/**
7720 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
7721 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
7722 *
7723 * @param pVCpu The cross context virtual CPU structure.
7724 */
7725DECLINLINE(void) hmR0VmxSetNmiWindowExitVmcs(PVMCPU pVCpu)
7726{
7727 if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT))
7728 {
7729 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT))
7730 {
7731 pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT;
7732 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7733 AssertRC(rc);
7734 Log4(("Setup NMI-window exiting\n"));
7735 }
7736 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
7737}
7738
7739
7740/**
7741 * Clears the NMI-window exiting control in the VMCS.
7742 *
7743 * @param pVCpu The cross context virtual CPU structure.
7744 */
7745DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMCPU pVCpu)
7746{
7747 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT);
7748 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT;
7749 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
7750 AssertRC(rc);
7751 Log4(("Cleared NMI-window exiting\n"));
7752}
7753
7754
7755/**
7756 * Evaluates the event to be delivered to the guest and sets it as the pending
7757 * event.
7758 *
7759 * @returns The VT-x guest-interruptibility state.
7760 * @param pVCpu The cross context virtual CPU structure.
7761 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7762 * out-of-sync. Make sure to update the required fields
7763 * before using them.
7764 */
7765static uint32_t hmR0VmxEvaluatePendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7766{
7767 /* Get the current interruptibility-state of the guest and then figure out what can be injected. */
7768 uint32_t const uIntrState = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx);
7769 bool const fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7770 bool const fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7771 bool const fBlockNmi = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI);
7772
7773 Assert(!fBlockSti || HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS));
7774 Assert(!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
7775 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
7776 Assert(!TRPMHasTrap(pVCpu));
7777
7778 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
7779 APICUpdatePendingInterrupts(pVCpu);
7780
7781 /*
7782 * Toggling of interrupt force-flags here is safe since we update TRPM on premature exits
7783 * to ring-3 before executing guest code, see hmR0VmxExitToRing3(). We must NOT restore these force-flags.
7784 */
7785 /** @todo SMI. SMIs take priority over NMIs. */
7786 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NMI)) /* NMI. NMIs take priority over regular interrupts. */
7787 {
7788 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
7789 if ( !pVCpu->hm.s.Event.fPending
7790 && !fBlockNmi
7791 && !fBlockSti
7792 && !fBlockMovSS)
7793 {
7794 Log4(("Pending NMI vcpu[%RU32]\n", pVCpu->idCpu));
7795 uint32_t u32IntInfo = X86_XCPT_NMI | VMX_EXIT_INTERRUPTION_INFO_VALID;
7796 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7797
7798 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7799 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
7800 }
7801 else
7802 hmR0VmxSetNmiWindowExitVmcs(pVCpu);
7803 }
7804 /*
7805 * Check if the guest can receive external interrupts (PIC/APIC). Once PDMGetInterrupt() returns
7806 * a valid interrupt we must- deliver the interrupt. We can no longer re-request it from the APIC.
7807 */
7808 else if ( VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
7809 && !pVCpu->hm.s.fSingleInstruction)
7810 {
7811 Assert(!DBGFIsStepping(pVCpu));
7812 int rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7813 AssertRC(rc);
7814 bool const fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
7815 if ( !pVCpu->hm.s.Event.fPending
7816 && !fBlockInt
7817 && !fBlockSti
7818 && !fBlockMovSS)
7819 {
7820 uint8_t u8Interrupt;
7821 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
7822 if (RT_SUCCESS(rc))
7823 {
7824 Log4(("Pending interrupt vcpu[%RU32] u8Interrupt=%#x \n", pVCpu->idCpu, u8Interrupt));
7825 uint32_t u32IntInfo = u8Interrupt | VMX_EXIT_INTERRUPTION_INFO_VALID;
7826 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
7827
7828 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrfaultAddress */);
7829 }
7830 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
7831 {
7832 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
7833 hmR0VmxApicSetTprThreshold(pVCpu, u8Interrupt >> 4);
7834 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
7835
7836 /*
7837 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
7838 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
7839 * need to re-set this force-flag here.
7840 */
7841 }
7842 else
7843 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
7844 }
7845 else
7846 hmR0VmxSetIntWindowExitVmcs(pVCpu);
7847 }
7848
7849 return uIntrState;
7850}
7851
7852
7853/**
7854 * Sets a pending-debug exception to be delivered to the guest if the guest is
7855 * single-stepping in the VMCS.
7856 *
7857 * @param pVCpu The cross context virtual CPU structure.
7858 */
7859DECLINLINE(void) hmR0VmxSetPendingDebugXcptVmcs(PVMCPU pVCpu)
7860{
7861 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS)); NOREF(pVCpu);
7862 int rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_BS);
7863 AssertRC(rc);
7864}
7865
7866
7867/**
7868 * Injects any pending events into the guest if the guest is in a state to
7869 * receive them.
7870 *
7871 * @returns Strict VBox status code (i.e. informational status codes too).
7872 * @param pVCpu The cross context virtual CPU structure.
7873 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7874 * out-of-sync. Make sure to update the required fields
7875 * before using them.
7876 * @param uIntrState The VT-x guest-interruptibility state.
7877 * @param fStepping Running in hmR0VmxRunGuestCodeStep() and we should
7878 * return VINF_EM_DBG_STEPPED if the event was
7879 * dispatched directly.
7880 */
7881static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t uIntrState, bool fStepping)
7882{
7883 HMVMX_ASSERT_PREEMPT_SAFE();
7884 Assert(VMMRZCallRing3IsEnabled(pVCpu));
7885
7886 bool fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7887 bool fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7888
7889 Assert(!fBlockSti || HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RFLAGS));
7890 Assert(!(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
7891 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
7892 Assert(!TRPMHasTrap(pVCpu));
7893
7894 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
7895 if (pVCpu->hm.s.Event.fPending)
7896 {
7897 /*
7898 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
7899 * pending even while injecting an event and in this case, we want a VM-exit as soon as
7900 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
7901 *
7902 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
7903 */
7904 uint32_t const uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
7905#ifdef VBOX_STRICT
7906 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
7907 {
7908 bool const fBlockInt = !(pMixedCtx->eflags.u32 & X86_EFL_IF);
7909 Assert(!fBlockInt);
7910 Assert(!fBlockSti);
7911 Assert(!fBlockMovSS);
7912 }
7913 else if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
7914 {
7915 bool const fBlockNmi = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI);
7916 Assert(!fBlockSti);
7917 Assert(!fBlockMovSS);
7918 Assert(!fBlockNmi);
7919 }
7920#endif
7921 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#x\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
7922 (uint8_t)uIntType));
7923 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, pVCpu->hm.s.Event.u64IntInfo, pVCpu->hm.s.Event.cbInstr,
7924 pVCpu->hm.s.Event.u32ErrCode, pVCpu->hm.s.Event.GCPtrFaultAddress,
7925 fStepping, &uIntrState);
7926 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
7927
7928 /* Update the interruptibility-state as it could have been changed by
7929 hmR0VmxInjectEventVmcs() (e.g. real-on-v86 guest injecting software interrupts) */
7930 fBlockMovSS = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS);
7931 fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
7932
7933 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
7934 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
7935 else
7936 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
7937 }
7938
7939 /* Deliver pending debug exception if the guest is single-stepping. Evaluate and set the BS bit. */
7940 if ( fBlockSti
7941 || fBlockMovSS)
7942 {
7943 if (!pVCpu->hm.s.fSingleInstruction)
7944 {
7945 /*
7946 * The pending-debug exceptions field is cleared on all VM-exits except VMX_EXIT_TPR_BELOW_THRESHOLD,
7947 * VMX_EXIT_MTF, VMX_EXIT_APIC_WRITE and VMX_EXIT_VIRTUALIZED_EOI.
7948 * See Intel spec. 27.3.4 "Saving Non-Register State".
7949 */
7950 Assert(!DBGFIsStepping(pVCpu));
7951 int rc2 = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
7952 AssertRCReturn(rc2, rc2);
7953 if (pMixedCtx->eflags.Bits.u1TF)
7954 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
7955 }
7956 else if (pMixedCtx->eflags.Bits.u1TF)
7957 {
7958 /*
7959 * We are single-stepping in the hypervisor debugger using EFLAGS.TF. Clear interrupt inhibition as setting the
7960 * BS bit would mean delivering a #DB to the guest upon VM-entry when it shouldn't be.
7961 */
7962 Assert(!(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG));
7963 uIntrState = 0;
7964 }
7965 }
7966
7967 /*
7968 * There's no need to clear the VM-entry interruption-information field here if we're not injecting anything.
7969 * VT-x clears the valid bit on every VM-exit. See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
7970 */
7971 int rc2 = hmR0VmxLoadGuestIntrState(pVCpu, uIntrState);
7972 AssertRC(rc2);
7973
7974 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
7975 NOREF(fBlockMovSS); NOREF(fBlockSti);
7976 return rcStrict;
7977}
7978
7979
7980/**
7981 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
7982 *
7983 * @param pVCpu The cross context virtual CPU structure.
7984 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
7985 * out-of-sync. Make sure to update the required fields
7986 * before using them.
7987 */
7988DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
7989{
7990 NOREF(pMixedCtx);
7991 uint32_t u32IntInfo = X86_XCPT_UD | VMX_EXIT_INTERRUPTION_INFO_VALID;
7992 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7993}
7994
7995
7996/**
7997 * Injects a double-fault (\#DF) exception into the VM.
7998 *
7999 * @returns Strict VBox status code (i.e. informational status codes too).
8000 * @param pVCpu The cross context virtual CPU structure.
8001 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8002 * out-of-sync. Make sure to update the required fields
8003 * before using them.
8004 * @param fStepping Whether we're running in hmR0VmxRunGuestCodeStep()
8005 * and should return VINF_EM_DBG_STEPPED if the event
8006 * is injected directly (register modified by us, not
8007 * by hardware on VM-entry).
8008 * @param puIntrState Pointer to the current guest interruptibility-state.
8009 * This interruptibility-state will be updated if
8010 * necessary. This cannot not be NULL.
8011 */
8012DECLINLINE(VBOXSTRICTRC) hmR0VmxInjectXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fStepping, uint32_t *puIntrState)
8013{
8014 uint32_t u32IntInfo = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
8015 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
8016 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
8017 return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */,
8018 fStepping, puIntrState);
8019}
8020
8021
8022/**
8023 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
8024 *
8025 * @param pVCpu The cross context virtual CPU structure.
8026 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8027 * out-of-sync. Make sure to update the required fields
8028 * before using them.
8029 */
8030DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
8031{
8032 NOREF(pMixedCtx);
8033 uint32_t u32IntInfo = X86_XCPT_DB | VMX_EXIT_INTERRUPTION_INFO_VALID;
8034 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
8035 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
8036}
8037
8038
8039/**
8040 * Sets an overflow (\#OF) exception as pending-for-injection into the VM.
8041 *
8042 * @param pVCpu The cross context virtual CPU structure.
8043 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8044 * out-of-sync. Make sure to update the required fields
8045 * before using them.
8046 * @param cbInstr The value of RIP that is to be pushed on the guest
8047 * stack.
8048 */
8049DECLINLINE(void) hmR0VmxSetPendingXcptOF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
8050{
8051 NOREF(pMixedCtx);
8052 uint32_t u32IntInfo = X86_XCPT_OF | VMX_EXIT_INTERRUPTION_INFO_VALID;
8053 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
8054 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
8055}
8056
8057
8058/**
8059 * Injects a general-protection (\#GP) fault into the VM.
8060 *
8061 * @returns Strict VBox status code (i.e. informational status codes too).
8062 * @param pVCpu The cross context virtual CPU structure.
8063 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8064 * out-of-sync. Make sure to update the required fields
8065 * before using them.
8066 * @param fErrorCodeValid Whether the error code is valid (depends on the CPU
8067 * mode, i.e. in real-mode it's not valid).
8068 * @param u32ErrorCode The error code associated with the \#GP.
8069 * @param fStepping Whether we're running in
8070 * hmR0VmxRunGuestCodeStep() and should return
8071 * VINF_EM_DBG_STEPPED if the event is injected
8072 * directly (register modified by us, not by
8073 * hardware on VM-entry).
8074 * @param puIntrState Pointer to the current guest interruptibility-state.
8075 * This interruptibility-state will be updated if
8076 * necessary. This cannot not be NULL.
8077 */
8078DECLINLINE(VBOXSTRICTRC) hmR0VmxInjectXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fErrorCodeValid, uint32_t u32ErrorCode,
8079 bool fStepping, uint32_t *puIntrState)
8080{
8081 uint32_t u32IntInfo = X86_XCPT_GP | VMX_EXIT_INTERRUPTION_INFO_VALID;
8082 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
8083 if (fErrorCodeValid)
8084 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
8085 return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */,
8086 fStepping, puIntrState);
8087}
8088
8089
8090#if 0 /* unused */
8091/**
8092 * Sets a general-protection (\#GP) exception as pending-for-injection into the
8093 * VM.
8094 *
8095 * @param pVCpu The cross context virtual CPU structure.
8096 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8097 * out-of-sync. Make sure to update the required fields
8098 * before using them.
8099 * @param u32ErrorCode The error code associated with the \#GP.
8100 */
8101DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t u32ErrorCode)
8102{
8103 NOREF(pMixedCtx);
8104 uint32_t u32IntInfo = X86_XCPT_GP | VMX_EXIT_INTERRUPTION_INFO_VALID;
8105 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
8106 u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
8107 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */);
8108}
8109#endif /* unused */
8110
8111
8112/**
8113 * Sets a software interrupt (INTn) as pending-for-injection into the VM.
8114 *
8115 * @param pVCpu The cross context virtual CPU structure.
8116 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8117 * out-of-sync. Make sure to update the required fields
8118 * before using them.
8119 * @param uVector The software interrupt vector number.
8120 * @param cbInstr The value of RIP that is to be pushed on the guest
8121 * stack.
8122 */
8123DECLINLINE(void) hmR0VmxSetPendingIntN(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint16_t uVector, uint32_t cbInstr)
8124{
8125 NOREF(pMixedCtx);
8126 uint32_t u32IntInfo = uVector | VMX_EXIT_INTERRUPTION_INFO_VALID;
8127 if ( uVector == X86_XCPT_BP
8128 || uVector == X86_XCPT_OF)
8129 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
8130 else
8131 u32IntInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
8132 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
8133}
8134
8135
8136/**
8137 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8138 * stack.
8139 *
8140 * @returns Strict VBox status code (i.e. informational status codes too).
8141 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8142 * @param pVM The cross context VM structure.
8143 * @param pMixedCtx Pointer to the guest-CPU context.
8144 * @param uValue The value to push to the guest stack.
8145 */
8146DECLINLINE(VBOXSTRICTRC) hmR0VmxRealModeGuestStackPush(PVM pVM, PCPUMCTX pMixedCtx, uint16_t uValue)
8147{
8148 /*
8149 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8150 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8151 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8152 */
8153 if (pMixedCtx->sp == 1)
8154 return VINF_EM_RESET;
8155 pMixedCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8156 int rc = PGMPhysSimpleWriteGCPhys(pVM, pMixedCtx->ss.u64Base + pMixedCtx->sp, &uValue, sizeof(uint16_t));
8157 AssertRC(rc);
8158 return rc;
8159}
8160
8161
8162/**
8163 * Injects an event into the guest upon VM-entry by updating the relevant fields
8164 * in the VM-entry area in the VMCS.
8165 *
8166 * @returns Strict VBox status code (i.e. informational status codes too).
8167 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8168 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8169 *
8170 * @param pVCpu The cross context virtual CPU structure.
8171 * @param pMixedCtx Pointer to the guest-CPU context. The data may
8172 * be out-of-sync. Make sure to update the required
8173 * fields before using them.
8174 * @param u64IntInfo The VM-entry interruption-information field.
8175 * @param cbInstr The VM-entry instruction length in bytes (for
8176 * software interrupts, exceptions and privileged
8177 * software exceptions).
8178 * @param u32ErrCode The VM-entry exception error code.
8179 * @param GCPtrFaultAddress The page-fault address for \#PF exceptions.
8180 * @param puIntrState Pointer to the current guest interruptibility-state.
8181 * This interruptibility-state will be updated if
8182 * necessary. This cannot not be NULL.
8183 * @param fStepping Whether we're running in
8184 * hmR0VmxRunGuestCodeStep() and should return
8185 * VINF_EM_DBG_STEPPED if the event is injected
8186 * directly (register modified by us, not by
8187 * hardware on VM-entry).
8188 *
8189 * @remarks Requires CR0!
8190 */
8191static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
8192 uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, bool fStepping,
8193 uint32_t *puIntrState)
8194{
8195 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8196 AssertMsg(u64IntInfo >> 32 == 0, ("%#RX64\n", u64IntInfo));
8197 Assert(puIntrState);
8198 uint32_t u32IntInfo = (uint32_t)u64IntInfo;
8199
8200 uint32_t const uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(u32IntInfo);
8201 uint32_t const uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntInfo);
8202
8203#ifdef VBOX_STRICT
8204 /* Validate the error-code-valid bit for hardware exceptions. */
8205 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT)
8206 {
8207 switch (uVector)
8208 {
8209 case X86_XCPT_PF:
8210 case X86_XCPT_DF:
8211 case X86_XCPT_TS:
8212 case X86_XCPT_NP:
8213 case X86_XCPT_SS:
8214 case X86_XCPT_GP:
8215 case X86_XCPT_AC:
8216 AssertMsg(VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(u32IntInfo),
8217 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8218 /* fall thru */
8219 default:
8220 break;
8221 }
8222 }
8223#endif
8224
8225 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8226 Assert( uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
8227 || !(*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS));
8228
8229 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
8230
8231 /* We require CR0 to check if the guest is in real-mode. */
8232 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
8233 AssertRCReturn(rc, rc);
8234
8235 /*
8236 * Hardware interrupts & exceptions cannot be delivered through the software interrupt redirection bitmap to the real
8237 * mode task in virtual-8086 mode. We must jump to the interrupt handler in the (real-mode) guest.
8238 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode" for interrupt & exception classes.
8239 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8240 */
8241 if (CPUMIsGuestInRealModeEx(pMixedCtx))
8242 {
8243 PVM pVM = pVCpu->CTX_SUFF(pVM);
8244 if (!pVM->hm.s.vmx.fUnrestrictedGuest)
8245 {
8246 Assert(PDMVmmDevHeapIsEnabled(pVM));
8247 Assert(pVM->hm.s.vmx.pRealModeTSS);
8248
8249 /* We require RIP, RSP, RFLAGS, CS, IDTR. Save the required ones from the VMCS. */
8250 rc = hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
8251 rc |= hmR0VmxSaveGuestTableRegs(pVCpu, pMixedCtx);
8252 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
8253 AssertRCReturn(rc, rc);
8254 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_RIP));
8255
8256 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8257 size_t const cbIdtEntry = sizeof(X86IDTR16);
8258 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pMixedCtx->idtr.cbIdt)
8259 {
8260 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8261 if (uVector == X86_XCPT_DF)
8262 return VINF_EM_RESET;
8263
8264 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault. */
8265 if (uVector == X86_XCPT_GP)
8266 return hmR0VmxInjectXcptDF(pVCpu, pMixedCtx, fStepping, puIntrState);
8267
8268 /* If we're injecting an interrupt/exception with no valid IDT entry, inject a general-protection fault. */
8269 /* No error codes for exceptions in real-mode. See Intel spec. 20.1.4 "Interrupt and Exception Handling" */
8270 return hmR0VmxInjectXcptGP(pVCpu, pMixedCtx, false /* fErrCodeValid */, 0 /* u32ErrCode */,
8271 fStepping, puIntrState);
8272 }
8273
8274 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8275 uint16_t uGuestIp = pMixedCtx->ip;
8276 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT)
8277 {
8278 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8279 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8280 uGuestIp = pMixedCtx->ip + (uint16_t)cbInstr;
8281 }
8282 else if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT)
8283 uGuestIp = pMixedCtx->ip + (uint16_t)cbInstr;
8284
8285 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8286 X86IDTR16 IdtEntry;
8287 RTGCPHYS GCPhysIdtEntry = (RTGCPHYS)pMixedCtx->idtr.pIdt + uVector * cbIdtEntry;
8288 rc = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8289 AssertRCReturn(rc, rc);
8290
8291 /* Construct the stack frame for the interrupt/exception handler. */
8292 VBOXSTRICTRC rcStrict;
8293 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, pMixedCtx->eflags.u32);
8294 if (rcStrict == VINF_SUCCESS)
8295 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, pMixedCtx->cs.Sel);
8296 if (rcStrict == VINF_SUCCESS)
8297 rcStrict = hmR0VmxRealModeGuestStackPush(pVM, pMixedCtx, uGuestIp);
8298
8299 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8300 if (rcStrict == VINF_SUCCESS)
8301 {
8302 pMixedCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8303 pMixedCtx->rip = IdtEntry.offSel;
8304 pMixedCtx->cs.Sel = IdtEntry.uSel;
8305 pMixedCtx->cs.ValidSel = IdtEntry.uSel;
8306 pMixedCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8307 if ( uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
8308 && uVector == X86_XCPT_PF)
8309 pMixedCtx->cr2 = GCPtrFaultAddress;
8310
8311 /* If any other guest-state bits are changed here, make sure to update
8312 hmR0VmxPreRunGuestCommitted() when thread-context hooks are used. */
8313 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS
8314 | HM_CHANGED_GUEST_RIP
8315 | HM_CHANGED_GUEST_RFLAGS
8316 | HM_CHANGED_GUEST_RSP);
8317
8318 /* We're clearing interrupts, which means no block-by-STI interrupt-inhibition. */
8319 if (*puIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
8320 {
8321 Assert( uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI
8322 && uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
8323 Log4(("Clearing inhibition due to STI.\n"));
8324 *puIntrState &= ~VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
8325 }
8326 Log4(("Injecting real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8327 u32IntInfo, u32ErrCode, cbInstr, pMixedCtx->eflags.u, pMixedCtx->cs.Sel, pMixedCtx->eip));
8328
8329 /* The event has been truly dispatched. Mark it as no longer pending so we don't attempt to 'undo'
8330 it, if we are returning to ring-3 before executing guest code. */
8331 pVCpu->hm.s.Event.fPending = false;
8332
8333 /* Make hmR0VmxPreRunGuest return if we're stepping since we've changed cs:rip. */
8334 if (fStepping)
8335 rcStrict = VINF_EM_DBG_STEPPED;
8336 }
8337 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8338 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8339 return rcStrict;
8340 }
8341
8342 /*
8343 * For unrestricted execution enabled CPUs running real-mode guests, we must not set the deliver-error-code bit.
8344 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8345 */
8346 u32IntInfo &= ~VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
8347 }
8348
8349 /* Validate. */
8350 Assert(VMX_EXIT_INTERRUPTION_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8351 Assert(!VMX_EXIT_INTERRUPTION_INFO_NMI_UNBLOCK_IRET(u32IntInfo)); /* Bit 12 MBZ. */
8352 Assert(!(u32IntInfo & 0x7ffff000)); /* Bits 30:12 MBZ. */
8353
8354 /* Inject. */
8355 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8356 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(u32IntInfo))
8357 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8358 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8359
8360 if ( VMX_EXIT_INTERRUPTION_INFO_TYPE(u32IntInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT
8361 && uVector == X86_XCPT_PF)
8362 pMixedCtx->cr2 = GCPtrFaultAddress;
8363
8364 Log4(("Injecting vcpu[%RU32] u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x pMixedCtx->uCR2=%#RX64\n", pVCpu->idCpu,
8365 u32IntInfo, u32ErrCode, cbInstr, pMixedCtx->cr2));
8366
8367 AssertRCReturn(rc, rc);
8368 return VINF_SUCCESS;
8369}
8370
8371
8372/**
8373 * Clears the interrupt-window exiting control in the VMCS and if necessary
8374 * clears the current event in the VMCS as well.
8375 *
8376 * @returns VBox status code.
8377 * @param pVCpu The cross context virtual CPU structure.
8378 *
8379 * @remarks Use this function only to clear events that have not yet been
8380 * delivered to the guest but are injected in the VMCS!
8381 * @remarks No-long-jump zone!!!
8382 */
8383static void hmR0VmxClearIntNmiWindowsVmcs(PVMCPU pVCpu)
8384{
8385 Log4Func(("vcpu[%d]\n", pVCpu->idCpu));
8386
8387 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT)
8388 hmR0VmxClearIntWindowExitVmcs(pVCpu);
8389
8390 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT)
8391 hmR0VmxClearNmiWindowExitVmcs(pVCpu);
8392}
8393
8394
8395/**
8396 * Enters the VT-x session.
8397 *
8398 * @returns VBox status code.
8399 * @param pVM The cross context VM structure.
8400 * @param pVCpu The cross context virtual CPU structure.
8401 * @param pCpu Pointer to the CPU info struct.
8402 */
8403VMMR0DECL(int) VMXR0Enter(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
8404{
8405 AssertPtr(pVM);
8406 AssertPtr(pVCpu);
8407 Assert(pVM->hm.s.vmx.fSupported);
8408 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8409 NOREF(pCpu); NOREF(pVM);
8410
8411 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8412 Assert(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE));
8413
8414#ifdef VBOX_STRICT
8415 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
8416 RTCCUINTREG uHostCR4 = ASMGetCR4();
8417 if (!(uHostCR4 & X86_CR4_VMXE))
8418 {
8419 LogRel(("VMXR0Enter: X86_CR4_VMXE bit in CR4 is not set!\n"));
8420 return VERR_VMX_X86_CR4_VMXE_CLEARED;
8421 }
8422#endif
8423
8424 /*
8425 * Load the VCPU's VMCS as the current (and active) one.
8426 */
8427 Assert(pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_CLEAR);
8428 int rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
8429 if (RT_FAILURE(rc))
8430 return rc;
8431
8432 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
8433 pVCpu->hm.s.fLeaveDone = false;
8434 Log4Func(("Activated Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8435
8436 return VINF_SUCCESS;
8437}
8438
8439
8440/**
8441 * The thread-context callback (only on platforms which support it).
8442 *
8443 * @param enmEvent The thread-context event.
8444 * @param pVCpu The cross context virtual CPU structure.
8445 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
8446 * @thread EMT(pVCpu)
8447 */
8448VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPU pVCpu, bool fGlobalInit)
8449{
8450 NOREF(fGlobalInit);
8451
8452 switch (enmEvent)
8453 {
8454 case RTTHREADCTXEVENT_OUT:
8455 {
8456 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8457 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8458 VMCPU_ASSERT_EMT(pVCpu);
8459
8460 PCPUMCTX pMixedCtx = CPUMQueryGuestCtxPtr(pVCpu);
8461
8462 /* No longjmps (logger flushes, locks) in this fragile context. */
8463 VMMRZCallRing3Disable(pVCpu);
8464 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
8465
8466 /*
8467 * Restore host-state (FPU, debug etc.)
8468 */
8469 if (!pVCpu->hm.s.fLeaveDone)
8470 {
8471 /* Do -not- save guest-state here as we might already be in the middle of saving it (esp. bad if we are
8472 holding the PGM lock while saving the guest state (see hmR0VmxSaveGuestControlRegs()). */
8473 hmR0VmxLeave(pVCpu, pMixedCtx, false /* fSaveGuestState */);
8474 pVCpu->hm.s.fLeaveDone = true;
8475 }
8476
8477 /* Leave HM context, takes care of local init (term). */
8478 int rc = HMR0LeaveCpu(pVCpu);
8479 AssertRC(rc); NOREF(rc);
8480
8481 /* Restore longjmp state. */
8482 VMMRZCallRing3Enable(pVCpu);
8483 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
8484 break;
8485 }
8486
8487 case RTTHREADCTXEVENT_IN:
8488 {
8489 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8490 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
8491 VMCPU_ASSERT_EMT(pVCpu);
8492
8493 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
8494 VMMRZCallRing3Disable(pVCpu);
8495 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
8496
8497 /* Initialize the bare minimum state required for HM. This takes care of
8498 initializing VT-x if necessary (onlined CPUs, local init etc.) */
8499 int rc = HMR0EnterCpu(pVCpu);
8500 AssertRC(rc);
8501 Assert(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE));
8502
8503 /* Load the active VMCS as the current one. */
8504 if (pVCpu->hm.s.vmx.uVmcsState & HMVMX_VMCS_STATE_CLEAR)
8505 {
8506 rc = VMXActivateVmcs(pVCpu->hm.s.vmx.HCPhysVmcs);
8507 AssertRC(rc); NOREF(rc);
8508 pVCpu->hm.s.vmx.uVmcsState = HMVMX_VMCS_STATE_ACTIVE;
8509 Log4Func(("Resumed: Activated Vmcs. HostCpuId=%u\n", RTMpCpuId()));
8510 }
8511 pVCpu->hm.s.fLeaveDone = false;
8512
8513 /* Restore longjmp state. */
8514 VMMRZCallRing3Enable(pVCpu);
8515 break;
8516 }
8517
8518 default:
8519 break;
8520 }
8521}
8522
8523
8524/**
8525 * Saves the host state in the VMCS host-state.
8526 * Sets up the VM-exit MSR-load area.
8527 *
8528 * The CPU state will be loaded from these fields on every successful VM-exit.
8529 *
8530 * @returns VBox status code.
8531 * @param pVM The cross context VM structure.
8532 * @param pVCpu The cross context virtual CPU structure.
8533 *
8534 * @remarks No-long-jump zone!!!
8535 */
8536static int hmR0VmxSaveHostState(PVM pVM, PVMCPU pVCpu)
8537{
8538 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8539
8540 int rc = VINF_SUCCESS;
8541 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT))
8542 {
8543 rc = hmR0VmxSaveHostControlRegs(pVM, pVCpu);
8544 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostControlRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8545
8546 rc = hmR0VmxSaveHostSegmentRegs(pVM, pVCpu);
8547 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostSegmentRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8548
8549 rc = hmR0VmxSaveHostMsrs(pVM, pVCpu);
8550 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostMsrs failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8551
8552 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_HOST_CONTEXT);
8553 }
8554 return rc;
8555}
8556
8557
8558/**
8559 * Saves the host state in the VMCS host-state.
8560 *
8561 * @returns VBox status code.
8562 * @param pVM The cross context VM structure.
8563 * @param pVCpu The cross context virtual CPU structure.
8564 *
8565 * @remarks No-long-jump zone!!!
8566 */
8567VMMR0DECL(int) VMXR0SaveHostState(PVM pVM, PVMCPU pVCpu)
8568{
8569 AssertPtr(pVM);
8570 AssertPtr(pVCpu);
8571
8572 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8573
8574 /* Save the host state here while entering HM context. When thread-context hooks are used, we might get preempted
8575 and have to resave the host state but most of the time we won't be, so do it here before we disable interrupts. */
8576 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8577 return hmR0VmxSaveHostState(pVM, pVCpu);
8578}
8579
8580
8581/**
8582 * Loads the guest state into the VMCS guest-state area.
8583 *
8584 * The will typically be done before VM-entry when the guest-CPU state and the
8585 * VMCS state may potentially be out of sync.
8586 *
8587 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
8588 * VM-entry controls.
8589 * Sets up the appropriate VMX non-root function to execute guest code based on
8590 * the guest CPU mode.
8591 *
8592 * @returns VBox strict status code.
8593 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8594 * without unrestricted guest access and the VMMDev is not presently
8595 * mapped (e.g. EFI32).
8596 *
8597 * @param pVM The cross context VM structure.
8598 * @param pVCpu The cross context virtual CPU structure.
8599 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8600 * out-of-sync. Make sure to update the required fields
8601 * before using them.
8602 *
8603 * @remarks No-long-jump zone!!!
8604 */
8605static VBOXSTRICTRC hmR0VmxLoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
8606{
8607 AssertPtr(pVM);
8608 AssertPtr(pVCpu);
8609 AssertPtr(pMixedCtx);
8610 HMVMX_ASSERT_PREEMPT_SAFE();
8611
8612 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
8613
8614 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestState, x);
8615
8616 /* Determine real-on-v86 mode. */
8617 pVCpu->hm.s.vmx.RealMode.fRealOnV86Active = false;
8618 if ( !pVM->hm.s.vmx.fUnrestrictedGuest
8619 && CPUMIsGuestInRealModeEx(pMixedCtx))
8620 {
8621 pVCpu->hm.s.vmx.RealMode.fRealOnV86Active = true;
8622 }
8623
8624 /*
8625 * Load the guest-state into the VMCS.
8626 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
8627 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
8628 */
8629 int rc = hmR0VmxSetupVMRunHandler(pVCpu, pMixedCtx);
8630 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupVMRunHandler! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8631
8632 /* This needs to be done after hmR0VmxSetupVMRunHandler() as changing pfnStartVM may require VM-entry control updates. */
8633 rc = hmR0VmxLoadGuestEntryCtls(pVCpu, pMixedCtx);
8634 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestEntryCtls! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8635
8636 /* This needs to be done after hmR0VmxSetupVMRunHandler() as changing pfnStartVM may require VM-exit control updates. */
8637 rc = hmR0VmxLoadGuestExitCtls(pVCpu, pMixedCtx);
8638 AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupExitCtls failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8639
8640 rc = hmR0VmxLoadGuestActivityState(pVCpu, pMixedCtx);
8641 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestActivityState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8642
8643 VBOXSTRICTRC rcStrict = hmR0VmxLoadGuestCR3AndCR4(pVCpu, pMixedCtx);
8644 if (rcStrict == VINF_SUCCESS)
8645 { /* likely */ }
8646 else
8647 {
8648 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
8649 return rcStrict;
8650 }
8651
8652 /* Assumes pMixedCtx->cr0 is up-to-date (strict builds require CR0 for segment register validation checks). */
8653 rc = hmR0VmxLoadGuestSegmentRegs(pVCpu, pMixedCtx);
8654 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestSegmentRegs: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8655
8656 /* This needs to be done after hmR0VmxLoadGuestEntryCtls() and hmR0VmxLoadGuestExitCtls() as it may alter controls if we
8657 determine we don't have to swap EFER after all. */
8658 rc = hmR0VmxLoadGuestMsrs(pVCpu, pMixedCtx);
8659 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestMsrs! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8660
8661 rc = hmR0VmxLoadGuestApicState(pVCpu, pMixedCtx);
8662 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestApicState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8663
8664 rc = hmR0VmxLoadGuestXcptIntercepts(pVCpu, pMixedCtx);
8665 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestXcptIntercepts! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8666
8667 /*
8668 * Loading Rflags here is fine, even though Rflags.TF might depend on guest debug state (which is not loaded here).
8669 * It is re-evaluated and updated if necessary in hmR0VmxLoadSharedState().
8670 */
8671 rc = hmR0VmxLoadGuestRipRspRflags(pVCpu, pMixedCtx);
8672 AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestRipRspRflags! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
8673
8674 /* Clear any unused and reserved bits. */
8675 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR2);
8676
8677 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
8678 return rc;
8679}
8680
8681
8682/**
8683 * Loads the state shared between the host and guest into the VMCS.
8684 *
8685 * @param pVM The cross context VM structure.
8686 * @param pVCpu The cross context virtual CPU structure.
8687 * @param pCtx Pointer to the guest-CPU context.
8688 *
8689 * @remarks No-long-jump zone!!!
8690 */
8691static void hmR0VmxLoadSharedState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
8692{
8693 NOREF(pVM);
8694
8695 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8696 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8697
8698 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
8699 {
8700 int rc = hmR0VmxLoadSharedCR0(pVCpu, pCtx);
8701 AssertRC(rc);
8702 }
8703
8704 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_DEBUG))
8705 {
8706 int rc = hmR0VmxLoadSharedDebugState(pVCpu, pCtx);
8707 AssertRC(rc);
8708
8709 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
8710 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_RFLAGS))
8711 {
8712 rc = hmR0VmxLoadGuestRflags(pVCpu, pCtx);
8713 AssertRC(rc);
8714 }
8715 }
8716
8717 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS))
8718 {
8719 hmR0VmxLazyLoadGuestMsrs(pVCpu, pCtx);
8720 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS);
8721 }
8722
8723 /* Loading CR0, debug state might have changed intercepts, update VMCS. */
8724 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
8725 {
8726 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_AC));
8727 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
8728 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
8729 AssertRC(rc);
8730 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
8731 }
8732
8733 AssertMsg(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE),
8734 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8735}
8736
8737
8738/**
8739 * Worker for loading the guest-state bits in the inner VT-x execution loop.
8740 *
8741 * @returns Strict VBox status code (i.e. informational status codes too).
8742 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
8743 * without unrestricted guest access and the VMMDev is not presently
8744 * mapped (e.g. EFI32).
8745 *
8746 * @param pVM The cross context VM structure.
8747 * @param pVCpu The cross context virtual CPU structure.
8748 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8749 * out-of-sync. Make sure to update the required fields
8750 * before using them.
8751 *
8752 * @remarks No-long-jump zone!!!
8753 */
8754static VBOXSTRICTRC hmR0VmxLoadGuestStateOptimal(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx)
8755{
8756 HMVMX_ASSERT_PREEMPT_SAFE();
8757 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8758 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8759
8760 Log5(("LoadFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8761#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
8762 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
8763#endif
8764
8765 /*
8766 * RIP is what changes the most often and hence if it's the only bit needing to be
8767 * updated, we shall handle it early for performance reasons.
8768 */
8769 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
8770 if (HMCPU_CF_IS_SET_ONLY(pVCpu, HM_CHANGED_GUEST_RIP))
8771 {
8772 rcStrict = hmR0VmxLoadGuestRip(pVCpu, pMixedCtx);
8773 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8774 { /* likely */}
8775 else
8776 {
8777 AssertMsgFailedReturn(("hmR0VmxLoadGuestStateOptimal: hmR0VmxLoadGuestRip failed! rc=%Rrc\n",
8778 VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
8779 }
8780 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadMinimal);
8781 }
8782 else if (HMCPU_CF_VALUE(pVCpu))
8783 {
8784 rcStrict = hmR0VmxLoadGuestState(pVM, pVCpu, pMixedCtx);
8785 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8786 { /* likely */}
8787 else
8788 {
8789 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM,
8790 ("hmR0VmxLoadGuestStateOptimal: hmR0VmxLoadGuestState failed! rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8791 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8792 return rcStrict;
8793 }
8794 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadFull);
8795 }
8796
8797 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
8798 AssertMsg( !HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_ALL_GUEST)
8799 || HMCPU_CF_IS_PENDING_ONLY(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE),
8800 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
8801 return rcStrict;
8802}
8803
8804
8805/**
8806 * Does the preparations before executing guest code in VT-x.
8807 *
8808 * This may cause longjmps to ring-3 and may even result in rescheduling to the
8809 * recompiler/IEM. We must be cautious what we do here regarding committing
8810 * guest-state information into the VMCS assuming we assuredly execute the
8811 * guest in VT-x mode.
8812 *
8813 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
8814 * the common-state (TRPM/forceflags), we must undo those changes so that the
8815 * recompiler/IEM can (and should) use them when it resumes guest execution.
8816 * Otherwise such operations must be done when we can no longer exit to ring-3.
8817 *
8818 * @returns Strict VBox status code (i.e. informational status codes too).
8819 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
8820 * have been disabled.
8821 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
8822 * double-fault into the guest.
8823 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
8824 * dispatched directly.
8825 * @retval VINF_* scheduling changes, we have to go back to ring-3.
8826 *
8827 * @param pVM The cross context VM structure.
8828 * @param pVCpu The cross context virtual CPU structure.
8829 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8830 * out-of-sync. Make sure to update the required fields
8831 * before using them.
8832 * @param pVmxTransient Pointer to the VMX transient structure.
8833 * @param fStepping Set if called from hmR0VmxRunGuestCodeStep(). Makes
8834 * us ignore some of the reasons for returning to
8835 * ring-3, and return VINF_EM_DBG_STEPPED if event
8836 * dispatching took place.
8837 */
8838static VBOXSTRICTRC hmR0VmxPreRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, bool fStepping)
8839{
8840 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8841
8842#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
8843 PGMRZDynMapFlushAutoSet(pVCpu);
8844#endif
8845
8846 /* Check force flag actions that might require us to go back to ring-3. */
8847 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVM, pVCpu, pMixedCtx, fStepping);
8848 if (rcStrict == VINF_SUCCESS)
8849 { /* FFs doesn't get set all the time. */ }
8850 else
8851 return rcStrict;
8852
8853#ifndef IEM_VERIFICATION_MODE_FULL
8854 /*
8855 * Setup the virtualized-APIC accesses.
8856 *
8857 * Note! This can cause a longjumps to R3 due to the acquisition of the PGM lock
8858 * in both PGMHandlerPhysicalReset() and IOMMMIOMapMMIOHCPage(), see @bugref{8721}.
8859 *
8860 * This is the reason we do it here and not in hmR0VmxLoadGuestState().
8861 */
8862 if ( !pVCpu->hm.s.vmx.u64MsrApicBase
8863 && (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC)
8864 && PDMHasApic(pVM))
8865 {
8866 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
8867 Assert(u64MsrApicBase);
8868 Assert(pVM->hm.s.vmx.HCPhysApicAccess);
8869
8870 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
8871
8872 /* Unalias any existing mapping. */
8873 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
8874 AssertRCReturn(rc, rc);
8875
8876 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
8877 Log4(("hmR0VmxPreRunGuest: VCPU%u: Mapped HC APIC-access page at %#RGp\n", pVCpu->idCpu, GCPhysApicBase));
8878 rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
8879 AssertRCReturn(rc, rc);
8880
8881 /* Update the per-VCPU cache of the APIC base MSR. */
8882 pVCpu->hm.s.vmx.u64MsrApicBase = u64MsrApicBase;
8883 }
8884#endif /* !IEM_VERIFICATION_MODE_FULL */
8885
8886 if (TRPMHasTrap(pVCpu))
8887 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
8888 uint32_t uIntrState = hmR0VmxEvaluatePendingEvent(pVCpu, pMixedCtx);
8889
8890 /*
8891 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus needs to be done with
8892 * longjmps or interrupts + preemption enabled. Event injection might also result in triple-faulting the VM.
8893 */
8894 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx, uIntrState, fStepping);
8895 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8896 { /* likely */ }
8897 else
8898 {
8899 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8900 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8901 return rcStrict;
8902 }
8903
8904 /*
8905 * No longjmps to ring-3 from this point on!!!
8906 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
8907 * This also disables flushing of the R0-logger instance (if any).
8908 */
8909 VMMRZCallRing3Disable(pVCpu);
8910
8911 /*
8912 * Load the guest state bits.
8913 *
8914 * We cannot perform longjmps while loading the guest state because we do not preserve the
8915 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
8916 * CPU migration.
8917 *
8918 * If we are injecting events to a real-on-v86 mode guest, we will have to update
8919 * RIP and some segment registers, i.e. hmR0VmxInjectPendingEvent()->hmR0VmxInjectEventVmcs().
8920 * Hence, loading of the guest state needs to be done -after- injection of events.
8921 */
8922 rcStrict = hmR0VmxLoadGuestStateOptimal(pVM, pVCpu, pMixedCtx);
8923 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
8924 { /* likely */ }
8925 else
8926 {
8927 VMMRZCallRing3Enable(pVCpu);
8928 return rcStrict;
8929 }
8930
8931 /*
8932 * We disable interrupts so that we don't miss any interrupts that would flag preemption (IPI/timers etc.)
8933 * when thread-context hooks aren't used and we've been running with preemption disabled for a while.
8934 *
8935 * We need to check for force-flags that could've possible been altered since we last checked them (e.g.
8936 * by PDMGetInterrupt() leaving the PDM critical section, see @bugref{6398}).
8937 *
8938 * We also check a couple of other force-flags as a last opportunity to get the EMT back to ring-3 before
8939 * executing guest code.
8940 */
8941 pVmxTransient->fEFlags = ASMIntDisableFlags();
8942
8943 if ( ( !VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
8944 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
8945 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
8946 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
8947 {
8948 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
8949 {
8950 pVCpu->hm.s.Event.fPending = false;
8951
8952 /*
8953 * We've injected any pending events. This is really the point of no return (to ring-3).
8954 *
8955 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
8956 * returns from this function, so don't enable them here.
8957 */
8958 return VINF_SUCCESS;
8959 }
8960
8961 STAM_COUNTER_INC(&pVCpu->hm.s.StatPendingHostIrq);
8962 rcStrict = VINF_EM_RAW_INTERRUPT;
8963 }
8964 else
8965 {
8966 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
8967 rcStrict = VINF_EM_RAW_TO_R3;
8968 }
8969
8970 ASMSetFlags(pVmxTransient->fEFlags);
8971 VMMRZCallRing3Enable(pVCpu);
8972
8973 return rcStrict;
8974}
8975
8976
8977/**
8978 * Prepares to run guest code in VT-x and we've committed to doing so. This
8979 * means there is no backing out to ring-3 or anywhere else at this
8980 * point.
8981 *
8982 * @param pVM The cross context VM structure.
8983 * @param pVCpu The cross context virtual CPU structure.
8984 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
8985 * out-of-sync. Make sure to update the required fields
8986 * before using them.
8987 * @param pVmxTransient Pointer to the VMX transient structure.
8988 *
8989 * @remarks Called with preemption disabled.
8990 * @remarks No-long-jump zone!!!
8991 */
8992static void hmR0VmxPreRunGuestCommitted(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
8993{
8994 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8995 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8996 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8997
8998 /*
8999 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
9000 */
9001 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
9002 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
9003
9004#ifdef HMVMX_ALWAYS_SWAP_FPU_STATE
9005 if (!CPUMIsGuestFPUStateActive(pVCpu))
9006 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
9007 HMCPU_CF_SET(pVCpu, HM_CHANGED_HOST_CONTEXT);
9008 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9009#endif
9010
9011 if ( pVCpu->hm.s.fPreloadGuestFpu
9012 && !CPUMIsGuestFPUStateActive(pVCpu))
9013 {
9014 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
9015 HMCPU_CF_SET(pVCpu, HM_CHANGED_HOST_CONTEXT);
9016 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_CR0));
9017 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9018 }
9019
9020 /*
9021 * Lazy-update of the host MSRs values in the auto-load/store MSR area.
9022 */
9023 if ( !pVCpu->hm.s.vmx.fUpdatedHostMsrs
9024 && pVCpu->hm.s.vmx.cMsrs > 0)
9025 {
9026 hmR0VmxUpdateAutoLoadStoreHostMsrs(pVCpu);
9027 }
9028
9029 /*
9030 * Load the host state bits as we may've been preempted (only happens when
9031 * thread-context hooks are used or when hmR0VmxSetupVMRunHandler() changes pfnStartVM).
9032 * Note that the 64-on-32 switcher saves the (64-bit) host state into the VMCS and
9033 * if we change the switcher back to 32-bit, we *must* save the 32-bit host state here.
9034 * See @bugref{8432}.
9035 */
9036 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT))
9037 {
9038 int rc = hmR0VmxSaveHostState(pVM, pVCpu);
9039 AssertRC(rc);
9040 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreemptSaveHostState);
9041 }
9042 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_CONTEXT));
9043
9044 /*
9045 * Load the state shared between host and guest (FPU, debug, lazy MSRs).
9046 */
9047 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE))
9048 hmR0VmxLoadSharedState(pVM, pVCpu, pMixedCtx);
9049 AssertMsg(!HMCPU_CF_VALUE(pVCpu), ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
9050
9051 /* Store status of the shared guest-host state at the time of VM-entry. */
9052#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
9053 if (CPUMIsGuestInLongModeEx(pMixedCtx))
9054 {
9055 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActivePending(pVCpu);
9056 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActivePending(pVCpu);
9057 }
9058 else
9059#endif
9060 {
9061 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
9062 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
9063 }
9064 pVmxTransient->fWasGuestFPUStateActive = CPUMIsGuestFPUStateActive(pVCpu);
9065
9066 /*
9067 * Cache the TPR-shadow for checking on every VM-exit if it might have changed.
9068 */
9069 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
9070 pVmxTransient->u8GuestTpr = pVCpu->hm.s.vmx.pbVirtApic[XAPIC_OFF_TPR];
9071
9072 PHMGLOBALCPUINFO pCpu = hmR0GetCurrentCpu();
9073 RTCPUID idCurrentCpu = pCpu->idCpu;
9074 if ( pVmxTransient->fUpdateTscOffsettingAndPreemptTimer
9075 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
9076 {
9077 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVM, pVCpu);
9078 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = false;
9079 }
9080
9081 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
9082 hmR0VmxFlushTaggedTlb(pVCpu, pCpu); /* Invalidate the appropriate guest entries from the TLB. */
9083 Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
9084 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Update the error reporting info. with the current host CPU. */
9085
9086 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
9087
9088 TMNotifyStartOfExecution(pVCpu); /* Finally, notify TM to resume its clocks as we're about
9089 to start executing. */
9090
9091 /*
9092 * Load the TSC_AUX MSR when we are not intercepting RDTSCP.
9093 */
9094 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP)
9095 {
9096 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
9097 {
9098 bool fMsrUpdated;
9099 int rc2 = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
9100 AssertRC(rc2);
9101 Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS));
9102
9103 rc2 = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_TSC_AUX, CPUMR0GetGuestTscAux(pVCpu), true /* fUpdateHostMsr */,
9104 &fMsrUpdated);
9105 AssertRC(rc2);
9106 Assert(fMsrUpdated || pVCpu->hm.s.vmx.fUpdatedHostMsrs);
9107
9108 /* Finally, mark that all host MSR values are updated so we don't redo it without leaving VT-x. See @bugref{6956}. */
9109 pVCpu->hm.s.vmx.fUpdatedHostMsrs = true;
9110 }
9111 else
9112 {
9113 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, MSR_K8_TSC_AUX);
9114 Assert(!pVCpu->hm.s.vmx.cMsrs || pVCpu->hm.s.vmx.fUpdatedHostMsrs);
9115 }
9116 }
9117
9118#ifdef VBOX_STRICT
9119 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu);
9120 hmR0VmxCheckHostEferMsr(pVCpu);
9121 AssertRC(hmR0VmxCheckVmcsCtls(pVCpu));
9122#endif
9123#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
9124 uint32_t uInvalidReason = hmR0VmxCheckGuestState(pVM, pVCpu, pMixedCtx);
9125 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
9126 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
9127#endif
9128}
9129
9130
9131/**
9132 * Performs some essential restoration of state after running guest code in
9133 * VT-x.
9134 *
9135 * @param pVM The cross context VM structure.
9136 * @param pVCpu The cross context virtual CPU structure.
9137 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
9138 * out-of-sync. Make sure to update the required fields
9139 * before using them.
9140 * @param pVmxTransient Pointer to the VMX transient structure.
9141 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
9142 *
9143 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
9144 *
9145 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
9146 * unconditionally when it is safe to do so.
9147 */
9148static void hmR0VmxPostRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, int rcVMRun)
9149{
9150 NOREF(pVM);
9151
9152 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9153
9154 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
9155 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
9156 HMVMXCPU_GST_RESET_TO(pVCpu, 0); /* Exits/longjmps to ring-3 requires saving the guest state. */
9157 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
9158 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
9159 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
9160
9161 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
9162 TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVCpu->hm.s.vmx.u64TSCOffset);
9163
9164 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatExit1, x);
9165 TMNotifyEndOfExecution(pVCpu); /* Notify TM that the guest is no longer running. */
9166 Assert(!ASMIntAreEnabled());
9167 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
9168
9169#ifdef HMVMX_ALWAYS_SWAP_FPU_STATE
9170 if (CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVM, pVCpu))
9171 {
9172 hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
9173 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9174 }
9175#endif
9176
9177#if HC_ARCH_BITS == 64
9178 pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Host state messed up by VT-x, we must restore. */
9179#endif
9180#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
9181 /* The 64-on-32 switcher maintains uVmcsState on its own and we need to leave it alone here. */
9182 if (pVCpu->hm.s.vmx.pfnStartVM != VMXR0SwitcherStartVM64)
9183 pVCpu->hm.s.vmx.uVmcsState |= HMVMX_VMCS_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
9184#else
9185 pVCpu->hm.s.vmx.uVmcsState |= HMVMX_VMCS_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
9186#endif
9187#ifdef VBOX_STRICT
9188 hmR0VmxCheckHostEferMsr(pVCpu); /* Verify that VMRUN/VMLAUNCH didn't modify host EFER. */
9189#endif
9190 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
9191 VMMRZCallRing3Enable(pVCpu); /* It is now safe to do longjmps to ring-3!!! */
9192
9193 /* Save the basic VM-exit reason. Refer Intel spec. 24.9.1 "Basic VM-exit Information". */
9194 uint32_t uExitReason;
9195 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
9196 rc |= hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
9197 AssertRC(rc);
9198 pVmxTransient->uExitReason = (uint16_t)VMX_EXIT_REASON_BASIC(uExitReason);
9199 pVmxTransient->fVMEntryFailed = VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uEntryIntInfo);
9200
9201 /* If the VMLAUNCH/VMRESUME failed, we can bail out early. This does -not- cover VMX_EXIT_ERR_*. */
9202 if (RT_UNLIKELY(rcVMRun != VINF_SUCCESS))
9203 {
9204 Log4(("VM-entry failure: pVCpu=%p idCpu=%RU32 rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", pVCpu, pVCpu->idCpu, rcVMRun,
9205 pVmxTransient->fVMEntryFailed));
9206 return;
9207 }
9208
9209 /*
9210 * Update the VM-exit history array here even if the VM-entry failed due to:
9211 * - Invalid guest state.
9212 * - MSR loading.
9213 * - Machine-check event.
9214 *
9215 * In any of the above cases we will still have a "valid" VM-exit reason
9216 * despite @a fVMEntryFailed being false.
9217 *
9218 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
9219 */
9220 HMCPU_EXIT_HISTORY_ADD(pVCpu, pVmxTransient->uExitReason);
9221
9222 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
9223 {
9224 /** @todo We can optimize this by only syncing with our force-flags when
9225 * really needed and keeping the VMCS state as it is for most
9226 * VM-exits. */
9227 /* Update the guest interruptibility-state from the VMCS. */
9228 hmR0VmxSaveGuestIntrState(pVCpu, pMixedCtx);
9229
9230#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
9231 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
9232 AssertRC(rc);
9233#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
9234 rc = hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
9235 AssertRC(rc);
9236#endif
9237
9238 /*
9239 * Sync the TPR shadow with our APIC state.
9240 */
9241 if ( (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
9242 && pVmxTransient->u8GuestTpr != pVCpu->hm.s.vmx.pbVirtApic[XAPIC_OFF_TPR])
9243 {
9244 rc = APICSetTpr(pVCpu, pVCpu->hm.s.vmx.pbVirtApic[XAPIC_OFF_TPR]);
9245 AssertRC(rc);
9246 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
9247 }
9248 }
9249}
9250
9251
9252/**
9253 * Runs the guest code using VT-x the normal way.
9254 *
9255 * @returns VBox status code.
9256 * @param pVM The cross context VM structure.
9257 * @param pVCpu The cross context virtual CPU structure.
9258 * @param pCtx Pointer to the guest-CPU context.
9259 *
9260 * @note Mostly the same as hmR0VmxRunGuestCodeStep().
9261 */
9262static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
9263{
9264 VMXTRANSIENT VmxTransient;
9265 VmxTransient.fUpdateTscOffsettingAndPreemptTimer = true;
9266 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
9267 uint32_t cLoops = 0;
9268
9269 for (;; cLoops++)
9270 {
9271 Assert(!HMR0SuspendPending());
9272 HMVMX_ASSERT_CPU_SAFE();
9273
9274 /* Preparatory work for running guest code, this may force us to return
9275 to ring-3. This bugger disables interrupts on VINF_SUCCESS! */
9276 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
9277 rcStrict = hmR0VmxPreRunGuest(pVM, pVCpu, pCtx, &VmxTransient, false /* fStepping */);
9278 if (rcStrict != VINF_SUCCESS)
9279 break;
9280
9281 hmR0VmxPreRunGuestCommitted(pVM, pVCpu, pCtx, &VmxTransient);
9282 int rcRun = hmR0VmxRunGuest(pVM, pVCpu, pCtx);
9283 /* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
9284
9285 /* Restore any residual host-state and save any bits shared between host
9286 and guest into the guest-CPU state. Re-enables interrupts! */
9287 hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, rcRun);
9288
9289 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
9290 if (RT_SUCCESS(rcRun))
9291 { /* very likely */ }
9292 else
9293 {
9294 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
9295 hmR0VmxReportWorldSwitchError(pVM, pVCpu, rcRun, pCtx, &VmxTransient);
9296 return rcRun;
9297 }
9298
9299 /* Profile the VM-exit. */
9300 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
9301 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
9302 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
9303 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
9304 HMVMX_START_EXIT_DISPATCH_PROF();
9305
9306 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, pCtx, VmxTransient.uExitReason);
9307
9308 /* Handle the VM-exit. */
9309#ifdef HMVMX_USE_FUNCTION_TABLE
9310 rcStrict = g_apfnVMExitHandlers[VmxTransient.uExitReason](pVCpu, pCtx, &VmxTransient);
9311#else
9312 rcStrict = hmR0VmxHandleExit(pVCpu, pCtx, &VmxTransient, VmxTransient.uExitReason);
9313#endif
9314 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
9315 if (rcStrict == VINF_SUCCESS)
9316 {
9317 if (cLoops <= pVM->hm.s.cMaxResumeLoops)
9318 continue; /* likely */
9319 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
9320 rcStrict = VINF_EM_RAW_INTERRUPT;
9321 }
9322 break;
9323 }
9324
9325 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
9326 return rcStrict;
9327}
9328
9329
9330
9331/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
9332 * probes.
9333 *
9334 * The following few functions and associated structure contains the bloat
9335 * necessary for providing detailed debug events and dtrace probes as well as
9336 * reliable host side single stepping. This works on the principle of
9337 * "subclassing" the normal execution loop and workers. We replace the loop
9338 * method completely and override selected helpers to add necessary adjustments
9339 * to their core operation.
9340 *
9341 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
9342 * any performance for debug and analysis features.
9343 *
9344 * @{
9345 */
9346
9347/**
9348 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
9349 * the debug run loop.
9350 */
9351typedef struct VMXRUNDBGSTATE
9352{
9353 /** The RIP we started executing at. This is for detecting that we stepped. */
9354 uint64_t uRipStart;
9355 /** The CS we started executing with. */
9356 uint16_t uCsStart;
9357
9358 /** Whether we've actually modified the 1st execution control field. */
9359 bool fModifiedProcCtls : 1;
9360 /** Whether we've actually modified the 2nd execution control field. */
9361 bool fModifiedProcCtls2 : 1;
9362 /** Whether we've actually modified the exception bitmap. */
9363 bool fModifiedXcptBitmap : 1;
9364
9365 /** We desire the modified the CR0 mask to be cleared. */
9366 bool fClearCr0Mask : 1;
9367 /** We desire the modified the CR4 mask to be cleared. */
9368 bool fClearCr4Mask : 1;
9369 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
9370 uint32_t fCpe1Extra;
9371 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
9372 uint32_t fCpe1Unwanted;
9373 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
9374 uint32_t fCpe2Extra;
9375 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
9376 uint32_t bmXcptExtra;
9377 /** The sequence number of the Dtrace provider settings the state was
9378 * configured against. */
9379 uint32_t uDtraceSettingsSeqNo;
9380 /** VM-exits to check (one bit per VM-exit). */
9381 uint32_t bmExitsToCheck[3];
9382
9383 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
9384 uint32_t fProcCtlsInitial;
9385 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
9386 uint32_t fProcCtls2Initial;
9387 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
9388 uint32_t bmXcptInitial;
9389} VMXRUNDBGSTATE;
9390AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
9391typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
9392
9393
9394/**
9395 * Initializes the VMXRUNDBGSTATE structure.
9396 *
9397 * @param pVCpu The cross context virtual CPU structure of the
9398 * calling EMT.
9399 * @param pCtx The CPU register context to go with @a pVCpu.
9400 * @param pDbgState The structure to initialize.
9401 */
9402DECLINLINE(void) hmR0VmxRunDebugStateInit(PVMCPU pVCpu, PCCPUMCTX pCtx, PVMXRUNDBGSTATE pDbgState)
9403{
9404 pDbgState->uRipStart = pCtx->rip;
9405 pDbgState->uCsStart = pCtx->cs.Sel;
9406
9407 pDbgState->fModifiedProcCtls = false;
9408 pDbgState->fModifiedProcCtls2 = false;
9409 pDbgState->fModifiedXcptBitmap = false;
9410 pDbgState->fClearCr0Mask = false;
9411 pDbgState->fClearCr4Mask = false;
9412 pDbgState->fCpe1Extra = 0;
9413 pDbgState->fCpe1Unwanted = 0;
9414 pDbgState->fCpe2Extra = 0;
9415 pDbgState->bmXcptExtra = 0;
9416 pDbgState->fProcCtlsInitial = pVCpu->hm.s.vmx.u32ProcCtls;
9417 pDbgState->fProcCtls2Initial = pVCpu->hm.s.vmx.u32ProcCtls2;
9418 pDbgState->bmXcptInitial = pVCpu->hm.s.vmx.u32XcptBitmap;
9419}
9420
9421
9422/**
9423 * Updates the VMSC fields with changes requested by @a pDbgState.
9424 *
9425 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
9426 * immediately before executing guest code, i.e. when interrupts are disabled.
9427 * We don't check status codes here as we cannot easily assert or return in the
9428 * latter case.
9429 *
9430 * @param pVCpu The cross context virtual CPU structure.
9431 * @param pDbgState The debug state.
9432 */
9433DECLINLINE(void) hmR0VmxPreRunGuestDebugStateApply(PVMCPU pVCpu, PVMXRUNDBGSTATE pDbgState)
9434{
9435 /*
9436 * Ensure desired flags in VMCS control fields are set.
9437 * (Ignoring write failure here, as we're committed and it's just debug extras.)
9438 *
9439 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
9440 * there should be no stale data in pCtx at this point.
9441 */
9442 if ( (pVCpu->hm.s.vmx.u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
9443 || (pVCpu->hm.s.vmx.u32ProcCtls & pDbgState->fCpe1Unwanted))
9444 {
9445 pVCpu->hm.s.vmx.u32ProcCtls |= pDbgState->fCpe1Extra;
9446 pVCpu->hm.s.vmx.u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
9447 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
9448 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVCpu->hm.s.vmx.u32ProcCtls));
9449 pDbgState->fModifiedProcCtls = true;
9450 }
9451
9452 if ((pVCpu->hm.s.vmx.u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
9453 {
9454 pVCpu->hm.s.vmx.u32ProcCtls2 |= pDbgState->fCpe2Extra;
9455 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVCpu->hm.s.vmx.u32ProcCtls2);
9456 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVCpu->hm.s.vmx.u32ProcCtls2));
9457 pDbgState->fModifiedProcCtls2 = true;
9458 }
9459
9460 if ((pVCpu->hm.s.vmx.u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
9461 {
9462 pVCpu->hm.s.vmx.u32XcptBitmap |= pDbgState->bmXcptExtra;
9463 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVCpu->hm.s.vmx.u32XcptBitmap);
9464 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVCpu->hm.s.vmx.u32XcptBitmap));
9465 pDbgState->fModifiedXcptBitmap = true;
9466 }
9467
9468 if (pDbgState->fClearCr0Mask && pVCpu->hm.s.vmx.u32CR0Mask != 0)
9469 {
9470 pVCpu->hm.s.vmx.u32CR0Mask = 0;
9471 VMXWriteVmcs32(VMX_VMCS_CTRL_CR0_MASK, 0);
9472 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS_CTRL_CR0_MASK: 0\n"));
9473 }
9474
9475 if (pDbgState->fClearCr4Mask && pVCpu->hm.s.vmx.u32CR4Mask != 0)
9476 {
9477 pVCpu->hm.s.vmx.u32CR4Mask = 0;
9478 VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_MASK, 0);
9479 Log6(("hmR0VmxRunDebugStateRevert: VMX_VMCS_CTRL_CR4_MASK: 0\n"));
9480 }
9481}
9482
9483
9484DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugStateRevert(PVMCPU pVCpu, PVMXRUNDBGSTATE pDbgState, VBOXSTRICTRC rcStrict)
9485{
9486 /*
9487 * Restore VM-exit control settings as we may not reenter this function the
9488 * next time around.
9489 */
9490 /* We reload the initial value, trigger what we can of recalculations the
9491 next time around. From the looks of things, that's all that's required atm. */
9492 if (pDbgState->fModifiedProcCtls)
9493 {
9494 if (!(pDbgState->fProcCtlsInitial & VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
9495 pDbgState->fProcCtlsInitial |= VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
9496 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
9497 AssertRCReturn(rc2, rc2);
9498 pVCpu->hm.s.vmx.u32ProcCtls = pDbgState->fProcCtlsInitial;
9499 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0 | HM_CHANGED_GUEST_DEBUG);
9500 }
9501
9502 /* We're currently the only ones messing with this one, so just restore the
9503 cached value and reload the field. */
9504 if ( pDbgState->fModifiedProcCtls2
9505 && pVCpu->hm.s.vmx.u32ProcCtls2 != pDbgState->fProcCtls2Initial)
9506 {
9507 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
9508 AssertRCReturn(rc2, rc2);
9509 pVCpu->hm.s.vmx.u32ProcCtls2 = pDbgState->fProcCtls2Initial;
9510 }
9511
9512 /* If we've modified the exception bitmap, we restore it and trigger
9513 reloading and partial recalculation the next time around. */
9514 if (pDbgState->fModifiedXcptBitmap)
9515 {
9516 pVCpu->hm.s.vmx.u32XcptBitmap = pDbgState->bmXcptInitial;
9517 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS | HM_CHANGED_GUEST_CR0);
9518 }
9519
9520 /* We assume hmR0VmxLoadSharedCR0 will recalculate and load the CR0 mask. */
9521 if (pDbgState->fClearCr0Mask)
9522 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9523
9524 /* We assume hmR0VmxLoadGuestCR3AndCR4 will recalculate and load the CR4 mask. */
9525 if (pDbgState->fClearCr4Mask)
9526 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
9527
9528 return rcStrict;
9529}
9530
9531
9532/**
9533 * Configures VM-exit controls for current DBGF and DTrace settings.
9534 *
9535 * This updates @a pDbgState and the VMCS execution control fields to reflect
9536 * the necessary VM-exits demanded by DBGF and DTrace.
9537 *
9538 * @param pVM The cross context VM structure.
9539 * @param pVCpu The cross context virtual CPU structure.
9540 * @param pCtx Pointer to the guest-CPU context.
9541 * @param pDbgState The debug state.
9542 * @param pVmxTransient Pointer to the VMX transient structure. May update
9543 * fUpdateTscOffsettingAndPreemptTimer.
9544 */
9545static void hmR0VmxPreRunGuestDebugStateUpdate(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx,
9546 PVMXRUNDBGSTATE pDbgState, PVMXTRANSIENT pVmxTransient)
9547{
9548 /*
9549 * Take down the dtrace serial number so we can spot changes.
9550 */
9551 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
9552 ASMCompilerBarrier();
9553
9554 /*
9555 * We'll rebuild most of the middle block of data members (holding the
9556 * current settings) as we go along here, so start by clearing it all.
9557 */
9558 pDbgState->bmXcptExtra = 0;
9559 pDbgState->fCpe1Extra = 0;
9560 pDbgState->fCpe1Unwanted = 0;
9561 pDbgState->fCpe2Extra = 0;
9562 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
9563 pDbgState->bmExitsToCheck[i] = 0;
9564
9565 /*
9566 * Software interrupts (INT XXh) - no idea how to trigger these...
9567 */
9568 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
9569 || VBOXVMM_INT_SOFTWARE_ENABLED())
9570 {
9571 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
9572 }
9573
9574 /*
9575 * INT3 breakpoints - triggered by #BP exceptions.
9576 */
9577 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
9578 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
9579
9580 /*
9581 * Exception bitmap and XCPT events+probes.
9582 */
9583 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
9584 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
9585 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
9586
9587 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
9588 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
9589 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
9590 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
9591 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
9592 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
9593 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
9594 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
9595 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
9596 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
9597 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
9598 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
9599 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
9600 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
9601 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
9602 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
9603 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
9604 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
9605
9606 if (pDbgState->bmXcptExtra)
9607 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
9608
9609 /*
9610 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
9611 *
9612 * Note! This is the reverse of waft hmR0VmxHandleExitDtraceEvents does.
9613 * So, when adding/changing/removing please don't forget to update it.
9614 *
9615 * Some of the macros are picking up local variables to save horizontal space,
9616 * (being able to see it in a table is the lesser evil here).
9617 */
9618#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
9619 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
9620 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
9621#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
9622 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9623 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9624 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9625 } else do { } while (0)
9626#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
9627 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9628 { \
9629 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
9630 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9631 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9632 } else do { } while (0)
9633#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
9634 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9635 { \
9636 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
9637 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9638 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9639 } else do { } while (0)
9640#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
9641 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
9642 { \
9643 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
9644 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
9645 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
9646 } else do { } while (0)
9647
9648 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
9649 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
9650 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
9651 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
9652 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
9653
9654 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
9655 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
9656 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
9657 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
9658 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT); /* paranoia */
9659 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
9660 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
9661 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
9662 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT);
9663 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
9664 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_VMCS_CTRL_PROC_EXEC_RDPMC_EXIT);
9665 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
9666 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT);
9667 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
9668 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
9669 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
9670 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
9671 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
9672 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
9673 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
9674 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
9675 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
9676 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
9677 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
9678 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
9679 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
9680 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
9681 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
9682 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
9683 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
9684 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
9685 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
9686 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
9687 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
9688 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
9689 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
9690
9691 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
9692 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
9693 {
9694 int rc2 = hmR0VmxSaveGuestCR0(pVCpu, pCtx);
9695 rc2 |= hmR0VmxSaveGuestCR4(pVCpu, pCtx);
9696 rc2 |= hmR0VmxSaveGuestApicState(pVCpu, pCtx);
9697 AssertRC(rc2);
9698
9699#if 0 /** @todo fix me */
9700 pDbgState->fClearCr0Mask = true;
9701 pDbgState->fClearCr4Mask = true;
9702#endif
9703 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
9704 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_CR3_STORE_EXIT | VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT;
9705 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
9706 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_CR3_LOAD_EXIT | VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT;
9707 pDbgState->fCpe1Unwanted |= VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW; /* risky? */
9708 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
9709 require clearing here and in the loop if we start using it. */
9710 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
9711 }
9712 else
9713 {
9714 if (pDbgState->fClearCr0Mask)
9715 {
9716 pDbgState->fClearCr0Mask = false;
9717 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
9718 }
9719 if (pDbgState->fClearCr4Mask)
9720 {
9721 pDbgState->fClearCr4Mask = false;
9722 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
9723 }
9724 }
9725 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
9726 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
9727
9728 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
9729 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
9730 {
9731 /** @todo later, need to fix handler as it assumes this won't usually happen. */
9732 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
9733 }
9734 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
9735 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
9736
9737 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS); /* risky clearing this? */
9738 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
9739 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS);
9740 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
9741 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_VMCS_CTRL_PROC_EXEC_MWAIT_EXIT); /* paranoia */
9742 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
9743 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_VMCS_CTRL_PROC_EXEC_MONITOR_EXIT); /* paranoia */
9744 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
9745#if 0 /** @todo too slow, fix handler. */
9746 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_VMCS_CTRL_PROC_EXEC_PAUSE_EXIT);
9747#endif
9748 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
9749
9750 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
9751 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
9752 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
9753 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
9754 {
9755 pDbgState->fCpe2Extra |= VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT;
9756 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XDTR_ACCESS);
9757 }
9758 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_XDTR_ACCESS);
9759 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_XDTR_ACCESS);
9760 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_XDTR_ACCESS);
9761 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_XDTR_ACCESS);
9762
9763 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
9764 || IS_EITHER_ENABLED(pVM, INSTR_STR)
9765 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
9766 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
9767 {
9768 pDbgState->fCpe2Extra |= VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT;
9769 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_TR_ACCESS);
9770 }
9771 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_TR_ACCESS);
9772 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_TR_ACCESS);
9773 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_TR_ACCESS);
9774 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_TR_ACCESS);
9775
9776 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
9777 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
9778 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT);
9779 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
9780 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
9781 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
9782 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT);
9783 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
9784 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
9785 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
9786 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT);
9787 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
9788 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT);
9789 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
9790 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
9791 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
9792 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_VMCS_CTRL_PROC_EXEC2_RDSEED_EXIT);
9793 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
9794 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
9795 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
9796 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
9797 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
9798
9799#undef IS_EITHER_ENABLED
9800#undef SET_ONLY_XBM_IF_EITHER_EN
9801#undef SET_CPE1_XBM_IF_EITHER_EN
9802#undef SET_CPEU_XBM_IF_EITHER_EN
9803#undef SET_CPE2_XBM_IF_EITHER_EN
9804
9805 /*
9806 * Sanitize the control stuff.
9807 */
9808 pDbgState->fCpe2Extra &= pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1;
9809 if (pDbgState->fCpe2Extra)
9810 pDbgState->fCpe1Extra |= VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL;
9811 pDbgState->fCpe1Extra &= pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1;
9812 pDbgState->fCpe1Unwanted &= ~pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0;
9813 if (pVCpu->hm.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
9814 {
9815 pVCpu->hm.s.fDebugWantRdTscExit ^= true;
9816 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
9817 }
9818
9819 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
9820 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
9821 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
9822 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
9823}
9824
9825
9826/**
9827 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
9828 * appropriate.
9829 *
9830 * The caller has checked the VM-exit against the
9831 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
9832 * already, so we don't have to do that either.
9833 *
9834 * @returns Strict VBox status code (i.e. informational status codes too).
9835 * @param pVM The cross context VM structure.
9836 * @param pVCpu The cross context virtual CPU structure.
9837 * @param pMixedCtx Pointer to the guest-CPU context.
9838 * @param pVmxTransient Pointer to the VMX-transient structure.
9839 * @param uExitReason The VM-exit reason.
9840 *
9841 * @remarks The name of this function is displayed by dtrace, so keep it short
9842 * and to the point. No longer than 33 chars long, please.
9843 */
9844static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx,
9845 PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
9846{
9847 /*
9848 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
9849 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
9850 *
9851 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
9852 * does. Must add/change/remove both places. Same ordering, please.
9853 *
9854 * Added/removed events must also be reflected in the next section
9855 * where we dispatch dtrace events.
9856 */
9857 bool fDtrace1 = false;
9858 bool fDtrace2 = false;
9859 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
9860 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
9861 uint32_t uEventArg = 0;
9862#define SET_EXIT(a_EventSubName) \
9863 do { \
9864 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
9865 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
9866 } while (0)
9867#define SET_BOTH(a_EventSubName) \
9868 do { \
9869 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
9870 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
9871 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
9872 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
9873 } while (0)
9874 switch (uExitReason)
9875 {
9876 case VMX_EXIT_MTF:
9877 return hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient);
9878
9879 case VMX_EXIT_XCPT_OR_NMI:
9880 {
9881 uint8_t const idxVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
9882 switch (VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo))
9883 {
9884 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT:
9885 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT:
9886 case VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT:
9887 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
9888 {
9889 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uExitIntInfo))
9890 {
9891 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
9892 uEventArg = pVmxTransient->uExitIntErrorCode;
9893 }
9894 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
9895 switch (enmEvent1)
9896 {
9897 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
9898 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
9899 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
9900 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
9901 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
9902 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
9903 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
9904 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
9905 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
9906 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
9907 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
9908 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
9909 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
9910 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
9911 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
9912 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
9913 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
9914 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
9915 default: break;
9916 }
9917 }
9918 else
9919 AssertFailed();
9920 break;
9921
9922 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_INT:
9923 uEventArg = idxVector;
9924 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
9925 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
9926 break;
9927 }
9928 break;
9929 }
9930
9931 case VMX_EXIT_TRIPLE_FAULT:
9932 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
9933 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
9934 break;
9935 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
9936 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
9937 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
9938 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
9939 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
9940
9941 /* Instruction specific VM-exits: */
9942 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
9943 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
9944 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
9945 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
9946 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
9947 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
9948 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
9949 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
9950 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
9951 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
9952 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
9953 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
9954 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
9955 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
9956 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
9957 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
9958 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
9959 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
9960 case VMX_EXIT_MOV_CRX:
9961 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9962/** @todo r=bird: I feel these macros aren't very descriptive and needs to be at least 30 chars longer! ;-)
9963* Sensible abbreviations strongly recommended here because even with 130 columns this stuff get too wide! */
9964 if ( VMX_EXIT_QUALIFICATION_CRX_ACCESS(pVmxTransient->uExitQualification)
9965 == VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ)
9966 SET_BOTH(CRX_READ);
9967 else
9968 SET_BOTH(CRX_WRITE);
9969 uEventArg = VMX_EXIT_QUALIFICATION_CRX_REGISTER(pVmxTransient->uExitQualification);
9970 break;
9971 case VMX_EXIT_MOV_DRX:
9972 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
9973 if ( VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification)
9974 == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_READ)
9975 SET_BOTH(DRX_READ);
9976 else
9977 SET_BOTH(DRX_WRITE);
9978 uEventArg = VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification);
9979 break;
9980 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
9981 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
9982 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
9983 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
9984 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
9985 case VMX_EXIT_XDTR_ACCESS:
9986 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
9987 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_XDTR_INSINFO_INSTR_ID))
9988 {
9989 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
9990 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
9991 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
9992 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
9993 }
9994 break;
9995
9996 case VMX_EXIT_TR_ACCESS:
9997 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
9998 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_YYTR_INSINFO_INSTR_ID))
9999 {
10000 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
10001 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
10002 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
10003 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
10004 }
10005 break;
10006
10007 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
10008 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
10009 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
10010 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
10011 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
10012 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
10013 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
10014 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
10015 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
10016 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
10017 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
10018
10019 /* Events that aren't relevant at this point. */
10020 case VMX_EXIT_EXT_INT:
10021 case VMX_EXIT_INT_WINDOW:
10022 case VMX_EXIT_NMI_WINDOW:
10023 case VMX_EXIT_TPR_BELOW_THRESHOLD:
10024 case VMX_EXIT_PREEMPT_TIMER:
10025 case VMX_EXIT_IO_INSTR:
10026 break;
10027
10028 /* Errors and unexpected events. */
10029 case VMX_EXIT_INIT_SIGNAL:
10030 case VMX_EXIT_SIPI:
10031 case VMX_EXIT_IO_SMI:
10032 case VMX_EXIT_SMI:
10033 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
10034 case VMX_EXIT_ERR_MSR_LOAD:
10035 case VMX_EXIT_ERR_MACHINE_CHECK:
10036 break;
10037
10038 default:
10039 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
10040 break;
10041 }
10042#undef SET_BOTH
10043#undef SET_EXIT
10044
10045 /*
10046 * Dtrace tracepoints go first. We do them here at once so we don't
10047 * have to copy the guest state saving and stuff a few dozen times.
10048 * Down side is that we've got to repeat the switch, though this time
10049 * we use enmEvent since the probes are a subset of what DBGF does.
10050 */
10051 if (fDtrace1 || fDtrace2)
10052 {
10053 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
10054 hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
10055 switch (enmEvent1)
10056 {
10057 /** @todo consider which extra parameters would be helpful for each probe. */
10058 case DBGFEVENT_END: break;
10059 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pMixedCtx); break;
10060 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pMixedCtx, pMixedCtx->dr[6]); break;
10061 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pMixedCtx); break;
10062 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pMixedCtx); break;
10063 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pMixedCtx); break;
10064 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pMixedCtx); break;
10065 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pMixedCtx); break;
10066 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pMixedCtx); break;
10067 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pMixedCtx, uEventArg); break;
10068 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pMixedCtx, uEventArg); break;
10069 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pMixedCtx, uEventArg); break;
10070 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pMixedCtx, uEventArg); break;
10071 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pMixedCtx, uEventArg, pMixedCtx->cr2); break;
10072 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pMixedCtx); break;
10073 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pMixedCtx); break;
10074 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pMixedCtx); break;
10075 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pMixedCtx); break;
10076 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pMixedCtx, uEventArg); break;
10077 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
10078 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pMixedCtx, pMixedCtx->eax, pMixedCtx->ecx); break;
10079 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pMixedCtx); break;
10080 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pMixedCtx); break;
10081 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pMixedCtx); break;
10082 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pMixedCtx); break;
10083 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pMixedCtx); break;
10084 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pMixedCtx); break;
10085 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pMixedCtx); break;
10086 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
10087 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
10088 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
10089 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
10090 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pMixedCtx, pMixedCtx->ecx); break;
10091 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pMixedCtx, pMixedCtx->ecx,
10092 RT_MAKE_U64(pMixedCtx->eax, pMixedCtx->edx)); break;
10093 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pMixedCtx); break;
10094 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pMixedCtx); break;
10095 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pMixedCtx); break;
10096 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pMixedCtx); break;
10097 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pMixedCtx); break;
10098 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pMixedCtx); break;
10099 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pMixedCtx); break;
10100 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pMixedCtx); break;
10101 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pMixedCtx); break;
10102 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pMixedCtx); break;
10103 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pMixedCtx); break;
10104 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pMixedCtx); break;
10105 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pMixedCtx); break;
10106 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pMixedCtx); break;
10107 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pMixedCtx); break;
10108 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pMixedCtx); break;
10109 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pMixedCtx); break;
10110 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pMixedCtx); break;
10111 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pMixedCtx); break;
10112 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pMixedCtx); break;
10113 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pMixedCtx); break;
10114 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pMixedCtx); break;
10115 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pMixedCtx); break;
10116 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pMixedCtx); break;
10117 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pMixedCtx); break;
10118 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pMixedCtx); break;
10119 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pMixedCtx); break;
10120 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pMixedCtx); break;
10121 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pMixedCtx); break;
10122 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pMixedCtx); break;
10123 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pMixedCtx); break;
10124 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pMixedCtx); break;
10125 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
10126 }
10127 switch (enmEvent2)
10128 {
10129 /** @todo consider which extra parameters would be helpful for each probe. */
10130 case DBGFEVENT_END: break;
10131 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pMixedCtx); break;
10132 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pMixedCtx, pMixedCtx->eax, pMixedCtx->ecx); break;
10133 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pMixedCtx); break;
10134 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pMixedCtx); break;
10135 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pMixedCtx); break;
10136 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pMixedCtx); break;
10137 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pMixedCtx); break;
10138 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pMixedCtx); break;
10139 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pMixedCtx); break;
10140 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
10141 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
10142 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
10143 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pMixedCtx, (uint8_t)uEventArg); break;
10144 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pMixedCtx, pMixedCtx->ecx); break;
10145 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pMixedCtx, pMixedCtx->ecx,
10146 RT_MAKE_U64(pMixedCtx->eax, pMixedCtx->edx)); break;
10147 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pMixedCtx); break;
10148 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pMixedCtx); break;
10149 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pMixedCtx); break;
10150 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pMixedCtx); break;
10151 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pMixedCtx); break;
10152 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pMixedCtx); break;
10153 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pMixedCtx); break;
10154 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pMixedCtx); break;
10155 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pMixedCtx); break;
10156 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pMixedCtx); break;
10157 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pMixedCtx); break;
10158 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pMixedCtx); break;
10159 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pMixedCtx); break;
10160 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pMixedCtx); break;
10161 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pMixedCtx); break;
10162 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pMixedCtx); break;
10163 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pMixedCtx); break;
10164 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pMixedCtx); break;
10165 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pMixedCtx); break;
10166 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pMixedCtx); break;
10167 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pMixedCtx); break;
10168 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pMixedCtx); break;
10169 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pMixedCtx); break;
10170 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pMixedCtx); break;
10171 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pMixedCtx); break;
10172 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pMixedCtx); break;
10173 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pMixedCtx); break;
10174 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pMixedCtx); break;
10175 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pMixedCtx); break;
10176 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pMixedCtx); break;
10177 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pMixedCtx); break;
10178 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pMixedCtx); break;
10179 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pMixedCtx); break;
10180 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pMixedCtx); break;
10181 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pMixedCtx); break;
10182 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pMixedCtx); break;
10183 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
10184 }
10185 }
10186
10187 /*
10188 * Fire of the DBGF event, if enabled (our check here is just a quick one,
10189 * the DBGF call will do a full check).
10190 *
10191 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
10192 * Note! If we have to events, we prioritize the first, i.e. the instruction
10193 * one, in order to avoid event nesting.
10194 */
10195 if ( enmEvent1 != DBGFEVENT_END
10196 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
10197 {
10198 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArg(pVM, pVCpu, enmEvent1, uEventArg, DBGFEVENTCTX_HM);
10199 if (rcStrict != VINF_SUCCESS)
10200 return rcStrict;
10201 }
10202 else if ( enmEvent2 != DBGFEVENT_END
10203 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
10204 {
10205 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArg(pVM, pVCpu, enmEvent2, uEventArg, DBGFEVENTCTX_HM);
10206 if (rcStrict != VINF_SUCCESS)
10207 return rcStrict;
10208 }
10209
10210 return VINF_SUCCESS;
10211}
10212
10213
10214/**
10215 * Single-stepping VM-exit filtering.
10216 *
10217 * This is preprocessing the VM-exits and deciding whether we've gotten far
10218 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
10219 * handling is performed.
10220 *
10221 * @returns Strict VBox status code (i.e. informational status codes too).
10222 * @param pVM The cross context VM structure.
10223 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
10224 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
10225 * out-of-sync. Make sure to update the required
10226 * fields before using them.
10227 * @param pVmxTransient Pointer to the VMX-transient structure.
10228 * @param uExitReason The VM-exit reason.
10229 * @param pDbgState The debug state.
10230 */
10231DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient,
10232 uint32_t uExitReason, PVMXRUNDBGSTATE pDbgState)
10233{
10234 /*
10235 * Expensive (saves context) generic dtrace VM-exit probe.
10236 */
10237 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
10238 { /* more likely */ }
10239 else
10240 {
10241 hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
10242 hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
10243 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, pMixedCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQualification);
10244 }
10245
10246 /*
10247 * Check for host NMI, just to get that out of the way.
10248 */
10249 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
10250 { /* normally likely */ }
10251 else
10252 {
10253 int rc2 = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
10254 AssertRCReturn(rc2, rc2);
10255 uint32_t uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo);
10256 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
10257 return hmR0VmxExitXcptOrNmi(pVCpu, pMixedCtx, pVmxTransient);
10258 }
10259
10260 /*
10261 * Check for single stepping event if we're stepping.
10262 */
10263 if (pVCpu->hm.s.fSingleInstruction)
10264 {
10265 switch (uExitReason)
10266 {
10267 case VMX_EXIT_MTF:
10268 return hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient);
10269
10270 /* Various events: */
10271 case VMX_EXIT_XCPT_OR_NMI:
10272 case VMX_EXIT_EXT_INT:
10273 case VMX_EXIT_TRIPLE_FAULT:
10274 case VMX_EXIT_INT_WINDOW:
10275 case VMX_EXIT_NMI_WINDOW:
10276 case VMX_EXIT_TASK_SWITCH:
10277 case VMX_EXIT_TPR_BELOW_THRESHOLD:
10278 case VMX_EXIT_APIC_ACCESS:
10279 case VMX_EXIT_EPT_VIOLATION:
10280 case VMX_EXIT_EPT_MISCONFIG:
10281 case VMX_EXIT_PREEMPT_TIMER:
10282
10283 /* Instruction specific VM-exits: */
10284 case VMX_EXIT_CPUID:
10285 case VMX_EXIT_GETSEC:
10286 case VMX_EXIT_HLT:
10287 case VMX_EXIT_INVD:
10288 case VMX_EXIT_INVLPG:
10289 case VMX_EXIT_RDPMC:
10290 case VMX_EXIT_RDTSC:
10291 case VMX_EXIT_RSM:
10292 case VMX_EXIT_VMCALL:
10293 case VMX_EXIT_VMCLEAR:
10294 case VMX_EXIT_VMLAUNCH:
10295 case VMX_EXIT_VMPTRLD:
10296 case VMX_EXIT_VMPTRST:
10297 case VMX_EXIT_VMREAD:
10298 case VMX_EXIT_VMRESUME:
10299 case VMX_EXIT_VMWRITE:
10300 case VMX_EXIT_VMXOFF:
10301 case VMX_EXIT_VMXON:
10302 case VMX_EXIT_MOV_CRX:
10303 case VMX_EXIT_MOV_DRX:
10304 case VMX_EXIT_IO_INSTR:
10305 case VMX_EXIT_RDMSR:
10306 case VMX_EXIT_WRMSR:
10307 case VMX_EXIT_MWAIT:
10308 case VMX_EXIT_MONITOR:
10309 case VMX_EXIT_PAUSE:
10310 case VMX_EXIT_XDTR_ACCESS:
10311 case VMX_EXIT_TR_ACCESS:
10312 case VMX_EXIT_INVEPT:
10313 case VMX_EXIT_RDTSCP:
10314 case VMX_EXIT_INVVPID:
10315 case VMX_EXIT_WBINVD:
10316 case VMX_EXIT_XSETBV:
10317 case VMX_EXIT_RDRAND:
10318 case VMX_EXIT_INVPCID:
10319 case VMX_EXIT_VMFUNC:
10320 case VMX_EXIT_RDSEED:
10321 case VMX_EXIT_XSAVES:
10322 case VMX_EXIT_XRSTORS:
10323 {
10324 int rc2 = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
10325 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
10326 AssertRCReturn(rc2, rc2);
10327 if ( pMixedCtx->rip != pDbgState->uRipStart
10328 || pMixedCtx->cs.Sel != pDbgState->uCsStart)
10329 return VINF_EM_DBG_STEPPED;
10330 break;
10331 }
10332
10333 /* Errors and unexpected events: */
10334 case VMX_EXIT_INIT_SIGNAL:
10335 case VMX_EXIT_SIPI:
10336 case VMX_EXIT_IO_SMI:
10337 case VMX_EXIT_SMI:
10338 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
10339 case VMX_EXIT_ERR_MSR_LOAD:
10340 case VMX_EXIT_ERR_MACHINE_CHECK:
10341 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
10342 break;
10343
10344 default:
10345 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
10346 break;
10347 }
10348 }
10349
10350 /*
10351 * Check for debugger event breakpoints and dtrace probes.
10352 */
10353 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
10354 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
10355 {
10356 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVM, pVCpu, pMixedCtx, pVmxTransient, uExitReason);
10357 if (rcStrict != VINF_SUCCESS)
10358 return rcStrict;
10359 }
10360
10361 /*
10362 * Normal processing.
10363 */
10364#ifdef HMVMX_USE_FUNCTION_TABLE
10365 return g_apfnVMExitHandlers[uExitReason](pVCpu, pMixedCtx, pVmxTransient);
10366#else
10367 return hmR0VmxHandleExit(pVCpu, pMixedCtx, pVmxTransient, uExitReason);
10368#endif
10369}
10370
10371
10372/**
10373 * Single steps guest code using VT-x.
10374 *
10375 * @returns Strict VBox status code (i.e. informational status codes too).
10376 * @param pVM The cross context VM structure.
10377 * @param pVCpu The cross context virtual CPU structure.
10378 * @param pCtx Pointer to the guest-CPU context.
10379 *
10380 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
10381 */
10382static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10383{
10384 VMXTRANSIENT VmxTransient;
10385 VmxTransient.fUpdateTscOffsettingAndPreemptTimer = true;
10386
10387 /* Set HMCPU indicators. */
10388 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
10389 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
10390 pVCpu->hm.s.fDebugWantRdTscExit = false;
10391 pVCpu->hm.s.fUsingDebugLoop = true;
10392
10393 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
10394 VMXRUNDBGSTATE DbgState;
10395 hmR0VmxRunDebugStateInit(pVCpu, pCtx, &DbgState);
10396 hmR0VmxPreRunGuestDebugStateUpdate(pVM, pVCpu, pCtx, &DbgState, &VmxTransient);
10397
10398 /*
10399 * The loop.
10400 */
10401 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
10402 for (uint32_t cLoops = 0; ; cLoops++)
10403 {
10404 Assert(!HMR0SuspendPending());
10405 HMVMX_ASSERT_CPU_SAFE();
10406 bool fStepping = pVCpu->hm.s.fSingleInstruction;
10407
10408 /*
10409 * Preparatory work for running guest code, this may force us to return
10410 * to ring-3. This bugger disables interrupts on VINF_SUCCESS!
10411 */
10412 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
10413 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &DbgState); /* Set up execute controls the next to can respond to. */
10414 rcStrict = hmR0VmxPreRunGuest(pVM, pVCpu, pCtx, &VmxTransient, fStepping);
10415 if (rcStrict != VINF_SUCCESS)
10416 break;
10417
10418 hmR0VmxPreRunGuestCommitted(pVM, pVCpu, pCtx, &VmxTransient);
10419 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &DbgState); /* Override any obnoxious code in the above two calls. */
10420
10421 /*
10422 * Now we can run the guest code.
10423 */
10424 int rcRun = hmR0VmxRunGuest(pVM, pVCpu, pCtx);
10425
10426 /* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
10427
10428 /*
10429 * Restore any residual host-state and save any bits shared between host
10430 * and guest into the guest-CPU state. Re-enables interrupts!
10431 */
10432 hmR0VmxPostRunGuest(pVM, pVCpu, pCtx, &VmxTransient, rcRun);
10433
10434 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
10435 if (RT_SUCCESS(rcRun))
10436 { /* very likely */ }
10437 else
10438 {
10439 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
10440 hmR0VmxReportWorldSwitchError(pVM, pVCpu, rcRun, pCtx, &VmxTransient);
10441 return rcRun;
10442 }
10443
10444 /* Profile the VM-exit. */
10445 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
10446 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
10447 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
10448 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
10449 HMVMX_START_EXIT_DISPATCH_PROF();
10450
10451 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, pCtx, VmxTransient.uExitReason);
10452
10453 /*
10454 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
10455 */
10456 rcStrict = hmR0VmxRunDebugHandleExit(pVM, pVCpu, pCtx, &VmxTransient, VmxTransient.uExitReason, &DbgState);
10457 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
10458 if (rcStrict != VINF_SUCCESS)
10459 break;
10460 if (cLoops > pVM->hm.s.cMaxResumeLoops)
10461 {
10462 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
10463 rcStrict = VINF_EM_RAW_INTERRUPT;
10464 break;
10465 }
10466
10467 /*
10468 * Stepping: Did the RIP change, if so, consider it a single step.
10469 * Otherwise, make sure one of the TFs gets set.
10470 */
10471 if (fStepping)
10472 {
10473 int rc2 = hmR0VmxSaveGuestRip(pVCpu, pCtx);
10474 rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pCtx);
10475 AssertRCReturn(rc2, rc2);
10476 if ( pCtx->rip != DbgState.uRipStart
10477 || pCtx->cs.Sel != DbgState.uCsStart)
10478 {
10479 rcStrict = VINF_EM_DBG_STEPPED;
10480 break;
10481 }
10482 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
10483 }
10484
10485 /*
10486 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
10487 */
10488 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
10489 hmR0VmxPreRunGuestDebugStateUpdate(pVM, pVCpu, pCtx, &DbgState, &VmxTransient);
10490 }
10491
10492 /*
10493 * Clear the X86_EFL_TF if necessary.
10494 */
10495 if (pVCpu->hm.s.fClearTrapFlag)
10496 {
10497 int rc2 = hmR0VmxSaveGuestRflags(pVCpu, pCtx);
10498 AssertRCReturn(rc2, rc2);
10499 pVCpu->hm.s.fClearTrapFlag = false;
10500 pCtx->eflags.Bits.u1TF = 0;
10501 }
10502 /** @todo there seems to be issues with the resume flag when the monitor trap
10503 * flag is pending without being used. Seen early in bios init when
10504 * accessing APIC page in protected mode. */
10505
10506 /*
10507 * Restore VM-exit control settings as we may not reenter this function the
10508 * next time around.
10509 */
10510 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &DbgState, rcStrict);
10511
10512 /* Restore HMCPU indicators. */
10513 pVCpu->hm.s.fUsingDebugLoop = false;
10514 pVCpu->hm.s.fDebugWantRdTscExit = false;
10515 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
10516
10517 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
10518 return rcStrict;
10519}
10520
10521
10522/** @} */
10523
10524
10525/**
10526 * Checks if any expensive dtrace probes are enabled and we should go to the
10527 * debug loop.
10528 *
10529 * @returns true if we should use debug loop, false if not.
10530 */
10531static bool hmR0VmxAnyExpensiveProbesEnabled(void)
10532{
10533 /* It's probably faster to OR the raw 32-bit counter variables together.
10534 Since the variables are in an array and the probes are next to one
10535 another (more or less), we have good locality. So, better read
10536 eight-nine cache lines ever time and only have one conditional, than
10537 128+ conditionals, right? */
10538 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
10539 | VBOXVMM_XCPT_DE_ENABLED_RAW()
10540 | VBOXVMM_XCPT_DB_ENABLED_RAW()
10541 | VBOXVMM_XCPT_BP_ENABLED_RAW()
10542 | VBOXVMM_XCPT_OF_ENABLED_RAW()
10543 | VBOXVMM_XCPT_BR_ENABLED_RAW()
10544 | VBOXVMM_XCPT_UD_ENABLED_RAW()
10545 | VBOXVMM_XCPT_NM_ENABLED_RAW()
10546 | VBOXVMM_XCPT_DF_ENABLED_RAW()
10547 | VBOXVMM_XCPT_TS_ENABLED_RAW()
10548 | VBOXVMM_XCPT_NP_ENABLED_RAW()
10549 | VBOXVMM_XCPT_SS_ENABLED_RAW()
10550 | VBOXVMM_XCPT_GP_ENABLED_RAW()
10551 | VBOXVMM_XCPT_PF_ENABLED_RAW()
10552 | VBOXVMM_XCPT_MF_ENABLED_RAW()
10553 | VBOXVMM_XCPT_AC_ENABLED_RAW()
10554 | VBOXVMM_XCPT_XF_ENABLED_RAW()
10555 | VBOXVMM_XCPT_VE_ENABLED_RAW()
10556 | VBOXVMM_XCPT_SX_ENABLED_RAW()
10557 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
10558 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
10559 ) != 0
10560 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
10561 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
10562 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
10563 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
10564 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
10565 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
10566 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
10567 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
10568 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
10569 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
10570 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
10571 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
10572 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
10573 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
10574 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
10575 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
10576 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
10577 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
10578 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
10579 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
10580 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
10581 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
10582 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
10583 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
10584 | VBOXVMM_INSTR_STR_ENABLED_RAW()
10585 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
10586 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
10587 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
10588 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
10589 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
10590 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
10591 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
10592 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
10593 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
10594 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
10595 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
10596 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
10597 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
10598 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
10599 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
10600 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
10601 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
10602 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
10603 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
10604 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
10605 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
10606 ) != 0
10607 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
10608 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
10609 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
10610 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
10611 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
10612 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
10613 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
10614 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
10615 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
10616 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
10617 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
10618 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
10619 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
10620 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
10621 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
10622 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
10623 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
10624 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
10625 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
10626 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
10627 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
10628 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
10629 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
10630 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
10631 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
10632 | VBOXVMM_EXIT_STR_ENABLED_RAW()
10633 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
10634 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
10635 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
10636 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
10637 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
10638 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
10639 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
10640 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
10641 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
10642 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
10643 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
10644 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
10645 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
10646 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
10647 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
10648 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
10649 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
10650 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
10651 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
10652 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
10653 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
10654 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
10655 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
10656 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
10657 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
10658 ) != 0;
10659}
10660
10661
10662/**
10663 * Runs the guest code using VT-x.
10664 *
10665 * @returns Strict VBox status code (i.e. informational status codes too).
10666 * @param pVM The cross context VM structure.
10667 * @param pVCpu The cross context virtual CPU structure.
10668 * @param pCtx Pointer to the guest-CPU context.
10669 */
10670VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10671{
10672 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10673 Assert(HMVMXCPU_GST_VALUE(pVCpu) == HMVMX_UPDATED_GUEST_ALL);
10674 HMVMX_ASSERT_PREEMPT_SAFE();
10675
10676 VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pCtx);
10677
10678 VBOXSTRICTRC rcStrict;
10679 if ( !pVCpu->hm.s.fUseDebugLoop
10680 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
10681 && !DBGFIsStepping(pVCpu)
10682 && !pVM->dbgf.ro.cEnabledInt3Breakpoints)
10683 rcStrict = hmR0VmxRunGuestCodeNormal(pVM, pVCpu, pCtx);
10684 else
10685 rcStrict = hmR0VmxRunGuestCodeDebug(pVM, pVCpu, pCtx);
10686
10687 if (rcStrict == VERR_EM_INTERPRETER)
10688 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
10689 else if (rcStrict == VINF_EM_RESET)
10690 rcStrict = VINF_EM_TRIPLE_FAULT;
10691
10692 int rc2 = hmR0VmxExitToRing3(pVM, pVCpu, pCtx, rcStrict);
10693 if (RT_FAILURE(rc2))
10694 {
10695 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
10696 rcStrict = rc2;
10697 }
10698 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
10699 return rcStrict;
10700}
10701
10702
10703#ifndef HMVMX_USE_FUNCTION_TABLE
10704DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason)
10705{
10706# ifdef DEBUG_ramshankar
10707# define RETURN_EXIT_CALL(a_CallExpr) \
10708 do { \
10709 int rc2 = hmR0VmxSaveGuestState(pVCpu, pMixedCtx); AssertRC(rc2); \
10710 VBOXSTRICTRC rcStrict = a_CallExpr; \
10711 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST); \
10712 return rcStrict; \
10713 } while (0)
10714# else
10715# define RETURN_EXIT_CALL(a_CallExpr) return a_CallExpr
10716# endif
10717 switch (rcReason)
10718 {
10719 case VMX_EXIT_EPT_MISCONFIG: RETURN_EXIT_CALL(hmR0VmxExitEptMisconfig(pVCpu, pMixedCtx, pVmxTransient));
10720 case VMX_EXIT_EPT_VIOLATION: RETURN_EXIT_CALL(hmR0VmxExitEptViolation(pVCpu, pMixedCtx, pVmxTransient));
10721 case VMX_EXIT_IO_INSTR: RETURN_EXIT_CALL(hmR0VmxExitIoInstr(pVCpu, pMixedCtx, pVmxTransient));
10722 case VMX_EXIT_CPUID: RETURN_EXIT_CALL(hmR0VmxExitCpuid(pVCpu, pMixedCtx, pVmxTransient));
10723 case VMX_EXIT_RDTSC: RETURN_EXIT_CALL(hmR0VmxExitRdtsc(pVCpu, pMixedCtx, pVmxTransient));
10724 case VMX_EXIT_RDTSCP: RETURN_EXIT_CALL(hmR0VmxExitRdtscp(pVCpu, pMixedCtx, pVmxTransient));
10725 case VMX_EXIT_APIC_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitApicAccess(pVCpu, pMixedCtx, pVmxTransient));
10726 case VMX_EXIT_XCPT_OR_NMI: RETURN_EXIT_CALL(hmR0VmxExitXcptOrNmi(pVCpu, pMixedCtx, pVmxTransient));
10727 case VMX_EXIT_MOV_CRX: RETURN_EXIT_CALL(hmR0VmxExitMovCRx(pVCpu, pMixedCtx, pVmxTransient));
10728 case VMX_EXIT_EXT_INT: RETURN_EXIT_CALL(hmR0VmxExitExtInt(pVCpu, pMixedCtx, pVmxTransient));
10729 case VMX_EXIT_INT_WINDOW: RETURN_EXIT_CALL(hmR0VmxExitIntWindow(pVCpu, pMixedCtx, pVmxTransient));
10730 case VMX_EXIT_MWAIT: RETURN_EXIT_CALL(hmR0VmxExitMwait(pVCpu, pMixedCtx, pVmxTransient));
10731 case VMX_EXIT_MONITOR: RETURN_EXIT_CALL(hmR0VmxExitMonitor(pVCpu, pMixedCtx, pVmxTransient));
10732 case VMX_EXIT_TASK_SWITCH: RETURN_EXIT_CALL(hmR0VmxExitTaskSwitch(pVCpu, pMixedCtx, pVmxTransient));
10733 case VMX_EXIT_PREEMPT_TIMER: RETURN_EXIT_CALL(hmR0VmxExitPreemptTimer(pVCpu, pMixedCtx, pVmxTransient));
10734 case VMX_EXIT_RDMSR: RETURN_EXIT_CALL(hmR0VmxExitRdmsr(pVCpu, pMixedCtx, pVmxTransient));
10735 case VMX_EXIT_WRMSR: RETURN_EXIT_CALL(hmR0VmxExitWrmsr(pVCpu, pMixedCtx, pVmxTransient));
10736 case VMX_EXIT_MOV_DRX: RETURN_EXIT_CALL(hmR0VmxExitMovDRx(pVCpu, pMixedCtx, pVmxTransient));
10737 case VMX_EXIT_TPR_BELOW_THRESHOLD: RETURN_EXIT_CALL(hmR0VmxExitTprBelowThreshold(pVCpu, pMixedCtx, pVmxTransient));
10738 case VMX_EXIT_HLT: RETURN_EXIT_CALL(hmR0VmxExitHlt(pVCpu, pMixedCtx, pVmxTransient));
10739 case VMX_EXIT_INVD: RETURN_EXIT_CALL(hmR0VmxExitInvd(pVCpu, pMixedCtx, pVmxTransient));
10740 case VMX_EXIT_INVLPG: RETURN_EXIT_CALL(hmR0VmxExitInvlpg(pVCpu, pMixedCtx, pVmxTransient));
10741 case VMX_EXIT_RSM: RETURN_EXIT_CALL(hmR0VmxExitRsm(pVCpu, pMixedCtx, pVmxTransient));
10742 case VMX_EXIT_MTF: RETURN_EXIT_CALL(hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient));
10743 case VMX_EXIT_PAUSE: RETURN_EXIT_CALL(hmR0VmxExitPause(pVCpu, pMixedCtx, pVmxTransient));
10744 case VMX_EXIT_XDTR_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient));
10745 case VMX_EXIT_TR_ACCESS: RETURN_EXIT_CALL(hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient));
10746 case VMX_EXIT_WBINVD: RETURN_EXIT_CALL(hmR0VmxExitWbinvd(pVCpu, pMixedCtx, pVmxTransient));
10747 case VMX_EXIT_XSETBV: RETURN_EXIT_CALL(hmR0VmxExitXsetbv(pVCpu, pMixedCtx, pVmxTransient));
10748 case VMX_EXIT_RDRAND: RETURN_EXIT_CALL(hmR0VmxExitRdrand(pVCpu, pMixedCtx, pVmxTransient));
10749 case VMX_EXIT_INVPCID: RETURN_EXIT_CALL(hmR0VmxExitInvpcid(pVCpu, pMixedCtx, pVmxTransient));
10750 case VMX_EXIT_GETSEC: RETURN_EXIT_CALL(hmR0VmxExitGetsec(pVCpu, pMixedCtx, pVmxTransient));
10751 case VMX_EXIT_RDPMC: RETURN_EXIT_CALL(hmR0VmxExitRdpmc(pVCpu, pMixedCtx, pVmxTransient));
10752 case VMX_EXIT_VMCALL: RETURN_EXIT_CALL(hmR0VmxExitVmcall(pVCpu, pMixedCtx, pVmxTransient));
10753
10754 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pMixedCtx, pVmxTransient);
10755 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pMixedCtx, pVmxTransient);
10756 case VMX_EXIT_INIT_SIGNAL: return hmR0VmxExitInitSignal(pVCpu, pMixedCtx, pVmxTransient);
10757 case VMX_EXIT_SIPI: return hmR0VmxExitSipi(pVCpu, pMixedCtx, pVmxTransient);
10758 case VMX_EXIT_IO_SMI: return hmR0VmxExitIoSmi(pVCpu, pMixedCtx, pVmxTransient);
10759 case VMX_EXIT_SMI: return hmR0VmxExitSmi(pVCpu, pMixedCtx, pVmxTransient);
10760 case VMX_EXIT_ERR_MSR_LOAD: return hmR0VmxExitErrMsrLoad(pVCpu, pMixedCtx, pVmxTransient);
10761 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pMixedCtx, pVmxTransient);
10762 case VMX_EXIT_ERR_MACHINE_CHECK: return hmR0VmxExitErrMachineCheck(pVCpu, pMixedCtx, pVmxTransient);
10763
10764 case VMX_EXIT_VMCLEAR:
10765 case VMX_EXIT_VMLAUNCH:
10766 case VMX_EXIT_VMPTRLD:
10767 case VMX_EXIT_VMPTRST:
10768 case VMX_EXIT_VMREAD:
10769 case VMX_EXIT_VMRESUME:
10770 case VMX_EXIT_VMWRITE:
10771 case VMX_EXIT_VMXOFF:
10772 case VMX_EXIT_VMXON:
10773 case VMX_EXIT_INVEPT:
10774 case VMX_EXIT_INVVPID:
10775 case VMX_EXIT_VMFUNC:
10776 case VMX_EXIT_XSAVES:
10777 case VMX_EXIT_XRSTORS:
10778 return hmR0VmxExitSetPendingXcptUD(pVCpu, pMixedCtx, pVmxTransient);
10779 case VMX_EXIT_ENCLS:
10780 case VMX_EXIT_RDSEED: /* only spurious VM-exits, so undefined */
10781 case VMX_EXIT_PML_FULL:
10782 default:
10783 return hmR0VmxExitErrUndefined(pVCpu, pMixedCtx, pVmxTransient);
10784 }
10785#undef RETURN_EXIT_CALL
10786}
10787#endif /* !HMVMX_USE_FUNCTION_TABLE */
10788
10789
10790#ifdef VBOX_STRICT
10791/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
10792# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
10793 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
10794
10795# define HMVMX_ASSERT_PREEMPT_CPUID() \
10796 do { \
10797 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
10798 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
10799 } while (0)
10800
10801# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS() \
10802 do { \
10803 AssertPtr(pVCpu); \
10804 AssertPtr(pMixedCtx); \
10805 AssertPtr(pVmxTransient); \
10806 Assert(pVmxTransient->fVMEntryFailed == false); \
10807 Assert(ASMIntAreEnabled()); \
10808 HMVMX_ASSERT_PREEMPT_SAFE(); \
10809 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
10810 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)); \
10811 HMVMX_ASSERT_PREEMPT_SAFE(); \
10812 if (VMMR0IsLogFlushDisabled(pVCpu)) \
10813 HMVMX_ASSERT_PREEMPT_CPUID(); \
10814 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
10815 } while (0)
10816
10817# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() \
10818 do { \
10819 Log4Func(("\n")); \
10820 } while (0)
10821#else /* nonstrict builds: */
10822# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS() \
10823 do { \
10824 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
10825 NOREF(pVCpu); NOREF(pMixedCtx); NOREF(pVmxTransient); \
10826 } while (0)
10827# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() do { } while (0)
10828#endif
10829
10830
10831/**
10832 * Advances the guest RIP by the specified number of bytes.
10833 *
10834 * @param pVCpu The cross context virtual CPU structure.
10835 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
10836 * out-of-sync. Make sure to update the required fields
10837 * before using them.
10838 * @param cbInstr Number of bytes to advance the RIP by.
10839 *
10840 * @remarks No-long-jump zone!!!
10841 */
10842DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t cbInstr)
10843{
10844 /* Advance the RIP. */
10845 pMixedCtx->rip += cbInstr;
10846 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
10847
10848 /* Update interrupt inhibition. */
10849 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
10850 && pMixedCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
10851 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
10852}
10853
10854
10855/**
10856 * Advances the guest RIP after reading it from the VMCS.
10857 *
10858 * @returns VBox status code, no informational status codes.
10859 * @param pVCpu The cross context virtual CPU structure.
10860 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
10861 * out-of-sync. Make sure to update the required fields
10862 * before using them.
10863 * @param pVmxTransient Pointer to the VMX transient structure.
10864 *
10865 * @remarks No-long-jump zone!!!
10866 */
10867static int hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
10868{
10869 int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
10870 rc |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
10871 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
10872 AssertRCReturn(rc, rc);
10873
10874 hmR0VmxAdvanceGuestRipBy(pVCpu, pMixedCtx, pVmxTransient->cbInstr);
10875
10876 /*
10877 * Deliver a debug exception to the guest if it is single-stepping. Don't directly inject a #DB but use the
10878 * pending debug exception field as it takes care of priority of events.
10879 *
10880 * See Intel spec. 32.2.1 "Debug Exceptions".
10881 */
10882 if ( !pVCpu->hm.s.fSingleInstruction
10883 && pMixedCtx->eflags.Bits.u1TF)
10884 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
10885
10886 return VINF_SUCCESS;
10887}
10888
10889
10890/**
10891 * Tries to determine what part of the guest-state VT-x has deemed as invalid
10892 * and update error record fields accordingly.
10893 *
10894 * @return VMX_IGS_* return codes.
10895 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
10896 * wrong with the guest state.
10897 *
10898 * @param pVM The cross context VM structure.
10899 * @param pVCpu The cross context virtual CPU structure.
10900 * @param pCtx Pointer to the guest-CPU state.
10901 *
10902 * @remarks This function assumes our cache of the VMCS controls
10903 * are valid, i.e. hmR0VmxCheckVmcsCtls() succeeded.
10904 */
10905static uint32_t hmR0VmxCheckGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
10906{
10907#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
10908#define HMVMX_CHECK_BREAK(expr, err) if (!(expr)) { \
10909 uError = (err); \
10910 break; \
10911 } else do { } while (0)
10912
10913 int rc;
10914 uint32_t uError = VMX_IGS_ERROR;
10915 uint32_t u32Val;
10916 bool fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuest;
10917
10918 do
10919 {
10920 /*
10921 * CR0.
10922 */
10923 uint32_t uSetCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
10924 uint32_t uZapCR0 = (uint32_t)(pVM->hm.s.vmx.Msrs.u64Cr0Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr0Fixed1);
10925 /* Exceptions for unrestricted-guests for fixed CR0 bits (PE, PG).
10926 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
10927 if (fUnrestrictedGuest)
10928 uSetCR0 &= ~(X86_CR0_PE | X86_CR0_PG);
10929
10930 uint32_t u32GuestCR0;
10931 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32GuestCR0);
10932 AssertRCBreak(rc);
10933 HMVMX_CHECK_BREAK((u32GuestCR0 & uSetCR0) == uSetCR0, VMX_IGS_CR0_FIXED1);
10934 HMVMX_CHECK_BREAK(!(u32GuestCR0 & ~uZapCR0), VMX_IGS_CR0_FIXED0);
10935 if ( !fUnrestrictedGuest
10936 && (u32GuestCR0 & X86_CR0_PG)
10937 && !(u32GuestCR0 & X86_CR0_PE))
10938 {
10939 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
10940 }
10941
10942 /*
10943 * CR4.
10944 */
10945 uint64_t uSetCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 & pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
10946 uint64_t uZapCR4 = (pVM->hm.s.vmx.Msrs.u64Cr4Fixed0 | pVM->hm.s.vmx.Msrs.u64Cr4Fixed1);
10947
10948 uint32_t u32GuestCR4;
10949 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR4, &u32GuestCR4);
10950 AssertRCBreak(rc);
10951 HMVMX_CHECK_BREAK((u32GuestCR4 & uSetCR4) == uSetCR4, VMX_IGS_CR4_FIXED1);
10952 HMVMX_CHECK_BREAK(!(u32GuestCR4 & ~uZapCR4), VMX_IGS_CR4_FIXED0);
10953
10954 /*
10955 * IA32_DEBUGCTL MSR.
10956 */
10957 uint64_t u64Val;
10958 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
10959 AssertRCBreak(rc);
10960 if ( (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
10961 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
10962 {
10963 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
10964 }
10965 uint64_t u64DebugCtlMsr = u64Val;
10966
10967#ifdef VBOX_STRICT
10968 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
10969 AssertRCBreak(rc);
10970 Assert(u32Val == pVCpu->hm.s.vmx.u32EntryCtls);
10971#endif
10972 bool const fLongModeGuest = RT_BOOL(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST);
10973
10974 /*
10975 * RIP and RFLAGS.
10976 */
10977 uint32_t u32Eflags;
10978#if HC_ARCH_BITS == 64
10979 rc = VMXReadVmcs64(VMX_VMCS_GUEST_RIP, &u64Val);
10980 AssertRCBreak(rc);
10981 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
10982 if ( !fLongModeGuest
10983 || !pCtx->cs.Attr.n.u1Long)
10984 {
10985 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
10986 }
10987 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
10988 * must be identical if the "IA-32e mode guest" VM-entry
10989 * control is 1 and CS.L is 1. No check applies if the
10990 * CPU supports 64 linear-address bits. */
10991
10992 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
10993 rc = VMXReadVmcs64(VMX_VMCS_GUEST_RFLAGS, &u64Val);
10994 AssertRCBreak(rc);
10995 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
10996 VMX_IGS_RFLAGS_RESERVED);
10997 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
10998 u32Eflags = u64Val;
10999#else
11000 rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &u32Eflags);
11001 AssertRCBreak(rc);
11002 HMVMX_CHECK_BREAK(!(u32Eflags & 0xffc08028), VMX_IGS_RFLAGS_RESERVED); /* Bit 31:22, Bit 15, 5, 3 MBZ. */
11003 HMVMX_CHECK_BREAK((u32Eflags & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
11004#endif
11005
11006 if ( fLongModeGuest
11007 || ( fUnrestrictedGuest
11008 && !(u32GuestCR0 & X86_CR0_PE)))
11009 {
11010 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
11011 }
11012
11013 uint32_t u32EntryInfo;
11014 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
11015 AssertRCBreak(rc);
11016 if ( VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo)
11017 && VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
11018 {
11019 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
11020 }
11021
11022 /*
11023 * 64-bit checks.
11024 */
11025#if HC_ARCH_BITS == 64
11026 if (fLongModeGuest)
11027 {
11028 HMVMX_CHECK_BREAK(u32GuestCR0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
11029 HMVMX_CHECK_BREAK(u32GuestCR4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
11030 }
11031
11032 if ( !fLongModeGuest
11033 && (u32GuestCR4 & X86_CR4_PCIDE))
11034 {
11035 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
11036 }
11037
11038 /** @todo CR3 field must be such that bits 63:52 and bits in the range
11039 * 51:32 beyond the processor's physical-address width are 0. */
11040
11041 if ( (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG)
11042 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
11043 {
11044 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
11045 }
11046
11047 rc = VMXReadVmcs64(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
11048 AssertRCBreak(rc);
11049 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
11050
11051 rc = VMXReadVmcs64(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
11052 AssertRCBreak(rc);
11053 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
11054#endif
11055
11056 /*
11057 * PERF_GLOBAL MSR.
11058 */
11059 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PERF_MSR)
11060 {
11061 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
11062 AssertRCBreak(rc);
11063 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
11064 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
11065 }
11066
11067 /*
11068 * PAT MSR.
11069 */
11070 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_PAT_MSR)
11071 {
11072 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
11073 AssertRCBreak(rc);
11074 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
11075 for (unsigned i = 0; i < 8; i++)
11076 {
11077 uint8_t u8Val = (u64Val & 0xff);
11078 if ( u8Val != 0 /* UC */
11079 && u8Val != 1 /* WC */
11080 && u8Val != 4 /* WT */
11081 && u8Val != 5 /* WP */
11082 && u8Val != 6 /* WB */
11083 && u8Val != 7 /* UC- */)
11084 {
11085 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
11086 }
11087 u64Val >>= 8;
11088 }
11089 }
11090
11091 /*
11092 * EFER MSR.
11093 */
11094 if (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_LOAD_GUEST_EFER_MSR)
11095 {
11096 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
11097 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
11098 AssertRCBreak(rc);
11099 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
11100 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
11101 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVCpu->hm.s.vmx.u32EntryCtls
11102 & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST),
11103 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
11104 HMVMX_CHECK_BREAK( fUnrestrictedGuest
11105 || !(u32GuestCR0 & X86_CR0_PG)
11106 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
11107 VMX_IGS_EFER_LMA_LME_MISMATCH);
11108 }
11109
11110 /*
11111 * Segment registers.
11112 */
11113 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
11114 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
11115 if (!(u32Eflags & X86_EFL_VM))
11116 {
11117 /* CS */
11118 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
11119 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
11120 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
11121 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
11122 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
11123 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
11124 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
11125 /* CS cannot be loaded with NULL in protected mode. */
11126 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
11127 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
11128 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
11129 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
11130 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
11131 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
11132 else if (pVM->hm.s.vmx.fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
11133 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
11134 else
11135 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
11136
11137 /* SS */
11138 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
11139 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
11140 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
11141 if ( !(pCtx->cr0 & X86_CR0_PE)
11142 || pCtx->cs.Attr.n.u4Type == 3)
11143 {
11144 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
11145 }
11146 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
11147 {
11148 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
11149 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
11150 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
11151 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
11152 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
11153 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
11154 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
11155 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
11156 }
11157
11158 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxWriteSegmentReg(). */
11159 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
11160 {
11161 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
11162 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
11163 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
11164 || pCtx->ds.Attr.n.u4Type > 11
11165 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
11166 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
11167 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
11168 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
11169 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
11170 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
11171 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
11172 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
11173 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
11174 }
11175 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
11176 {
11177 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
11178 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
11179 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
11180 || pCtx->es.Attr.n.u4Type > 11
11181 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
11182 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
11183 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
11184 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
11185 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
11186 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
11187 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
11188 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
11189 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
11190 }
11191 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
11192 {
11193 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
11194 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
11195 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
11196 || pCtx->fs.Attr.n.u4Type > 11
11197 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
11198 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
11199 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
11200 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
11201 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
11202 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
11203 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
11204 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
11205 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
11206 }
11207 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
11208 {
11209 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
11210 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
11211 HMVMX_CHECK_BREAK( pVM->hm.s.vmx.fUnrestrictedGuest
11212 || pCtx->gs.Attr.n.u4Type > 11
11213 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
11214 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
11215 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
11216 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
11217 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
11218 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
11219 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
11220 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
11221 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
11222 }
11223 /* 64-bit capable CPUs. */
11224#if HC_ARCH_BITS == 64
11225 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
11226 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
11227 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
11228 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
11229 HMVMX_CHECK_BREAK(!(pCtx->cs.u64Base >> 32), VMX_IGS_LONGMODE_CS_BASE_INVALID);
11230 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ss.u64Base >> 32),
11231 VMX_IGS_LONGMODE_SS_BASE_INVALID);
11232 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ds.u64Base >> 32),
11233 VMX_IGS_LONGMODE_DS_BASE_INVALID);
11234 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->es.u64Base >> 32),
11235 VMX_IGS_LONGMODE_ES_BASE_INVALID);
11236#endif
11237 }
11238 else
11239 {
11240 /* V86 mode checks. */
11241 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
11242 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
11243 {
11244 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
11245 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
11246 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
11247 }
11248 else
11249 {
11250 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
11251 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
11252 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
11253 }
11254
11255 /* CS */
11256 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
11257 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
11258 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
11259 /* SS */
11260 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
11261 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
11262 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
11263 /* DS */
11264 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
11265 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
11266 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
11267 /* ES */
11268 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
11269 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
11270 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
11271 /* FS */
11272 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
11273 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
11274 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
11275 /* GS */
11276 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
11277 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
11278 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
11279 /* 64-bit capable CPUs. */
11280#if HC_ARCH_BITS == 64
11281 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
11282 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
11283 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
11284 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
11285 HMVMX_CHECK_BREAK(!(pCtx->cs.u64Base >> 32), VMX_IGS_LONGMODE_CS_BASE_INVALID);
11286 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ss.u64Base >> 32),
11287 VMX_IGS_LONGMODE_SS_BASE_INVALID);
11288 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->ds.u64Base >> 32),
11289 VMX_IGS_LONGMODE_DS_BASE_INVALID);
11290 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !(pCtx->es.u64Base >> 32),
11291 VMX_IGS_LONGMODE_ES_BASE_INVALID);
11292#endif
11293 }
11294
11295 /*
11296 * TR.
11297 */
11298 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
11299 /* 64-bit capable CPUs. */
11300#if HC_ARCH_BITS == 64
11301 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
11302#endif
11303 if (fLongModeGuest)
11304 {
11305 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
11306 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
11307 }
11308 else
11309 {
11310 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
11311 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
11312 VMX_IGS_TR_ATTR_TYPE_INVALID);
11313 }
11314 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
11315 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
11316 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
11317 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
11318 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
11319 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
11320 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
11321 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
11322
11323 /*
11324 * GDTR and IDTR.
11325 */
11326#if HC_ARCH_BITS == 64
11327 rc = VMXReadVmcs64(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
11328 AssertRCBreak(rc);
11329 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
11330
11331 rc = VMXReadVmcs64(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
11332 AssertRCBreak(rc);
11333 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
11334#endif
11335
11336 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
11337 AssertRCBreak(rc);
11338 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
11339
11340 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
11341 AssertRCBreak(rc);
11342 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
11343
11344 /*
11345 * Guest Non-Register State.
11346 */
11347 /* Activity State. */
11348 uint32_t u32ActivityState;
11349 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
11350 AssertRCBreak(rc);
11351 HMVMX_CHECK_BREAK( !u32ActivityState
11352 || (u32ActivityState & MSR_IA32_VMX_MISC_ACTIVITY_STATES(pVM->hm.s.vmx.Msrs.u64Misc)),
11353 VMX_IGS_ACTIVITY_STATE_INVALID);
11354 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
11355 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
11356 uint32_t u32IntrState;
11357 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &u32IntrState);
11358 AssertRCBreak(rc);
11359 if ( u32IntrState == VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS
11360 || u32IntrState == VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
11361 {
11362 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
11363 }
11364
11365 /** @todo Activity state and injecting interrupts. Left as a todo since we
11366 * currently don't use activity states but ACTIVE. */
11367
11368 HMVMX_CHECK_BREAK( !(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_ENTRY_SMM)
11369 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
11370
11371 /* Guest interruptibility-state. */
11372 HMVMX_CHECK_BREAK(!(u32IntrState & 0xfffffff0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
11373 HMVMX_CHECK_BREAK((u32IntrState & ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI
11374 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS))
11375 != ( VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI
11376 | VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
11377 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
11378 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
11379 || !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI),
11380 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
11381 if (VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo))
11382 {
11383 if (VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT)
11384 {
11385 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
11386 && !(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
11387 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
11388 }
11389 else if (VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11390 {
11391 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS),
11392 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
11393 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI),
11394 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
11395 }
11396 }
11397 /** @todo Assumes the processor is not in SMM. */
11398 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI),
11399 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
11400 HMVMX_CHECK_BREAK( !(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_ENTRY_SMM)
11401 || (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI),
11402 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
11403 if ( (pVCpu->hm.s.vmx.u32PinCtls & VMX_VMCS_CTRL_PIN_EXEC_VIRTUAL_NMI)
11404 && VMX_ENTRY_INTERRUPTION_INFO_IS_VALID(u32EntryInfo)
11405 && VMX_ENTRY_INTERRUPTION_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11406 {
11407 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI),
11408 VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
11409 }
11410
11411 /* Pending debug exceptions. */
11412#if HC_ARCH_BITS == 64
11413 rc = VMXReadVmcs64(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, &u64Val);
11414 AssertRCBreak(rc);
11415 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
11416 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
11417 u32Val = u64Val; /* For pending debug exceptions checks below. */
11418#else
11419 rc = VMXReadVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, &u32Val);
11420 AssertRCBreak(rc);
11421 /* Bits 31:15, Bit 13, Bits 11:4 MBZ. */
11422 HMVMX_CHECK_BREAK(!(u32Val & 0xffffaff0), VMX_IGS_PENDING_DEBUG_RESERVED);
11423#endif
11424
11425 if ( (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI)
11426 || (u32IntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS)
11427 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
11428 {
11429 if ( (u32Eflags & X86_EFL_TF)
11430 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
11431 {
11432 /* Bit 14 is PendingDebug.BS. */
11433 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
11434 }
11435 if ( !(u32Eflags & X86_EFL_TF)
11436 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
11437 {
11438 /* Bit 14 is PendingDebug.BS. */
11439 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
11440 }
11441 }
11442
11443 /* VMCS link pointer. */
11444 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
11445 AssertRCBreak(rc);
11446 if (u64Val != UINT64_C(0xffffffffffffffff))
11447 {
11448 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
11449 /** @todo Bits beyond the processor's physical-address width MBZ. */
11450 /** @todo 32-bit located in memory referenced by value of this field (as a
11451 * physical address) must contain the processor's VMCS revision ID. */
11452 /** @todo SMM checks. */
11453 }
11454
11455 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
11456 * not using Nested Paging? */
11457 if ( pVM->hm.s.fNestedPaging
11458 && !fLongModeGuest
11459 && CPUMIsGuestInPAEModeEx(pCtx))
11460 {
11461 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
11462 AssertRCBreak(rc);
11463 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11464
11465 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
11466 AssertRCBreak(rc);
11467 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11468
11469 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
11470 AssertRCBreak(rc);
11471 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11472
11473 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
11474 AssertRCBreak(rc);
11475 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
11476 }
11477
11478 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
11479 if (uError == VMX_IGS_ERROR)
11480 uError = VMX_IGS_REASON_NOT_FOUND;
11481 } while (0);
11482
11483 pVCpu->hm.s.u32HMError = uError;
11484 return uError;
11485
11486#undef HMVMX_ERROR_BREAK
11487#undef HMVMX_CHECK_BREAK
11488}
11489
11490/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
11491/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
11492/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
11493
11494/** @name VM-exit handlers.
11495 * @{
11496 */
11497
11498/**
11499 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
11500 */
11501HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11502{
11503 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11504 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
11505 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
11506 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
11507 return VINF_SUCCESS;
11508 return VINF_EM_RAW_INTERRUPT;
11509}
11510
11511
11512/**
11513 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
11514 */
11515HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11516{
11517 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11518 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
11519
11520 int rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
11521 AssertRCReturn(rc, rc);
11522
11523 uint32_t uIntType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVmxTransient->uExitIntInfo);
11524 Assert( !(pVCpu->hm.s.vmx.u32ExitCtls & VMX_VMCS_CTRL_EXIT_ACK_EXT_INT)
11525 && uIntType != VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT);
11526 Assert(VMX_EXIT_INTERRUPTION_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
11527
11528 if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI)
11529 {
11530 /*
11531 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we injected it ourselves and
11532 * anything we inject is not going to cause a VM-exit directly for the event being injected.
11533 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
11534 *
11535 * Dispatch the NMI to the host. See Intel spec. 27.5.5 "Updating Non-Register State".
11536 */
11537 VMXDispatchHostNmi();
11538 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
11539 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11540 return VINF_SUCCESS;
11541 }
11542
11543 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
11544 VBOXSTRICTRC rcStrictRc1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
11545 if (RT_UNLIKELY(rcStrictRc1 == VINF_SUCCESS))
11546 { /* likely */ }
11547 else
11548 {
11549 if (rcStrictRc1 == VINF_HM_DOUBLE_FAULT)
11550 rcStrictRc1 = VINF_SUCCESS;
11551 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11552 return rcStrictRc1;
11553 }
11554
11555 uint32_t uExitIntInfo = pVmxTransient->uExitIntInfo;
11556 uint32_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(uExitIntInfo);
11557 switch (uIntType)
11558 {
11559 case VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT: /* Privileged software exception. (#DB from ICEBP) */
11560 Assert(uVector == X86_XCPT_DB);
11561 /* fall thru */
11562 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SW_XCPT: /* Software exception. (#BP or #OF) */
11563 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT);
11564 /* fall thru */
11565 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT:
11566 {
11567 /*
11568 * If there's any exception caused as a result of event injection, go back to
11569 * the interpreter. The page-fault case is complicated and we manually handle
11570 * any currently pending event in hmR0VmxExitXcptPF. Nested #ACs are already
11571 * handled in hmR0VmxCheckExitDueToEventDelivery.
11572 */
11573 if (!pVCpu->hm.s.Event.fPending)
11574 { /* likely */ }
11575 else if ( uVector != X86_XCPT_PF
11576 && uVector != X86_XCPT_AC)
11577 {
11578 /** @todo Why do we need to fallback to the interpreter here? */
11579 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
11580 rc = VERR_EM_INTERPRETER;
11581 break;
11582 }
11583
11584 switch (uVector)
11585 {
11586 case X86_XCPT_PF: rc = hmR0VmxExitXcptPF(pVCpu, pMixedCtx, pVmxTransient); break;
11587 case X86_XCPT_GP: rc = hmR0VmxExitXcptGP(pVCpu, pMixedCtx, pVmxTransient); break;
11588 case X86_XCPT_NM: rc = hmR0VmxExitXcptNM(pVCpu, pMixedCtx, pVmxTransient); break;
11589 case X86_XCPT_MF: rc = hmR0VmxExitXcptMF(pVCpu, pMixedCtx, pVmxTransient); break;
11590 case X86_XCPT_DB: rc = hmR0VmxExitXcptDB(pVCpu, pMixedCtx, pVmxTransient); break;
11591 case X86_XCPT_BP: rc = hmR0VmxExitXcptBP(pVCpu, pMixedCtx, pVmxTransient); break;
11592 case X86_XCPT_AC: rc = hmR0VmxExitXcptAC(pVCpu, pMixedCtx, pVmxTransient); break;
11593
11594 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF);
11595 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11596 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE);
11597 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11598 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD);
11599 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11600 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS);
11601 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11602 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP);
11603 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11604 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS);
11605 rc = hmR0VmxExitXcptGeneric(pVCpu, pMixedCtx, pVmxTransient); break;
11606 default:
11607 {
11608 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11609 AssertRCReturn(rc, rc);
11610
11611 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
11612 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
11613 {
11614 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
11615 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
11616 Assert(CPUMIsGuestInRealModeEx(pMixedCtx));
11617
11618 rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
11619 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
11620 AssertRCReturn(rc, rc);
11621 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(uExitIntInfo),
11622 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode,
11623 0 /* GCPtrFaultAddress */);
11624 AssertRCReturn(rc, rc);
11625 }
11626 else
11627 {
11628 AssertMsgFailed(("Unexpected VM-exit caused by exception %#x\n", uVector));
11629 pVCpu->hm.s.u32HMError = uVector;
11630 rc = VERR_VMX_UNEXPECTED_EXCEPTION;
11631 }
11632 break;
11633 }
11634 }
11635 break;
11636 }
11637
11638 default:
11639 {
11640 pVCpu->hm.s.u32HMError = uExitIntInfo;
11641 rc = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
11642 AssertMsgFailed(("Unexpected interruption info %#x\n", VMX_EXIT_INTERRUPTION_INFO_TYPE(uExitIntInfo)));
11643 break;
11644 }
11645 }
11646 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
11647 return rc;
11648}
11649
11650
11651/**
11652 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
11653 */
11654HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11655{
11656 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11657
11658 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
11659 hmR0VmxClearIntWindowExitVmcs(pVCpu);
11660
11661 /* Deliver the pending interrupts via hmR0VmxEvaluatePendingEvent() and resume guest execution. */
11662 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
11663 return VINF_SUCCESS;
11664}
11665
11666
11667/**
11668 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
11669 */
11670HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11671{
11672 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11673 if (RT_UNLIKELY(!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_NMI_WINDOW_EXIT)))
11674 {
11675 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
11676 HMVMX_RETURN_UNEXPECTED_EXIT();
11677 }
11678
11679 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS));
11680
11681 /*
11682 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
11683 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
11684 */
11685 uint32_t uIntrState = 0;
11686 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
11687 AssertRCReturn(rc, rc);
11688
11689 bool const fBlockSti = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
11690 if ( fBlockSti
11691 && VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
11692 {
11693 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
11694 }
11695
11696 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
11697 hmR0VmxClearNmiWindowExitVmcs(pVCpu);
11698
11699 /* Deliver the pending NMI via hmR0VmxEvaluatePendingEvent() and resume guest execution. */
11700 return VINF_SUCCESS;
11701}
11702
11703
11704/**
11705 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
11706 */
11707HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11708{
11709 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11710 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWbinvd);
11711 return hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11712}
11713
11714
11715/**
11716 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
11717 */
11718HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11719{
11720 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11721 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvd);
11722 return hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11723}
11724
11725
11726/**
11727 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
11728 */
11729HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11730{
11731 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11732 PVM pVM = pVCpu->CTX_SUFF(pVM);
11733 int rc = EMInterpretCpuId(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11734 if (RT_LIKELY(rc == VINF_SUCCESS))
11735 {
11736 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11737 Assert(pVmxTransient->cbInstr == 2);
11738 }
11739 else
11740 {
11741 AssertMsgFailed(("hmR0VmxExitCpuid: EMInterpretCpuId failed with %Rrc\n", rc));
11742 rc = VERR_EM_INTERPRETER;
11743 }
11744 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCpuid);
11745 return rc;
11746}
11747
11748
11749/**
11750 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
11751 */
11752HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11753{
11754 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11755 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11756 AssertRCReturn(rc, rc);
11757
11758 if (pMixedCtx->cr4 & X86_CR4_SMXE)
11759 return VINF_EM_RAW_EMULATE_INSTR;
11760
11761 AssertMsgFailed(("hmR0VmxExitGetsec: unexpected VM-exit when CR4.SMXE is 0.\n"));
11762 HMVMX_RETURN_UNEXPECTED_EXIT();
11763}
11764
11765
11766/**
11767 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
11768 */
11769HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11770{
11771 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11772 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11773 AssertRCReturn(rc, rc);
11774
11775 PVM pVM = pVCpu->CTX_SUFF(pVM);
11776 rc = EMInterpretRdtsc(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11777 if (RT_LIKELY(rc == VINF_SUCCESS))
11778 {
11779 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11780 Assert(pVmxTransient->cbInstr == 2);
11781 /* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
11782 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING)
11783 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11784 }
11785 else
11786 rc = VERR_EM_INTERPRETER;
11787 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
11788 return rc;
11789}
11790
11791
11792/**
11793 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
11794 */
11795HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11796{
11797 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11798 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11799 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx); /* For MSR_K8_TSC_AUX */
11800 AssertRCReturn(rc, rc);
11801
11802 PVM pVM = pVCpu->CTX_SUFF(pVM);
11803 rc = EMInterpretRdtscp(pVM, pVCpu, pMixedCtx);
11804 if (RT_SUCCESS(rc))
11805 {
11806 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11807 Assert(pVmxTransient->cbInstr == 3);
11808 /* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
11809 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TSC_OFFSETTING)
11810 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
11811 }
11812 else
11813 {
11814 AssertMsgFailed(("hmR0VmxExitRdtscp: EMInterpretRdtscp failed with %Rrc\n", rc));
11815 rc = VERR_EM_INTERPRETER;
11816 }
11817 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
11818 return rc;
11819}
11820
11821
11822/**
11823 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
11824 */
11825HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11826{
11827 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11828 int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
11829 rc |= hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11830 AssertRCReturn(rc, rc);
11831
11832 PVM pVM = pVCpu->CTX_SUFF(pVM);
11833 rc = EMInterpretRdpmc(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11834 if (RT_LIKELY(rc == VINF_SUCCESS))
11835 {
11836 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11837 Assert(pVmxTransient->cbInstr == 2);
11838 }
11839 else
11840 {
11841 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
11842 rc = VERR_EM_INTERPRETER;
11843 }
11844 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdpmc);
11845 return rc;
11846}
11847
11848
11849/**
11850 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
11851 */
11852HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11853{
11854 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11855 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
11856
11857 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
11858 if (pVCpu->hm.s.fHypercallsEnabled)
11859 {
11860#if 0
11861 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
11862#else
11863 /* Aggressive state sync. for now. */
11864 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
11865 rc |= hmR0VmxSaveGuestRflags(pVCpu,pMixedCtx); /* For CPL checks in gimHvHypercall() & gimKvmHypercall() */
11866 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* For long-mode checks in gimKvmHypercall(). */
11867 AssertRCReturn(rc, rc);
11868#endif
11869
11870 /* Perform the hypercall. */
11871 rcStrict = GIMHypercall(pVCpu, pMixedCtx);
11872 if (rcStrict == VINF_SUCCESS)
11873 {
11874 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11875 AssertRCReturn(rc, rc);
11876 }
11877 else
11878 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
11879 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
11880 || RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)));
11881
11882 /* If the hypercall changes anything other than guest's general-purpose registers,
11883 we would need to reload the guest changed bits here before VM-entry. */
11884 }
11885 else
11886 Log4(("hmR0VmxExitVmcall: Hypercalls not enabled\n"));
11887
11888 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
11889 if (RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)))
11890 {
11891 hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
11892 rcStrict = VINF_SUCCESS;
11893 }
11894
11895 return rcStrict;
11896}
11897
11898
11899/**
11900 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
11901 */
11902HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11903{
11904 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11905 PVM pVM = pVCpu->CTX_SUFF(pVM);
11906 Assert(!pVM->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
11907
11908 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
11909 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
11910 AssertRCReturn(rc, rc);
11911
11912 VBOXSTRICTRC rcStrict = EMInterpretInvlpg(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), pVmxTransient->uExitQualification);
11913 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
11914 rcStrict = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11915 else
11916 AssertMsg(rcStrict == VERR_EM_INTERPRETER, ("hmR0VmxExitInvlpg: EMInterpretInvlpg %#RX64 failed with %Rrc\n",
11917 pVmxTransient->uExitQualification, VBOXSTRICTRC_VAL(rcStrict)));
11918 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvlpg);
11919 return rcStrict;
11920}
11921
11922
11923/**
11924 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
11925 */
11926HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11927{
11928 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11929 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11930 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
11931 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
11932 AssertRCReturn(rc, rc);
11933
11934 PVM pVM = pVCpu->CTX_SUFF(pVM);
11935 rc = EMInterpretMonitor(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11936 if (RT_LIKELY(rc == VINF_SUCCESS))
11937 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11938 else
11939 {
11940 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMonitor: EMInterpretMonitor failed with %Rrc\n", rc));
11941 rc = VERR_EM_INTERPRETER;
11942 }
11943 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMonitor);
11944 return rc;
11945}
11946
11947
11948/**
11949 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
11950 */
11951HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11952{
11953 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11954 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
11955 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
11956 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
11957 AssertRCReturn(rc, rc);
11958
11959 PVM pVM = pVCpu->CTX_SUFF(pVM);
11960 VBOXSTRICTRC rc2 = EMInterpretMWait(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
11961 rc = VBOXSTRICTRC_VAL(rc2);
11962 if (RT_LIKELY( rc == VINF_SUCCESS
11963 || rc == VINF_EM_HALT))
11964 {
11965 int rc3 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
11966 AssertRCReturn(rc3, rc3);
11967
11968 if ( rc == VINF_EM_HALT
11969 && EMMonitorWaitShouldContinue(pVCpu, pMixedCtx))
11970 {
11971 rc = VINF_SUCCESS;
11972 }
11973 }
11974 else
11975 {
11976 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMwait: EMInterpretMWait failed with %Rrc\n", rc));
11977 rc = VERR_EM_INTERPRETER;
11978 }
11979 AssertMsg(rc == VINF_SUCCESS || rc == VINF_EM_HALT || rc == VERR_EM_INTERPRETER,
11980 ("hmR0VmxExitMwait: failed, invalid error code %Rrc\n", rc));
11981 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMwait);
11982 return rc;
11983}
11984
11985
11986/**
11987 * VM-exit handler for RSM (VMX_EXIT_RSM). Unconditional VM-exit.
11988 */
11989HMVMX_EXIT_NSRC_DECL hmR0VmxExitRsm(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
11990{
11991 /*
11992 * Execution of RSM outside of SMM mode causes #UD regardless of VMX root or VMX non-root mode. In theory, we should never
11993 * get this VM-exit. This can happen only if dual-monitor treatment of SMI and VMX is enabled, which can (only?) be done by
11994 * executing VMCALL in VMX root operation. If we get here, something funny is going on.
11995 * See Intel spec. "33.15.5 Enabling the Dual-Monitor Treatment".
11996 */
11997 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
11998 AssertMsgFailed(("Unexpected RSM VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
11999 HMVMX_RETURN_UNEXPECTED_EXIT();
12000}
12001
12002
12003/**
12004 * VM-exit handler for SMI (VMX_EXIT_SMI). Unconditional VM-exit.
12005 */
12006HMVMX_EXIT_NSRC_DECL hmR0VmxExitSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12007{
12008 /*
12009 * This can only happen if we support dual-monitor treatment of SMI, which can be activated by executing VMCALL in VMX
12010 * root operation. Only an STM (SMM transfer monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL
12011 * in VMX root mode or receive an SMI. If we get here, something funny is going on.
12012 * See Intel spec. "33.15.6 Activating the Dual-Monitor Treatment" and Intel spec. 25.3 "Other Causes of VM-Exits"
12013 */
12014 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12015 AssertMsgFailed(("Unexpected SMI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12016 HMVMX_RETURN_UNEXPECTED_EXIT();
12017}
12018
12019
12020/**
12021 * VM-exit handler for IO SMI (VMX_EXIT_IO_SMI). Unconditional VM-exit.
12022 */
12023HMVMX_EXIT_NSRC_DECL hmR0VmxExitIoSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12024{
12025 /* Same treatment as VMX_EXIT_SMI. See comment in hmR0VmxExitSmi(). */
12026 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12027 AssertMsgFailed(("Unexpected IO SMI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12028 HMVMX_RETURN_UNEXPECTED_EXIT();
12029}
12030
12031
12032/**
12033 * VM-exit handler for SIPI (VMX_EXIT_SIPI). Conditional VM-exit.
12034 */
12035HMVMX_EXIT_NSRC_DECL hmR0VmxExitSipi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12036{
12037 /*
12038 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest activity state is used. We currently
12039 * don't make use of it (see hmR0VmxLoadGuestActivityState()) as our guests don't have direct access to the host LAPIC.
12040 * See Intel spec. 25.3 "Other Causes of VM-exits".
12041 */
12042 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12043 AssertMsgFailed(("Unexpected SIPI VM-exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12044 HMVMX_RETURN_UNEXPECTED_EXIT();
12045}
12046
12047
12048/**
12049 * VM-exit handler for INIT signal (VMX_EXIT_INIT_SIGNAL). Unconditional
12050 * VM-exit.
12051 */
12052HMVMX_EXIT_NSRC_DECL hmR0VmxExitInitSignal(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12053{
12054 /*
12055 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
12056 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery" and Intel spec. 29.3 "VMX Instructions" for "VMXON".
12057 *
12058 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these VM-exits.
12059 * See Intel spec. "23.8 Restrictions on VMX operation".
12060 */
12061 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12062 return VINF_SUCCESS;
12063}
12064
12065
12066/**
12067 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
12068 * VM-exit.
12069 */
12070HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12071{
12072 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12073 return VINF_EM_RESET;
12074}
12075
12076
12077/**
12078 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
12079 */
12080HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12081{
12082 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12083 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT);
12084
12085 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12086 AssertRCReturn(rc, rc);
12087
12088 if (EMShouldContinueAfterHalt(pVCpu, pMixedCtx)) /* Requires eflags. */
12089 rc = VINF_SUCCESS;
12090 else
12091 rc = VINF_EM_HALT;
12092
12093 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
12094 if (rc != VINF_SUCCESS)
12095 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
12096 return rc;
12097}
12098
12099
12100/**
12101 * VM-exit handler for instructions that result in a \#UD exception delivered to
12102 * the guest.
12103 */
12104HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12105{
12106 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12107 hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
12108 return VINF_SUCCESS;
12109}
12110
12111
12112/**
12113 * VM-exit handler for expiry of the VMX preemption timer.
12114 */
12115HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12116{
12117 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12118
12119 /* If the preemption-timer has expired, reinitialize the preemption timer on next VM-entry. */
12120 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
12121
12122 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
12123 PVM pVM = pVCpu->CTX_SUFF(pVM);
12124 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
12125 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
12126 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
12127}
12128
12129
12130/**
12131 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
12132 */
12133HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12134{
12135 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12136
12137 int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12138 rc |= hmR0VmxSaveGuestRegsForIemExec(pVCpu, pMixedCtx, false /*fMemory*/, false /*fNeedRsp*/);
12139 rc |= hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx);
12140 AssertRCReturn(rc, rc);
12141
12142 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbInstr);
12143 HMCPU_CF_SET(pVCpu, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS : HM_CHANGED_ALL_GUEST);
12144
12145 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pMixedCtx->cr4 & X86_CR4_OSXSAVE) && pMixedCtx->aXcr[0] != ASMGetXcr0();
12146
12147 return rcStrict;
12148}
12149
12150
12151/**
12152 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
12153 */
12154HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12155{
12156 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12157
12158 /* The guest should not invalidate the host CPU's TLBs, fallback to interpreter. */
12159 /** @todo implement EMInterpretInvpcid() */
12160 return VERR_EM_INTERPRETER;
12161}
12162
12163
12164/**
12165 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE).
12166 * Error VM-exit.
12167 */
12168HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12169{
12170 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12171 AssertRCReturn(rc, rc);
12172
12173 rc = hmR0VmxCheckVmcsCtls(pVCpu);
12174 AssertRCReturn(rc, rc);
12175
12176 uint32_t uInvalidReason = hmR0VmxCheckGuestState(pVCpu->CTX_SUFF(pVM), pVCpu, pMixedCtx);
12177 NOREF(uInvalidReason);
12178
12179#ifdef VBOX_STRICT
12180 uint32_t uIntrState;
12181 RTHCUINTREG uHCReg;
12182 uint64_t u64Val;
12183 uint32_t u32Val;
12184
12185 rc = hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
12186 rc |= hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
12187 rc |= hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
12188 rc |= VMXReadVmcs32(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &uIntrState);
12189 AssertRCReturn(rc, rc);
12190
12191 Log4(("uInvalidReason %u\n", uInvalidReason));
12192 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
12193 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
12194 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
12195 Log4(("VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE %#RX32\n", uIntrState));
12196
12197 rc = VMXReadVmcs32(VMX_VMCS_GUEST_CR0, &u32Val); AssertRC(rc);
12198 Log4(("VMX_VMCS_GUEST_CR0 %#RX32\n", u32Val));
12199 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_MASK, &uHCReg); AssertRC(rc);
12200 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RHr\n", uHCReg));
12201 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR0_READ_SHADOW, &uHCReg); AssertRC(rc);
12202 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
12203 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_MASK, &uHCReg); AssertRC(rc);
12204 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RHr\n", uHCReg));
12205 rc = VMXReadVmcsHstN(VMX_VMCS_CTRL_CR4_READ_SHADOW, &uHCReg); AssertRC(rc);
12206 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RHr\n", uHCReg));
12207 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
12208 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
12209#else
12210 NOREF(pVmxTransient);
12211#endif
12212
12213 hmR0DumpRegs(pVCpu->CTX_SUFF(pVM), pVCpu, pMixedCtx);
12214 return VERR_VMX_INVALID_GUEST_STATE;
12215}
12216
12217
12218/**
12219 * VM-exit handler for VM-entry failure due to an MSR-load
12220 * (VMX_EXIT_ERR_MSR_LOAD). Error VM-exit.
12221 */
12222HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrMsrLoad(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12223{
12224 NOREF(pVmxTransient);
12225 AssertMsgFailed(("Unexpected MSR-load exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx)); NOREF(pMixedCtx);
12226 HMVMX_RETURN_UNEXPECTED_EXIT();
12227}
12228
12229
12230/**
12231 * VM-exit handler for VM-entry failure due to a machine-check event
12232 * (VMX_EXIT_ERR_MACHINE_CHECK). Error VM-exit.
12233 */
12234HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrMachineCheck(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12235{
12236 NOREF(pVmxTransient);
12237 AssertMsgFailed(("Unexpected machine-check event exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx)); NOREF(pMixedCtx);
12238 HMVMX_RETURN_UNEXPECTED_EXIT();
12239}
12240
12241
12242/**
12243 * VM-exit handler for all undefined reasons. Should never ever happen.. in
12244 * theory.
12245 */
12246HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUndefined(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12247{
12248 AssertMsgFailed(("Huh!? Undefined VM-exit reason %d. pVCpu=%p pMixedCtx=%p\n", pVmxTransient->uExitReason, pVCpu, pMixedCtx));
12249 NOREF(pVCpu); NOREF(pMixedCtx); NOREF(pVmxTransient);
12250 return VERR_VMX_UNDEFINED_EXIT_CODE;
12251}
12252
12253
12254/**
12255 * VM-exit handler for XDTR (LGDT, SGDT, LIDT, SIDT) accesses
12256 * (VMX_EXIT_XDTR_ACCESS) and LDT and TR access (LLDT, LTR, SLDT, STR).
12257 * Conditional VM-exit.
12258 */
12259HMVMX_EXIT_DECL hmR0VmxExitXdtrAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12260{
12261 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12262
12263 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT. */
12264 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitXdtrAccess);
12265 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_TABLE_EXIT)
12266 return VERR_EM_INTERPRETER;
12267 AssertMsgFailed(("Unexpected XDTR access. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12268 HMVMX_RETURN_UNEXPECTED_EXIT();
12269}
12270
12271
12272/**
12273 * VM-exit handler for RDRAND (VMX_EXIT_RDRAND). Conditional VM-exit.
12274 */
12275HMVMX_EXIT_DECL hmR0VmxExitRdrand(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12276{
12277 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12278
12279 /* By default, we don't enable VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT. */
12280 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdrand);
12281 if (pVCpu->hm.s.vmx.u32ProcCtls2 & VMX_VMCS_CTRL_PROC_EXEC2_RDRAND_EXIT)
12282 return VERR_EM_INTERPRETER;
12283 AssertMsgFailed(("Unexpected RDRAND exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
12284 HMVMX_RETURN_UNEXPECTED_EXIT();
12285}
12286
12287
12288/**
12289 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
12290 */
12291HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12292{
12293 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12294
12295 /* EMInterpretRdmsr() requires CR0, Eflags and SS segment register. */
12296 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
12297 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
12298 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12299 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
12300 {
12301 rc |= hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
12302 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
12303 }
12304 AssertRCReturn(rc, rc);
12305 Log4(("ecx=%#RX32\n", pMixedCtx->ecx));
12306
12307#ifdef VBOX_STRICT
12308 if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
12309 {
12310 if ( hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx)
12311 && pMixedCtx->ecx != MSR_K6_EFER)
12312 {
12313 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
12314 pMixedCtx->ecx));
12315 HMVMX_RETURN_UNEXPECTED_EXIT();
12316 }
12317 if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
12318 {
12319 VMXMSREXITREAD enmRead;
12320 VMXMSREXITWRITE enmWrite;
12321 int rc2 = hmR0VmxGetMsrPermission(pVCpu, pMixedCtx->ecx, &enmRead, &enmWrite);
12322 AssertRCReturn(rc2, rc2);
12323 if (enmRead == VMXMSREXIT_PASSTHRU_READ)
12324 {
12325 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", pMixedCtx->ecx));
12326 HMVMX_RETURN_UNEXPECTED_EXIT();
12327 }
12328 }
12329 }
12330#endif
12331
12332 PVM pVM = pVCpu->CTX_SUFF(pVM);
12333 rc = EMInterpretRdmsr(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
12334 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER,
12335 ("hmR0VmxExitRdmsr: failed, invalid error code %Rrc\n", rc));
12336 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
12337 if (RT_SUCCESS(rc))
12338 {
12339 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12340 Assert(pVmxTransient->cbInstr == 2);
12341 }
12342 return rc;
12343}
12344
12345
12346/**
12347 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
12348 */
12349HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12350{
12351 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12352 PVM pVM = pVCpu->CTX_SUFF(pVM);
12353 int rc = VINF_SUCCESS;
12354
12355 /* EMInterpretWrmsr() requires CR0, EFLAGS and SS segment register. */
12356 rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
12357 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx);
12358 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12359 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
12360 {
12361 rc |= hmR0VmxSaveGuestLazyMsrs(pVCpu, pMixedCtx);
12362 rc |= hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
12363 }
12364 AssertRCReturn(rc, rc);
12365 Log4(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", pMixedCtx->ecx, pMixedCtx->edx, pMixedCtx->eax));
12366
12367 rc = EMInterpretWrmsr(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
12368 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER, ("hmR0VmxExitWrmsr: failed, invalid error code %Rrc\n", rc));
12369 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
12370
12371 if (RT_SUCCESS(rc))
12372 {
12373 rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
12374
12375 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
12376 if ( pMixedCtx->ecx == MSR_IA32_APICBASE
12377 || ( pMixedCtx->ecx >= MSR_IA32_X2APIC_START
12378 && pMixedCtx->ecx <= MSR_IA32_X2APIC_END))
12379 {
12380 /*
12381 * We've already saved the APIC related guest-state (TPR) in hmR0VmxPostRunGuest(). When full APIC register
12382 * virtualization is implemented we'll have to make sure APIC state is saved from the VMCS before
12383 * EMInterpretWrmsr() changes it.
12384 */
12385 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
12386 }
12387 else if (pMixedCtx->ecx == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
12388 pVmxTransient->fUpdateTscOffsettingAndPreemptTimer = true;
12389 else if (pMixedCtx->ecx == MSR_K6_EFER)
12390 {
12391 /*
12392 * If the guest touches EFER we need to update the VM-Entry and VM-Exit controls as well,
12393 * even if it is -not- touching bits that cause paging mode changes (LMA/LME). We care about
12394 * the other bits as well, SCE and NXE. See @bugref{7368}.
12395 */
12396 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_CTLS | HM_CHANGED_VMX_EXIT_CTLS);
12397 }
12398
12399 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not supported. */
12400 if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS))
12401 {
12402 switch (pMixedCtx->ecx)
12403 {
12404 /*
12405 * For SYSENTER CS, EIP, ESP MSRs, we set both the flags here so we don't accidentally
12406 * overwrite the changed guest-CPU context value while going to ring-3, see @bufref{8745}.
12407 */
12408 case MSR_IA32_SYSENTER_CS:
12409 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR);
12410 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR);
12411 break;
12412 case MSR_IA32_SYSENTER_EIP:
12413 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
12414 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR);
12415 break;
12416 case MSR_IA32_SYSENTER_ESP:
12417 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
12418 HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR);
12419 break;
12420 case MSR_K8_FS_BASE: /* fall thru */
12421 case MSR_K8_GS_BASE: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS); break;
12422 case MSR_K6_EFER: /* already handled above */ break;
12423 default:
12424 {
12425 if (hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx))
12426 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
12427 else if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
12428 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS);
12429 break;
12430 }
12431 }
12432 }
12433#ifdef VBOX_STRICT
12434 else
12435 {
12436 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
12437 switch (pMixedCtx->ecx)
12438 {
12439 case MSR_IA32_SYSENTER_CS:
12440 case MSR_IA32_SYSENTER_EIP:
12441 case MSR_IA32_SYSENTER_ESP:
12442 case MSR_K8_FS_BASE:
12443 case MSR_K8_GS_BASE:
12444 {
12445 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", pMixedCtx->ecx));
12446 HMVMX_RETURN_UNEXPECTED_EXIT();
12447 }
12448
12449 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
12450 default:
12451 {
12452 if (hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx))
12453 {
12454 /* EFER writes are always intercepted, see hmR0VmxLoadGuestMsrs(). */
12455 if (pMixedCtx->ecx != MSR_K6_EFER)
12456 {
12457 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
12458 pMixedCtx->ecx));
12459 HMVMX_RETURN_UNEXPECTED_EXIT();
12460 }
12461 }
12462
12463 if (hmR0VmxIsLazyGuestMsr(pVCpu, pMixedCtx->ecx))
12464 {
12465 VMXMSREXITREAD enmRead;
12466 VMXMSREXITWRITE enmWrite;
12467 int rc2 = hmR0VmxGetMsrPermission(pVCpu, pMixedCtx->ecx, &enmRead, &enmWrite);
12468 AssertRCReturn(rc2, rc2);
12469 if (enmWrite == VMXMSREXIT_PASSTHRU_WRITE)
12470 {
12471 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", pMixedCtx->ecx));
12472 HMVMX_RETURN_UNEXPECTED_EXIT();
12473 }
12474 }
12475 break;
12476 }
12477 }
12478 }
12479#endif /* VBOX_STRICT */
12480 }
12481 return rc;
12482}
12483
12484
12485/**
12486 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
12487 */
12488HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12489{
12490 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12491
12492 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPause);
12493 return VINF_EM_RAW_INTERRUPT;
12494}
12495
12496
12497/**
12498 * VM-exit handler for when the TPR value is lowered below the specified
12499 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
12500 */
12501HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12502{
12503 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12504 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW);
12505
12506 /*
12507 * The TPR shadow would've been synced with the APIC TPR in hmR0VmxPostRunGuest(). We'll re-evaluate
12508 * pending interrupts and inject them before the next VM-entry so we can just continue execution here.
12509 */
12510 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
12511 return VINF_SUCCESS;
12512}
12513
12514
12515/**
12516 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
12517 * VM-exit.
12518 *
12519 * @retval VINF_SUCCESS when guest execution can continue.
12520 * @retval VINF_PGM_CHANGE_MODE when shadow paging mode changed, back to ring-3.
12521 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
12522 * @retval VERR_EM_INTERPRETER when something unexpected happened, fallback to
12523 * interpreter.
12524 */
12525HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12526{
12527 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12528 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
12529 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12530 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12531 AssertRCReturn(rc, rc);
12532
12533 RTGCUINTPTR const uExitQualification = pVmxTransient->uExitQualification;
12534 uint32_t const uAccessType = VMX_EXIT_QUALIFICATION_CRX_ACCESS(uExitQualification);
12535 PVM pVM = pVCpu->CTX_SUFF(pVM);
12536 VBOXSTRICTRC rcStrict;
12537 rc = hmR0VmxSaveGuestRegsForIemExec(pVCpu, pMixedCtx, false /*fMemory*/, true /*fNeedRsp*/);
12538 switch (uAccessType)
12539 {
12540 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_WRITE: /* MOV to CRx */
12541 {
12542 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12543 AssertRCReturn(rc, rc);
12544
12545 rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, pVmxTransient->cbInstr,
12546 VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification),
12547 VMX_EXIT_QUALIFICATION_CRX_GENREG(uExitQualification));
12548 AssertMsg( rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT || rcStrict == VINF_PGM_CHANGE_MODE
12549 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12550 switch (VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification))
12551 {
12552 case 0: /* CR0 */
12553 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
12554 Log4(("CRX CR0 write rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr0));
12555 break;
12556 case 2: /* CR2 */
12557 /* Nothing to do here, CR2 it's not part of the VMCS. */
12558 break;
12559 case 3: /* CR3 */
12560 Assert(!pVM->hm.s.fNestedPaging || !CPUMIsGuestPagingEnabledEx(pMixedCtx) || pVCpu->hm.s.fUsingDebugLoop);
12561 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR3);
12562 Log4(("CRX CR3 write rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr3));
12563 break;
12564 case 4: /* CR4 */
12565 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
12566 Log4(("CRX CR4 write rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n",
12567 VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->cr4, pVCpu->hm.s.fLoadSaveGuestXcr0));
12568 break;
12569 case 8: /* CR8 */
12570 Assert(!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW));
12571 /* CR8 contains the APIC TPR. Was updated by IEMExecDecodedMovCRxWrite(). */
12572 HMCPU_CF_SET(pVCpu, HM_CHANGED_VMX_GUEST_APIC_STATE);
12573 break;
12574 default:
12575 AssertMsgFailed(("Invalid CRx register %#x\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)));
12576 break;
12577 }
12578
12579 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxWrite[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
12580 break;
12581 }
12582
12583 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ: /* MOV from CRx */
12584 {
12585 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12586 AssertRCReturn(rc, rc);
12587
12588 Assert( !pVM->hm.s.fNestedPaging
12589 || !CPUMIsGuestPagingEnabledEx(pMixedCtx)
12590 || pVCpu->hm.s.fUsingDebugLoop
12591 || VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification) != 3);
12592
12593 /* CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
12594 Assert( VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification) != 8
12595 || !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW));
12596
12597 rcStrict = IEMExecDecodedMovCRxRead(pVCpu, pVmxTransient->cbInstr,
12598 VMX_EXIT_QUALIFICATION_CRX_GENREG(uExitQualification),
12599 VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification));
12600 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12601 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxRead[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
12602 Log4(("CRX CR%d Read access rcStrict=%Rrc\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification),
12603 VBOXSTRICTRC_VAL(rcStrict)));
12604 break;
12605 }
12606
12607 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_CLTS: /* CLTS (Clear Task-Switch Flag in CR0) */
12608 {
12609 AssertRCReturn(rc, rc);
12610 rcStrict = IEMExecDecodedClts(pVCpu, pVmxTransient->cbInstr);
12611 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12612 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
12613 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
12614 Log4(("CRX CLTS rcStrict=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
12615 break;
12616 }
12617
12618 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
12619 {
12620 AssertRCReturn(rc, rc);
12621 rcStrict = IEMExecDecodedLmsw(pVCpu, pVmxTransient->cbInstr,
12622 VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(uExitQualification));
12623 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IEM_RAISED_XCPT || rcStrict == VINF_PGM_CHANGE_MODE,
12624 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12625 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
12626 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
12627 Log4(("CRX LMSW rcStrict=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
12628 break;
12629 }
12630
12631 default:
12632 AssertMsgFailedReturn(("Invalid access-type in Mov CRx VM-exit qualification %#x\n", uAccessType),
12633 VERR_VMX_UNEXPECTED_EXCEPTION);
12634 }
12635
12636 HMCPU_CF_SET(pVCpu, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS : HM_CHANGED_ALL_GUEST);
12637 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
12638 NOREF(pVM);
12639 return rcStrict;
12640}
12641
12642
12643/**
12644 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
12645 * VM-exit.
12646 */
12647HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12648{
12649 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12650 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
12651
12652 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12653 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
12654 rc |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
12655 rc |= hmR0VmxSaveGuestRflags(pVCpu, pMixedCtx); /* Eflag checks in EMInterpretDisasCurrent(). */
12656 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx); /* CR0 checks & PGM* in EMInterpretDisasCurrent(). */
12657 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* SELM checks in EMInterpretDisasCurrent(). */
12658 /* EFER also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
12659 AssertRCReturn(rc, rc);
12660
12661 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
12662 uint32_t uIOPort = VMX_EXIT_QUALIFICATION_IO_PORT(pVmxTransient->uExitQualification);
12663 uint8_t uIOWidth = VMX_EXIT_QUALIFICATION_IO_WIDTH(pVmxTransient->uExitQualification);
12664 bool fIOWrite = ( VMX_EXIT_QUALIFICATION_IO_DIRECTION(pVmxTransient->uExitQualification)
12665 == VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT);
12666 bool fIOString = VMX_EXIT_QUALIFICATION_IO_IS_STRING(pVmxTransient->uExitQualification);
12667 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
12668 bool fDbgStepping = pVCpu->hm.s.fSingleInstruction;
12669 AssertReturn(uIOWidth <= 3 && uIOWidth != 2, VERR_VMX_IPE_1);
12670
12671 /* I/O operation lookup arrays. */
12672 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses. */
12673 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving the result (in AL/AX/EAX). */
12674
12675 VBOXSTRICTRC rcStrict;
12676 uint32_t const cbValue = s_aIOSizes[uIOWidth];
12677 uint32_t const cbInstr = pVmxTransient->cbInstr;
12678 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
12679 PVM pVM = pVCpu->CTX_SUFF(pVM);
12680 if (fIOString)
12681 {
12682#ifdef VBOX_WITH_2ND_IEM_STEP /* This used to gurus with debian 32-bit guest without NP (on ATA reads).
12683 See @bugref{5752#c158}. Should work now. */
12684 /*
12685 * INS/OUTS - I/O String instruction.
12686 *
12687 * Use instruction-information if available, otherwise fall back on
12688 * interpreting the instruction.
12689 */
12690 Log4(("CS:RIP=%04x:%08RX64 %#06x/%u %c str\n", pMixedCtx->cs.Sel, pMixedCtx->rip, uIOPort, cbValue,
12691 fIOWrite ? 'w' : 'r'));
12692 AssertReturn(pMixedCtx->dx == uIOPort, VERR_VMX_IPE_2);
12693 if (MSR_IA32_VMX_BASIC_INFO_VMCS_INS_OUTS(pVM->hm.s.vmx.Msrs.u64BasicInfo))
12694 {
12695 int rc2 = hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12696 /** @todo optimize this, IEM should request the additional state if it needs it (GP, PF, ++). */
12697 rc2 |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12698 AssertRCReturn(rc2, rc2);
12699 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
12700 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
12701 IEMMODE enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
12702 bool fRep = VMX_EXIT_QUALIFICATION_IO_IS_REP(pVmxTransient->uExitQualification);
12703 if (fIOWrite)
12704 {
12705 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
12706 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
12707 }
12708 else
12709 {
12710 /*
12711 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
12712 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
12713 * See Intel Instruction spec. for "INS".
12714 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
12715 */
12716 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
12717 }
12718 }
12719 else
12720 {
12721 /** @todo optimize this, IEM should request the additional state if it needs it (GP, PF, ++). */
12722 int rc2 = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12723 AssertRCReturn(rc2, rc2);
12724 rcStrict = IEMExecOne(pVCpu);
12725 }
12726 /** @todo IEM needs to be setting these flags somehow. */
12727 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
12728 fUpdateRipAlready = true;
12729#else
12730 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
12731 rcStrict = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL /* pcbInstr */);
12732 if (RT_SUCCESS(rcStrict))
12733 {
12734 if (fIOWrite)
12735 {
12736 rcStrict = IOMInterpretOUTSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix,
12737 (DISCPUMODE)pDis->uAddrMode, cbValue);
12738 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringWrite);
12739 }
12740 else
12741 {
12742 rcStrict = IOMInterpretINSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix,
12743 (DISCPUMODE)pDis->uAddrMode, cbValue);
12744 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringRead);
12745 }
12746 }
12747 else
12748 {
12749 AssertMsg(rcStrict == VERR_EM_INTERPRETER, ("rcStrict=%Rrc RIP=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict),
12750 pMixedCtx->rip));
12751 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
12752 }
12753#endif
12754 }
12755 else
12756 {
12757 /*
12758 * IN/OUT - I/O instruction.
12759 */
12760 Log4(("CS:RIP=%04x:%08RX64 %#06x/%u %c\n", pMixedCtx->cs.Sel, pMixedCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
12761 uint32_t const uAndVal = s_aIOOpAnd[uIOWidth];
12762 Assert(!VMX_EXIT_QUALIFICATION_IO_IS_REP(pVmxTransient->uExitQualification));
12763 if (fIOWrite)
12764 {
12765 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pMixedCtx->eax & uAndVal, cbValue);
12766 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
12767 }
12768 else
12769 {
12770 uint32_t u32Result = 0;
12771 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
12772 if (IOM_SUCCESS(rcStrict))
12773 {
12774 /* Save result of I/O IN instr. in AL/AX/EAX. */
12775 pMixedCtx->eax = (pMixedCtx->eax & ~uAndVal) | (u32Result & uAndVal);
12776 }
12777 else if (rcStrict == VINF_IOM_R3_IOPORT_READ)
12778 HMR0SavePendingIOPortRead(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbValue);
12779 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
12780 }
12781 }
12782
12783 if (IOM_SUCCESS(rcStrict))
12784 {
12785 if (!fUpdateRipAlready)
12786 {
12787 hmR0VmxAdvanceGuestRipBy(pVCpu, pMixedCtx, cbInstr);
12788 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
12789 }
12790
12791 /*
12792 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru while booting Fedora 17 64-bit guest.
12793 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
12794 */
12795 if (fIOString)
12796 {
12797 /** @todo Single-step for INS/OUTS with REP prefix? */
12798 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
12799 }
12800 else if ( !fDbgStepping
12801 && fGstStepping)
12802 {
12803 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
12804 }
12805
12806 /*
12807 * If any I/O breakpoints are armed, we need to check if one triggered
12808 * and take appropriate action.
12809 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
12810 */
12811 int rc2 = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
12812 AssertRCReturn(rc2, rc2);
12813
12814 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
12815 * execution engines about whether hyper BPs and such are pending. */
12816 uint32_t const uDr7 = pMixedCtx->dr[7];
12817 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
12818 && X86_DR7_ANY_RW_IO(uDr7)
12819 && (pMixedCtx->cr4 & X86_CR4_DE))
12820 || DBGFBpIsHwIoArmed(pVM)))
12821 {
12822 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
12823
12824 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
12825 VMMRZCallRing3Disable(pVCpu);
12826 HM_DISABLE_PREEMPT();
12827
12828 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
12829
12830 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pMixedCtx, uIOPort, cbValue);
12831 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
12832 {
12833 /* Raise #DB. */
12834 if (fIsGuestDbgActive)
12835 ASMSetDR6(pMixedCtx->dr[6]);
12836 if (pMixedCtx->dr[7] != uDr7)
12837 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
12838
12839 hmR0VmxSetPendingXcptDB(pVCpu, pMixedCtx);
12840 }
12841 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
12842 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
12843 else if ( rcStrict2 != VINF_SUCCESS
12844 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
12845 rcStrict = rcStrict2;
12846 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
12847
12848 HM_RESTORE_PREEMPT();
12849 VMMRZCallRing3Enable(pVCpu);
12850 }
12851 }
12852
12853#ifdef VBOX_STRICT
12854 if (rcStrict == VINF_IOM_R3_IOPORT_READ)
12855 Assert(!fIOWrite);
12856 else if (rcStrict == VINF_IOM_R3_IOPORT_WRITE || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE)
12857 Assert(fIOWrite);
12858 else
12859 {
12860#if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
12861 * statuses, that the VMM device and some others may return. See
12862 * IOM_SUCCESS() for guidance. */
12863 AssertMsg( RT_FAILURE(rcStrict)
12864 || rcStrict == VINF_SUCCESS
12865 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
12866 || rcStrict == VINF_EM_DBG_BREAKPOINT
12867 || rcStrict == VINF_EM_RAW_GUEST_TRAP
12868 || rcStrict == VINF_EM_RAW_TO_R3
12869 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
12870#endif
12871 }
12872#endif
12873
12874 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
12875 return rcStrict;
12876}
12877
12878
12879/**
12880 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
12881 * VM-exit.
12882 */
12883HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12884{
12885 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12886
12887 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
12888 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12889 AssertRCReturn(rc, rc);
12890 if (VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_IDT)
12891 {
12892 rc = hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
12893 AssertRCReturn(rc, rc);
12894 if (VMX_IDT_VECTORING_INFO_VALID(pVmxTransient->uIdtVectoringInfo))
12895 {
12896 uint32_t uIntType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo);
12897
12898 uint32_t uVector = VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo);
12899 bool fErrorCodeValid = VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo);
12900
12901 /* Save it as a pending event and it'll be converted to a TRPM event on the way out to ring-3. */
12902 Assert(!pVCpu->hm.s.Event.fPending);
12903 pVCpu->hm.s.Event.fPending = true;
12904 pVCpu->hm.s.Event.u64IntInfo = pVmxTransient->uIdtVectoringInfo;
12905 rc = hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
12906 AssertRCReturn(rc, rc);
12907 if (fErrorCodeValid)
12908 pVCpu->hm.s.Event.u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
12909 else
12910 pVCpu->hm.s.Event.u32ErrCode = 0;
12911 if ( uIntType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
12912 && uVector == X86_XCPT_PF)
12913 {
12914 pVCpu->hm.s.Event.GCPtrFaultAddress = pMixedCtx->cr2;
12915 }
12916
12917 Log4(("Pending event on TaskSwitch uIntType=%#x uVector=%#x\n", uIntType, uVector));
12918 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
12919 return VINF_EM_RAW_INJECT_TRPM_EVENT;
12920 }
12921 }
12922
12923 /* Fall back to the interpreter to emulate the task-switch. */
12924 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
12925 return VERR_EM_INTERPRETER;
12926}
12927
12928
12929/**
12930 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
12931 */
12932HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12933{
12934 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12935 Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG);
12936 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG;
12937 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
12938 AssertRCReturn(rc, rc);
12939 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMtf);
12940 return VINF_EM_DBG_STEPPED;
12941}
12942
12943
12944/**
12945 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
12946 */
12947HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
12948{
12949 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
12950
12951 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
12952
12953 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
12954 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
12955 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
12956 {
12957 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
12958 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
12959 {
12960 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
12961 return VERR_EM_INTERPRETER;
12962 }
12963 }
12964 else
12965 {
12966 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
12967 rcStrict1 = VINF_SUCCESS;
12968 return rcStrict1;
12969 }
12970
12971#if 0
12972 /** @todo Investigate if IOMMMIOPhysHandler() requires a lot of state, for now
12973 * just sync the whole thing. */
12974 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
12975#else
12976 /* Aggressive state sync. for now. */
12977 int rc = hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
12978 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
12979 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
12980#endif
12981 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
12982 AssertRCReturn(rc, rc);
12983
12984 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
12985 uint32_t uAccessType = VMX_EXIT_QUALIFICATION_APIC_ACCESS_TYPE(pVmxTransient->uExitQualification);
12986 VBOXSTRICTRC rcStrict2;
12987 switch (uAccessType)
12988 {
12989 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
12990 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
12991 {
12992 AssertMsg( !(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW)
12993 || VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification) != XAPIC_OFF_TPR,
12994 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
12995
12996 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64MsrApicBase; /* Always up-to-date, u64MsrApicBase is not part of the VMCS. */
12997 GCPhys &= PAGE_BASE_GC_MASK;
12998 GCPhys += VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification);
12999 PVM pVM = pVCpu->CTX_SUFF(pVM);
13000 Log4(("ApicAccess uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
13001 VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(pVmxTransient->uExitQualification)));
13002
13003 rcStrict2 = IOMMMIOPhysHandler(pVM, pVCpu,
13004 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW,
13005 CPUMCTX2CORE(pMixedCtx), GCPhys);
13006 Log4(("ApicAccess rcStrict2=%d\n", VBOXSTRICTRC_VAL(rcStrict2)));
13007 if ( rcStrict2 == VINF_SUCCESS
13008 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
13009 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
13010 {
13011 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13012 | HM_CHANGED_GUEST_RSP
13013 | HM_CHANGED_GUEST_RFLAGS
13014 | HM_CHANGED_VMX_GUEST_APIC_STATE);
13015 rcStrict2 = VINF_SUCCESS;
13016 }
13017 break;
13018 }
13019
13020 default:
13021 Log4(("ApicAccess uAccessType=%#x\n", uAccessType));
13022 rcStrict2 = VINF_EM_RAW_EMULATE_INSTR;
13023 break;
13024 }
13025
13026 if (rcStrict2 != VINF_SUCCESS)
13027 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
13028 return rcStrict2;
13029}
13030
13031
13032/**
13033 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
13034 * VM-exit.
13035 */
13036HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13037{
13038 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
13039
13040 /* We should -not- get this VM-exit if the guest's debug registers were active. */
13041 if (pVmxTransient->fWasGuestDebugStateActive)
13042 {
13043 AssertMsgFailed(("Unexpected MOV DRx exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
13044 HMVMX_RETURN_UNEXPECTED_EXIT();
13045 }
13046
13047 if ( !pVCpu->hm.s.fSingleInstruction
13048 && !pVmxTransient->fWasHyperDebugStateActive)
13049 {
13050 Assert(!DBGFIsStepping(pVCpu));
13051 Assert(pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT_32(X86_XCPT_DB));
13052
13053 /* Don't intercept MOV DRx any more. */
13054 pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT;
13055 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);
13056 AssertRCReturn(rc, rc);
13057
13058 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
13059 VMMRZCallRing3Disable(pVCpu);
13060 HM_DISABLE_PREEMPT();
13061
13062 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
13063 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
13064 Assert(CPUMIsGuestDebugStateActive(pVCpu) || HC_ARCH_BITS == 32);
13065
13066 HM_RESTORE_PREEMPT();
13067 VMMRZCallRing3Enable(pVCpu);
13068
13069#ifdef VBOX_WITH_STATISTICS
13070 rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
13071 AssertRCReturn(rc, rc);
13072 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
13073 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
13074 else
13075 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
13076#endif
13077 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
13078 return VINF_SUCCESS;
13079 }
13080
13081 /*
13082 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER, CS. EFER is always up-to-date.
13083 * Update the segment registers and DR7 from the CPU.
13084 */
13085 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
13086 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
13087 rc |= hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
13088 AssertRCReturn(rc, rc);
13089 Log4(("CS:RIP=%04x:%08RX64\n", pMixedCtx->cs.Sel, pMixedCtx->rip));
13090
13091 PVM pVM = pVCpu->CTX_SUFF(pVM);
13092 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
13093 {
13094 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
13095 VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification),
13096 VMX_EXIT_QUALIFICATION_DRX_GENREG(pVmxTransient->uExitQualification));
13097 if (RT_SUCCESS(rc))
13098 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
13099 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
13100 }
13101 else
13102 {
13103 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx),
13104 VMX_EXIT_QUALIFICATION_DRX_GENREG(pVmxTransient->uExitQualification),
13105 VMX_EXIT_QUALIFICATION_DRX_REGISTER(pVmxTransient->uExitQualification));
13106 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
13107 }
13108
13109 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
13110 if (RT_SUCCESS(rc))
13111 {
13112 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
13113 AssertRCReturn(rc2, rc2);
13114 return VINF_SUCCESS;
13115 }
13116 return rc;
13117}
13118
13119
13120/**
13121 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
13122 * Conditional VM-exit.
13123 */
13124HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13125{
13126 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
13127 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
13128
13129 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
13130 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
13131 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
13132 {
13133 /* If event delivery causes an EPT misconfig (MMIO), go back to instruction emulation as otherwise
13134 injecting the original pending event would most likely cause the same EPT misconfig VM-exit. */
13135 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
13136 {
13137 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
13138 return VERR_EM_INTERPRETER;
13139 }
13140 }
13141 else
13142 {
13143 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
13144 rcStrict1 = VINF_SUCCESS;
13145 return rcStrict1;
13146 }
13147
13148 RTGCPHYS GCPhys = 0;
13149 int rc = VMXReadVmcs64(VMX_VMCS64_EXIT_GUEST_PHYS_ADDR_FULL, &GCPhys);
13150
13151#if 0
13152 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx); /** @todo Can we do better? */
13153#else
13154 /* Aggressive state sync. for now. */
13155 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
13156 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
13157 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
13158#endif
13159 AssertRCReturn(rc, rc);
13160
13161 /*
13162 * If we succeed, resume guest execution.
13163 * If we fail in interpreting the instruction because we couldn't get the guest physical address
13164 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
13165 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
13166 * weird case. See @bugref{6043}.
13167 */
13168 PVM pVM = pVCpu->CTX_SUFF(pVM);
13169 VBOXSTRICTRC rcStrict2 = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pMixedCtx), GCPhys, UINT32_MAX);
13170 Log4(("EPT misconfig at %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pMixedCtx->rip, VBOXSTRICTRC_VAL(rcStrict2)));
13171 if ( rcStrict2 == VINF_SUCCESS
13172 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
13173 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
13174 {
13175 /* Successfully handled MMIO operation. */
13176 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13177 | HM_CHANGED_GUEST_RSP
13178 | HM_CHANGED_GUEST_RFLAGS
13179 | HM_CHANGED_VMX_GUEST_APIC_STATE);
13180 return VINF_SUCCESS;
13181 }
13182 return rcStrict2;
13183}
13184
13185
13186/**
13187 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
13188 * VM-exit.
13189 */
13190HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13191{
13192 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
13193 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
13194
13195 /* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
13196 VBOXSTRICTRC rcStrict1 = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pMixedCtx, pVmxTransient);
13197 if (RT_LIKELY(rcStrict1 == VINF_SUCCESS))
13198 {
13199 /* In the unlikely case that the EPT violation happened as a result of delivering an event, log it. */
13200 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
13201 Log4(("EPT violation with an event pending u64IntInfo=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo));
13202 }
13203 else
13204 {
13205 if (rcStrict1 == VINF_HM_DOUBLE_FAULT)
13206 rcStrict1 = VINF_SUCCESS;
13207 return rcStrict1;
13208 }
13209
13210 RTGCPHYS GCPhys = 0;
13211 int rc = VMXReadVmcs64(VMX_VMCS64_EXIT_GUEST_PHYS_ADDR_FULL, &GCPhys);
13212 rc |= hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
13213#if 0
13214 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx); /** @todo Can we do better? */
13215#else
13216 /* Aggressive state sync. for now. */
13217 rc |= hmR0VmxSaveGuestRipRspRflags(pVCpu, pMixedCtx);
13218 rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx);
13219 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
13220#endif
13221 AssertRCReturn(rc, rc);
13222
13223 /* Intel spec. Table 27-7 "Exit Qualifications for EPT violations". */
13224 AssertMsg(((pVmxTransient->uExitQualification >> 7) & 3) != 2, ("%#RX64", pVmxTransient->uExitQualification));
13225
13226 RTGCUINT uErrorCode = 0;
13227 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_INSTR_FETCH)
13228 uErrorCode |= X86_TRAP_PF_ID;
13229 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_DATA_WRITE)
13230 uErrorCode |= X86_TRAP_PF_RW;
13231 if (pVmxTransient->uExitQualification & VMX_EXIT_QUALIFICATION_EPT_ENTRY_PRESENT)
13232 uErrorCode |= X86_TRAP_PF_P;
13233
13234 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
13235
13236 Log4(("EPT violation %#x at %#RX64 ErrorCode %#x CS:RIP=%04x:%08RX64\n", pVmxTransient->uExitQualification, GCPhys,
13237 uErrorCode, pMixedCtx->cs.Sel, pMixedCtx->rip));
13238
13239 /* Handle the pagefault trap for the nested shadow table. */
13240 PVM pVM = pVCpu->CTX_SUFF(pVM);
13241 VBOXSTRICTRC rcStrict2 = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pMixedCtx), GCPhys);
13242 TRPMResetTrap(pVCpu);
13243
13244 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
13245 if ( rcStrict2 == VINF_SUCCESS
13246 || rcStrict2 == VERR_PAGE_TABLE_NOT_PRESENT
13247 || rcStrict2 == VERR_PAGE_NOT_PRESENT)
13248 {
13249 /* Successfully synced our nested page tables. */
13250 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
13251 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13252 | HM_CHANGED_GUEST_RSP
13253 | HM_CHANGED_GUEST_RFLAGS);
13254 return VINF_SUCCESS;
13255 }
13256
13257 Log4(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)));
13258 return rcStrict2;
13259}
13260
13261/** @} */
13262
13263/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13264/* -=-=-=-=-=-=-=-=-=- VM-exit Exception Handlers -=-=-=-=-=-=-=-=-=-=- */
13265/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13266
13267/** @name VM-exit exception handlers.
13268 * @{
13269 */
13270
13271/**
13272 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
13273 */
13274static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13275{
13276 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13277 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
13278
13279 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
13280 AssertRCReturn(rc, rc);
13281
13282 if (!(pMixedCtx->cr0 & X86_CR0_NE))
13283 {
13284 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
13285 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
13286
13287 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
13288 * provides VM-exit instruction length. If this causes problem later,
13289 * disassemble the instruction like it's done on AMD-V. */
13290 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
13291 AssertRCReturn(rc2, rc2);
13292 return rc;
13293 }
13294
13295 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13296 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13297 return rc;
13298}
13299
13300
13301/**
13302 * VM-exit exception handler for \#BP (Breakpoint exception).
13303 */
13304static int hmR0VmxExitXcptBP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13305{
13306 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13307 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
13308
13309 /** @todo Try optimize this by not saving the entire guest state unless
13310 * really needed. */
13311 int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13312 AssertRCReturn(rc, rc);
13313
13314 PVM pVM = pVCpu->CTX_SUFF(pVM);
13315 rc = DBGFRZTrap03Handler(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx));
13316 if (rc == VINF_EM_RAW_GUEST_TRAP)
13317 {
13318 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13319 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13320 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13321 AssertRCReturn(rc, rc);
13322
13323 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13324 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13325 }
13326
13327 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_EM_DBG_BREAKPOINT);
13328 return rc;
13329}
13330
13331
13332/**
13333 * VM-exit exception handler for \#AC (alignment check exception).
13334 */
13335static int hmR0VmxExitXcptAC(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13336{
13337 RT_NOREF_PV(pMixedCtx);
13338 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13339
13340 /*
13341 * Re-inject it. We'll detect any nesting before getting here.
13342 */
13343 int rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13344 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13345 AssertRCReturn(rc, rc);
13346 Assert(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO);
13347
13348 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13349 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13350 return VINF_SUCCESS;
13351}
13352
13353
13354/**
13355 * VM-exit exception handler for \#DB (Debug exception).
13356 */
13357static int hmR0VmxExitXcptDB(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13358{
13359 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13360 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
13361 Log6(("XcptDB\n"));
13362
13363 /*
13364 * Get the DR6-like values from the VM-exit qualification and pass it to DBGF
13365 * for processing.
13366 */
13367 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
13368 AssertRCReturn(rc, rc);
13369
13370 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
13371 uint64_t uDR6 = X86_DR6_INIT_VAL;
13372 uDR6 |= ( pVmxTransient->uExitQualification
13373 & (X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3 | X86_DR6_BD | X86_DR6_BS));
13374
13375 rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pMixedCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
13376 if (rc == VINF_EM_RAW_GUEST_TRAP)
13377 {
13378 /*
13379 * The exception was for the guest. Update DR6, DR7.GD and
13380 * IA32_DEBUGCTL.LBR before forwarding it.
13381 * (See Intel spec. 27.1 "Architectural State before a VM-Exit".)
13382 */
13383 VMMRZCallRing3Disable(pVCpu);
13384 HM_DISABLE_PREEMPT();
13385
13386 pMixedCtx->dr[6] &= ~X86_DR6_B_MASK;
13387 pMixedCtx->dr[6] |= uDR6;
13388 if (CPUMIsGuestDebugStateActive(pVCpu))
13389 ASMSetDR6(pMixedCtx->dr[6]);
13390
13391 HM_RESTORE_PREEMPT();
13392 VMMRZCallRing3Enable(pVCpu);
13393
13394 rc = hmR0VmxSaveGuestDR7(pVCpu, pMixedCtx);
13395 AssertRCReturn(rc, rc);
13396
13397 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
13398 pMixedCtx->dr[7] &= ~X86_DR7_GD;
13399
13400 /* Paranoia. */
13401 pMixedCtx->dr[7] &= ~X86_DR7_RAZ_MASK;
13402 pMixedCtx->dr[7] |= X86_DR7_RA1_MASK;
13403
13404 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_DR7, (uint32_t)pMixedCtx->dr[7]);
13405 AssertRCReturn(rc, rc);
13406
13407 /*
13408 * Raise #DB in the guest.
13409 *
13410 * It is important to reflect what the VM-exit gave us (preserving the interruption-type) rather than use
13411 * hmR0VmxSetPendingXcptDB() as the #DB could've been raised while executing ICEBP and not the 'normal' #DB.
13412 * Thus it -may- trigger different handling in the CPU (like skipped DPL checks). See @bugref{6398}.
13413 *
13414 * Since ICEBP isn't documented on Intel, see AMD spec. 15.20 "Event Injection".
13415 */
13416 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13417 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13418 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13419 AssertRCReturn(rc, rc);
13420 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13421 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13422 return VINF_SUCCESS;
13423 }
13424
13425 /*
13426 * Not a guest trap, must be a hypervisor related debug event then.
13427 * Update DR6 in case someone is interested in it.
13428 */
13429 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
13430 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
13431 CPUMSetHyperDR6(pVCpu, uDR6);
13432
13433 return rc;
13434}
13435
13436
13437/**
13438 * VM-exit exception handler for \#NM (Device-not-available exception: floating
13439 * point exception).
13440 */
13441static int hmR0VmxExitXcptNM(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13442{
13443 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13444
13445 /* We require CR0 and EFER. EFER is always up-to-date. */
13446 int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
13447 AssertRCReturn(rc, rc);
13448
13449 /* We're playing with the host CPU state here, have to disable preemption or longjmp. */
13450 VMMRZCallRing3Disable(pVCpu);
13451 HM_DISABLE_PREEMPT();
13452
13453 /* If the guest FPU was active at the time of the #NM VM-exit, then it's a guest fault. */
13454 if (pVmxTransient->fWasGuestFPUStateActive)
13455 {
13456 rc = VINF_EM_RAW_GUEST_TRAP;
13457 Assert(CPUMIsGuestFPUStateActive(pVCpu) || HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0));
13458 }
13459 else
13460 {
13461#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13462 Assert(!pVmxTransient->fWasGuestFPUStateActive || pVCpu->hm.s.fUsingDebugLoop);
13463#endif
13464 rc = CPUMR0Trap07Handler(pVCpu->CTX_SUFF(pVM), pVCpu);
13465 Assert( rc == VINF_EM_RAW_GUEST_TRAP
13466 || ((rc == VINF_SUCCESS || rc == VINF_CPUM_HOST_CR0_MODIFIED) && CPUMIsGuestFPUStateActive(pVCpu)));
13467 if (rc == VINF_CPUM_HOST_CR0_MODIFIED)
13468 HMCPU_CF_SET(pVCpu, HM_CHANGED_HOST_CONTEXT);
13469 }
13470
13471 HM_RESTORE_PREEMPT();
13472 VMMRZCallRing3Enable(pVCpu);
13473
13474 if (rc == VINF_SUCCESS || rc == VINF_CPUM_HOST_CR0_MODIFIED)
13475 {
13476 /* Guest FPU state was activated, we'll want to change CR0 FPU intercepts before the next VM-reentry. */
13477 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
13478 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowNM);
13479 pVCpu->hm.s.fPreloadGuestFpu = true;
13480 }
13481 else
13482 {
13483 /* Forward #NM to the guest. */
13484 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
13485 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13486 AssertRCReturn(rc, rc);
13487 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13488 pVmxTransient->cbInstr, 0 /* error code */, 0 /* GCPtrFaultAddress */);
13489 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNM);
13490 }
13491
13492 return VINF_SUCCESS;
13493}
13494
13495
13496/**
13497 * VM-exit exception handler for \#GP (General-protection exception).
13498 *
13499 * @remarks Requires pVmxTransient->uExitIntInfo to be up-to-date.
13500 */
13501static int hmR0VmxExitXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13502{
13503 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13504 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
13505
13506 int rc;
13507 if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active)
13508 { /* likely */ }
13509 else
13510 {
13511#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13512 Assert(pVCpu->hm.s.fUsingDebugLoop);
13513#endif
13514 /* If the guest is not in real-mode or we have unrestricted execution support, reflect #GP to the guest. */
13515 rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13516 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13517 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13518 rc |= hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13519 AssertRCReturn(rc, rc);
13520 Log4(("#GP Gst: CS:RIP %04x:%08RX64 ErrorCode=%#x CR0=%#RX64 CPL=%u TR=%#04x\n", pMixedCtx->cs.Sel, pMixedCtx->rip,
13521 pVmxTransient->uExitIntErrorCode, pMixedCtx->cr0, CPUMGetGuestCPL(pVCpu), pMixedCtx->tr.Sel));
13522 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13523 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13524 return rc;
13525 }
13526
13527 Assert(CPUMIsGuestInRealModeEx(pMixedCtx));
13528 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUnrestrictedGuest);
13529
13530 /* EMInterpretDisasCurrent() requires a lot of the state, save the entire state. */
13531 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13532 AssertRCReturn(rc, rc);
13533
13534 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
13535 uint32_t cbOp = 0;
13536 PVM pVM = pVCpu->CTX_SUFF(pVM);
13537 bool fDbgStepping = pVCpu->hm.s.fSingleInstruction;
13538 rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, &cbOp);
13539 if (RT_SUCCESS(rc))
13540 {
13541 rc = VINF_SUCCESS;
13542 Assert(cbOp == pDis->cbInstr);
13543 Log4(("#GP Disas OpCode=%u CS:EIP %04x:%04RX64\n", pDis->pCurInstr->uOpcode, pMixedCtx->cs.Sel, pMixedCtx->rip));
13544 switch (pDis->pCurInstr->uOpcode)
13545 {
13546 case OP_CLI:
13547 {
13548 pMixedCtx->eflags.Bits.u1IF = 0;
13549 pMixedCtx->eflags.Bits.u1RF = 0;
13550 pMixedCtx->rip += pDis->cbInstr;
13551 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13552 if ( !fDbgStepping
13553 && pMixedCtx->eflags.Bits.u1TF)
13554 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13555 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCli);
13556 break;
13557 }
13558
13559 case OP_STI:
13560 {
13561 bool fOldIF = pMixedCtx->eflags.Bits.u1IF;
13562 pMixedCtx->eflags.Bits.u1IF = 1;
13563 pMixedCtx->eflags.Bits.u1RF = 0;
13564 pMixedCtx->rip += pDis->cbInstr;
13565 if (!fOldIF)
13566 {
13567 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
13568 Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
13569 }
13570 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13571 if ( !fDbgStepping
13572 && pMixedCtx->eflags.Bits.u1TF)
13573 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13574 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitSti);
13575 break;
13576 }
13577
13578 case OP_HLT:
13579 {
13580 rc = VINF_EM_HALT;
13581 pMixedCtx->rip += pDis->cbInstr;
13582 pMixedCtx->eflags.Bits.u1RF = 0;
13583 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13584 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
13585 break;
13586 }
13587
13588 case OP_POPF:
13589 {
13590 Log4(("POPF CS:EIP %04x:%04RX64\n", pMixedCtx->cs.Sel, pMixedCtx->rip));
13591 uint32_t cbParm;
13592 uint32_t uMask;
13593 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
13594 if (pDis->fPrefix & DISPREFIX_OPSIZE)
13595 {
13596 cbParm = 4;
13597 uMask = 0xffffffff;
13598 }
13599 else
13600 {
13601 cbParm = 2;
13602 uMask = 0xffff;
13603 }
13604
13605 /* Get the stack pointer & pop the contents of the stack onto Eflags. */
13606 RTGCPTR GCPtrStack = 0;
13607 X86EFLAGS Eflags;
13608 Eflags.u32 = 0;
13609 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
13610 &GCPtrStack);
13611 if (RT_SUCCESS(rc))
13612 {
13613 Assert(sizeof(Eflags.u32) >= cbParm);
13614 rc = VBOXSTRICTRC_TODO(PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &Eflags.u32, cbParm, PGMACCESSORIGIN_HM));
13615 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc)); /** @todo allow strict return codes here */
13616 }
13617 if (RT_FAILURE(rc))
13618 {
13619 rc = VERR_EM_INTERPRETER;
13620 break;
13621 }
13622 Log4(("POPF %#x -> %#RX64 mask=%#x RIP=%#RX64\n", Eflags.u, pMixedCtx->rsp, uMask, pMixedCtx->rip));
13623 pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ~((X86_EFL_POPF_BITS & uMask) | X86_EFL_RF))
13624 | (Eflags.u32 & X86_EFL_POPF_BITS & uMask);
13625 pMixedCtx->esp += cbParm;
13626 pMixedCtx->esp &= uMask;
13627 pMixedCtx->rip += pDis->cbInstr;
13628 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13629 | HM_CHANGED_GUEST_RSP
13630 | HM_CHANGED_GUEST_RFLAGS);
13631 /* Generate a pending-debug exception when the guest stepping over POPF regardless of how
13632 POPF restores EFLAGS.TF. */
13633 if ( !fDbgStepping
13634 && fGstStepping)
13635 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13636 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPopf);
13637 break;
13638 }
13639
13640 case OP_PUSHF:
13641 {
13642 uint32_t cbParm;
13643 uint32_t uMask;
13644 if (pDis->fPrefix & DISPREFIX_OPSIZE)
13645 {
13646 cbParm = 4;
13647 uMask = 0xffffffff;
13648 }
13649 else
13650 {
13651 cbParm = 2;
13652 uMask = 0xffff;
13653 }
13654
13655 /* Get the stack pointer & push the contents of eflags onto the stack. */
13656 RTGCPTR GCPtrStack = 0;
13657 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), (pMixedCtx->esp - cbParm) & uMask,
13658 SELMTOFLAT_FLAGS_CPL0, &GCPtrStack);
13659 if (RT_FAILURE(rc))
13660 {
13661 rc = VERR_EM_INTERPRETER;
13662 break;
13663 }
13664 X86EFLAGS Eflags = pMixedCtx->eflags;
13665 /* The RF & VM bits are cleared on image stored on stack; see Intel Instruction reference for PUSHF. */
13666 Eflags.Bits.u1RF = 0;
13667 Eflags.Bits.u1VM = 0;
13668
13669 rc = VBOXSTRICTRC_TODO(PGMPhysWrite(pVM, (RTGCPHYS)GCPtrStack, &Eflags.u, cbParm, PGMACCESSORIGIN_HM));
13670 if (RT_UNLIKELY(rc != VINF_SUCCESS))
13671 {
13672 AssertMsgFailed(("%Rrc\n", rc)); /** @todo allow strict return codes here */
13673 rc = VERR_EM_INTERPRETER;
13674 break;
13675 }
13676 Log4(("PUSHF %#x -> %#RGv\n", Eflags.u, GCPtrStack));
13677 pMixedCtx->esp -= cbParm;
13678 pMixedCtx->esp &= uMask;
13679 pMixedCtx->rip += pDis->cbInstr;
13680 pMixedCtx->eflags.Bits.u1RF = 0;
13681 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13682 | HM_CHANGED_GUEST_RSP
13683 | HM_CHANGED_GUEST_RFLAGS);
13684 if ( !fDbgStepping
13685 && pMixedCtx->eflags.Bits.u1TF)
13686 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13687 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPushf);
13688 break;
13689 }
13690
13691 case OP_IRET:
13692 {
13693 /** @todo Handle 32-bit operand sizes and check stack limits. See Intel
13694 * instruction reference. */
13695 RTGCPTR GCPtrStack = 0;
13696 uint32_t uMask = 0xffff;
13697 bool fGstStepping = RT_BOOL(pMixedCtx->eflags.Bits.u1TF);
13698 uint16_t aIretFrame[3];
13699 if (pDis->fPrefix & (DISPREFIX_OPSIZE | DISPREFIX_ADDRSIZE))
13700 {
13701 rc = VERR_EM_INTERPRETER;
13702 break;
13703 }
13704 rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
13705 &GCPtrStack);
13706 if (RT_SUCCESS(rc))
13707 {
13708 rc = VBOXSTRICTRC_TODO(PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &aIretFrame[0], sizeof(aIretFrame),
13709 PGMACCESSORIGIN_HM));
13710 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc)); /** @todo allow strict return codes here */
13711 }
13712 if (RT_FAILURE(rc))
13713 {
13714 rc = VERR_EM_INTERPRETER;
13715 break;
13716 }
13717 pMixedCtx->eip = 0;
13718 pMixedCtx->ip = aIretFrame[0];
13719 pMixedCtx->cs.Sel = aIretFrame[1];
13720 pMixedCtx->cs.ValidSel = aIretFrame[1];
13721 pMixedCtx->cs.u64Base = (uint64_t)pMixedCtx->cs.Sel << 4;
13722 pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ((UINT32_C(0xffff0000) | X86_EFL_1) & ~X86_EFL_RF))
13723 | (aIretFrame[2] & X86_EFL_POPF_BITS & uMask);
13724 pMixedCtx->sp += sizeof(aIretFrame);
13725 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13726 | HM_CHANGED_GUEST_SEGMENT_REGS
13727 | HM_CHANGED_GUEST_RSP
13728 | HM_CHANGED_GUEST_RFLAGS);
13729 /* Generate a pending-debug exception when stepping over IRET regardless of how IRET modifies EFLAGS.TF. */
13730 if ( !fDbgStepping
13731 && fGstStepping)
13732 hmR0VmxSetPendingDebugXcptVmcs(pVCpu);
13733 Log4(("IRET %#RX32 to %04x:%04x\n", GCPtrStack, pMixedCtx->cs.Sel, pMixedCtx->ip));
13734 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIret);
13735 break;
13736 }
13737
13738 case OP_INT:
13739 {
13740 uint16_t uVector = pDis->Param1.uValue & 0xff;
13741 hmR0VmxSetPendingIntN(pVCpu, pMixedCtx, uVector, pDis->cbInstr);
13742 /* INT clears EFLAGS.TF, we must not set any pending debug exceptions here. */
13743 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
13744 break;
13745 }
13746
13747 case OP_INTO:
13748 {
13749 if (pMixedCtx->eflags.Bits.u1OF)
13750 {
13751 hmR0VmxSetPendingXcptOF(pVCpu, pMixedCtx, pDis->cbInstr);
13752 /* INTO clears EFLAGS.TF, we must not set any pending debug exceptions here. */
13753 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
13754 }
13755 else
13756 {
13757 pMixedCtx->eflags.Bits.u1RF = 0;
13758 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
13759 }
13760 break;
13761 }
13762
13763 default:
13764 {
13765 pMixedCtx->eflags.Bits.u1RF = 0; /* This is correct most of the time... */
13766 VBOXSTRICTRC rc2 = EMInterpretInstructionDisasState(pVCpu, pDis, CPUMCTX2CORE(pMixedCtx), 0 /* pvFault */,
13767 EMCODETYPE_SUPERVISOR);
13768 rc = VBOXSTRICTRC_VAL(rc2);
13769 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
13770 /** @todo We have to set pending-debug exceptions here when the guest is
13771 * single-stepping depending on the instruction that was interpreted. */
13772 Log4(("#GP rc=%Rrc\n", rc));
13773 break;
13774 }
13775 }
13776 }
13777 else
13778 rc = VERR_EM_INTERPRETER;
13779
13780 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_EM_HALT,
13781 ("#GP Unexpected rc=%Rrc\n", rc));
13782 return rc;
13783}
13784
13785
13786/**
13787 * VM-exit exception handler wrapper for generic exceptions. Simply re-injects
13788 * the exception reported in the VMX transient structure back into the VM.
13789 *
13790 * @remarks Requires uExitIntInfo in the VMX transient structure to be
13791 * up-to-date.
13792 */
13793static int hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13794{
13795 RT_NOREF_PV(pMixedCtx);
13796 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13797#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
13798 AssertMsg(pVCpu->hm.s.fUsingDebugLoop || pVCpu->hm.s.vmx.RealMode.fRealOnV86Active,
13799 ("uVector=%#04x u32XcptBitmap=%#010RX32\n",
13800 VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVCpu->hm.s.vmx.u32XcptBitmap));
13801#endif
13802
13803 /* Re-inject the exception into the guest. This cannot be a double-fault condition which would have been handled in
13804 hmR0VmxCheckExitDueToEventDelivery(). */
13805 int rc = hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13806 rc |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13807 AssertRCReturn(rc, rc);
13808 Assert(pVmxTransient->fVmcsFieldsRead & HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO);
13809
13810#ifdef DEBUG_ramshankar
13811 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);
13812 uint8_t uVector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVmxTransient->uExitIntInfo);
13813 Log(("hmR0VmxExitXcptGeneric: Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
13814#endif
13815
13816 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13817 pVmxTransient->cbInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
13818 return VINF_SUCCESS;
13819}
13820
13821
13822/**
13823 * VM-exit exception handler for \#PF (Page-fault exception).
13824 */
13825static int hmR0VmxExitXcptPF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
13826{
13827 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS();
13828 PVM pVM = pVCpu->CTX_SUFF(pVM);
13829 int rc = hmR0VmxReadExitQualificationVmcs(pVCpu, pVmxTransient);
13830 rc |= hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
13831 rc |= hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
13832 AssertRCReturn(rc, rc);
13833
13834 if (!pVM->hm.s.fNestedPaging)
13835 { /* likely */ }
13836 else
13837 {
13838#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13839 Assert(pVCpu->hm.s.fUsingDebugLoop);
13840#endif
13841 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13842 if (RT_LIKELY(!pVmxTransient->fVectoringDoublePF))
13843 {
13844 pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
13845 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13846 0 /* cbInstr */, pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQualification);
13847 }
13848 else
13849 {
13850 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13851 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
13852 Log4(("Pending #DF due to vectoring #PF. NP\n"));
13853 }
13854 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13855 return rc;
13856 }
13857
13858 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13859 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13860 if (pVmxTransient->fVectoringPF)
13861 {
13862 Assert(pVCpu->hm.s.Event.fPending);
13863 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13864 }
13865
13866 rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
13867 AssertRCReturn(rc, rc);
13868
13869 Log4(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQualification,
13870 pMixedCtx->cs.Sel, pMixedCtx->rip, pVmxTransient->uExitIntErrorCode, pMixedCtx->cr3));
13871
13872 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQualification, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13873 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pMixedCtx),
13874 (RTGCPTR)pVmxTransient->uExitQualification);
13875
13876 Log4(("#PF: rc=%Rrc\n", rc));
13877 if (rc == VINF_SUCCESS)
13878 {
13879#if 0
13880 /* Successfully synced shadow pages tables or emulated an MMIO instruction. */
13881 /** @todo this isn't quite right, what if guest does lgdt with some MMIO
13882 * memory? We don't update the whole state here... */
13883 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP
13884 | HM_CHANGED_GUEST_RSP
13885 | HM_CHANGED_GUEST_RFLAGS
13886 | HM_CHANGED_VMX_GUEST_APIC_STATE);
13887#else
13888 /*
13889 * This is typically a shadow page table sync or a MMIO instruction. But we may have
13890 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
13891 */
13892 /** @todo take advantage of CPUM changed flags instead of brute forcing. */
13893 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
13894#endif
13895 TRPMResetTrap(pVCpu);
13896 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
13897 return rc;
13898 }
13899
13900 if (rc == VINF_EM_RAW_GUEST_TRAP)
13901 {
13902 if (!pVmxTransient->fVectoringDoublePF)
13903 {
13904 /* It's a guest page fault and needs to be reflected to the guest. */
13905 uint32_t uGstErrorCode = TRPMGetErrorCode(pVCpu);
13906 TRPMResetTrap(pVCpu);
13907 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
13908 pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
13909 hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
13910 0 /* cbInstr */, uGstErrorCode, pVmxTransient->uExitQualification);
13911 }
13912 else
13913 {
13914 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13915 TRPMResetTrap(pVCpu);
13916 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
13917 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx);
13918 Log4(("#PF: Pending #DF due to vectoring #PF\n"));
13919 }
13920
13921 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13922 return VINF_SUCCESS;
13923 }
13924
13925 TRPMResetTrap(pVCpu);
13926 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
13927 return rc;
13928}
13929
13930/** @} */
13931
Note: See TracBrowser for help on using the repository browser.

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