VirtualBox

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

Last change on this file since 87551 was 87551, checked in by vboxsync, 4 years ago

VMM/HMVMX: cPleGapTicks/cPleWindowTicks merge todo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 732.6 KB
Line 
1/* $Id: HMVMXR0.cpp 87551 2021-02-03 10:07:37Z vboxsync $ */
2/** @file
3 * HM VMX (Intel VT-x) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2012-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_HM
23#define VMCPU_INCL_CPUM_GST_CTX
24#include <iprt/x86.h>
25#include <iprt/asm-amd64-x86.h>
26#include <iprt/thread.h>
27#include <iprt/mem.h>
28#include <iprt/mp.h>
29
30#include <VBox/vmm/pdmapi.h>
31#include <VBox/vmm/dbgf.h>
32#include <VBox/vmm/iem.h>
33#include <VBox/vmm/iom.h>
34#include <VBox/vmm/tm.h>
35#include <VBox/vmm/em.h>
36#include <VBox/vmm/gim.h>
37#include <VBox/vmm/apic.h>
38#include "HMInternal.h"
39#include <VBox/vmm/vmcc.h>
40#include <VBox/vmm/hmvmxinline.h>
41#include "HMVMXR0.h"
42#include "dtrace/VBoxVMM.h"
43
44#ifdef DEBUG_ramshankar
45# define HMVMX_ALWAYS_SAVE_GUEST_RFLAGS
46# define HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
47# define HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE
48# define HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
49# define HMVMX_ALWAYS_CLEAN_TRANSIENT
50# define HMVMX_ALWAYS_CHECK_GUEST_STATE
51# define HMVMX_ALWAYS_TRAP_ALL_XCPTS
52# define HMVMX_ALWAYS_TRAP_PF
53# define HMVMX_ALWAYS_FLUSH_TLB
54# define HMVMX_ALWAYS_SWAP_EFER
55#endif
56
57
58/*********************************************************************************************************************************
59* Defined Constants And Macros *
60*********************************************************************************************************************************/
61/** Use the function table. */
62#define HMVMX_USE_FUNCTION_TABLE
63
64/** Determine which tagged-TLB flush handler to use. */
65#define HMVMX_FLUSH_TAGGED_TLB_EPT_VPID 0
66#define HMVMX_FLUSH_TAGGED_TLB_EPT 1
67#define HMVMX_FLUSH_TAGGED_TLB_VPID 2
68#define HMVMX_FLUSH_TAGGED_TLB_NONE 3
69
70/**
71 * Flags to skip redundant reads of some common VMCS fields that are not part of
72 * the guest-CPU or VCPU state but are needed while handling VM-exits.
73 */
74#define HMVMX_READ_IDT_VECTORING_INFO RT_BIT_32(0)
75#define HMVMX_READ_IDT_VECTORING_ERROR_CODE RT_BIT_32(1)
76#define HMVMX_READ_EXIT_QUALIFICATION RT_BIT_32(2)
77#define HMVMX_READ_EXIT_INSTR_LEN RT_BIT_32(3)
78#define HMVMX_READ_EXIT_INTERRUPTION_INFO RT_BIT_32(4)
79#define HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE RT_BIT_32(5)
80#define HMVMX_READ_EXIT_INSTR_INFO RT_BIT_32(6)
81#define HMVMX_READ_GUEST_LINEAR_ADDR RT_BIT_32(7)
82#define HMVMX_READ_GUEST_PHYSICAL_ADDR RT_BIT_32(8)
83#define HMVMX_READ_GUEST_PENDING_DBG_XCPTS RT_BIT_32(9)
84
85/** All the VMCS fields required for processing of exception/NMI VM-exits. */
86#define HMVMX_READ_XCPT_INFO ( HMVMX_READ_EXIT_INTERRUPTION_INFO \
87 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \
88 | HMVMX_READ_EXIT_INSTR_LEN \
89 | HMVMX_READ_IDT_VECTORING_INFO \
90 | HMVMX_READ_IDT_VECTORING_ERROR_CODE)
91
92/** Assert that all the given fields have been read from the VMCS. */
93#ifdef VBOX_STRICT
94# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) \
95 do { \
96 uint32_t const fVmcsFieldRead = ASMAtomicUoReadU32(&pVmxTransient->fVmcsFieldsRead); \
97 Assert((fVmcsFieldRead & (a_fReadFields)) == (a_fReadFields)); \
98 } while (0)
99#else
100# define HMVMX_ASSERT_READ(a_pVmxTransient, a_fReadFields) do { } while (0)
101#endif
102
103/**
104 * Subset of the guest-CPU state that is kept by VMX R0 code while executing the
105 * guest using hardware-assisted VMX.
106 *
107 * This excludes state like GPRs (other than RSP) which are always are
108 * swapped and restored across the world-switch and also registers like EFER,
109 * MSR which cannot be modified by the guest without causing a VM-exit.
110 */
111#define HMVMX_CPUMCTX_EXTRN_ALL ( CPUMCTX_EXTRN_RIP \
112 | CPUMCTX_EXTRN_RFLAGS \
113 | CPUMCTX_EXTRN_RSP \
114 | CPUMCTX_EXTRN_SREG_MASK \
115 | CPUMCTX_EXTRN_TABLE_MASK \
116 | CPUMCTX_EXTRN_KERNEL_GS_BASE \
117 | CPUMCTX_EXTRN_SYSCALL_MSRS \
118 | CPUMCTX_EXTRN_SYSENTER_MSRS \
119 | CPUMCTX_EXTRN_TSC_AUX \
120 | CPUMCTX_EXTRN_OTHER_MSRS \
121 | CPUMCTX_EXTRN_CR0 \
122 | CPUMCTX_EXTRN_CR3 \
123 | CPUMCTX_EXTRN_CR4 \
124 | CPUMCTX_EXTRN_DR7 \
125 | CPUMCTX_EXTRN_HWVIRT \
126 | CPUMCTX_EXTRN_HM_VMX_MASK)
127
128/**
129 * Exception bitmap mask for real-mode guests (real-on-v86).
130 *
131 * We need to intercept all exceptions manually except:
132 * - \#AC and \#DB are always intercepted to prevent the CPU from deadlocking
133 * due to bugs in Intel CPUs.
134 * - \#PF need not be intercepted even in real-mode if we have nested paging
135 * support.
136 */
137#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) /* always: | RT_BIT(X86_XCPT_DB) */ | RT_BIT(X86_XCPT_NMI) \
138 | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
139 | RT_BIT(X86_XCPT_UD) | RT_BIT(X86_XCPT_NM) | RT_BIT(X86_XCPT_DF) \
140 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
141 | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
142 | RT_BIT(X86_XCPT_MF) /* always: | RT_BIT(X86_XCPT_AC) */ | RT_BIT(X86_XCPT_MC) \
143 | RT_BIT(X86_XCPT_XF))
144
145/** Maximum VM-instruction error number. */
146#define HMVMX_INSTR_ERROR_MAX 28
147
148/** Profiling macro. */
149#ifdef HM_PROFILE_EXIT_DISPATCH
150# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitDispatch, ed)
151# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitDispatch, ed)
152#else
153# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
154# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
155#endif
156
157/** Assert that preemption is disabled or covered by thread-context hooks. */
158#define HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu) Assert( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
159 || !RTThreadPreemptIsEnabled(NIL_RTTHREAD))
160
161/** Assert that we haven't migrated CPUs when thread-context hooks are not
162 * used. */
163#define HMVMX_ASSERT_CPU_SAFE(a_pVCpu) AssertMsg( VMMR0ThreadCtxHookIsEnabled((a_pVCpu)) \
164 || (a_pVCpu)->hmr0.s.idEnteredCpu == RTMpCpuId(), \
165 ("Illegal migration! Entered on CPU %u Current %u\n", \
166 (a_pVCpu)->hmr0.s.idEnteredCpu, RTMpCpuId()))
167
168/** Asserts that the given CPUMCTX_EXTRN_XXX bits are present in the guest-CPU
169 * context. */
170#define HMVMX_CPUMCTX_ASSERT(a_pVCpu, a_fExtrnMbz) AssertMsg(!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnMbz)), \
171 ("fExtrn=%#RX64 fExtrnMbz=%#RX64\n", \
172 (a_pVCpu)->cpum.GstCtx.fExtrn, (a_fExtrnMbz)))
173
174/** Log the VM-exit reason with an easily visible marker to identify it in a
175 * potential sea of logging data. */
176#define HMVMX_LOG_EXIT(a_pVCpu, a_uExitReason) \
177 do { \
178 Log4(("VM-exit: vcpu[%RU32] %85s -v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-\n", (a_pVCpu)->idCpu, \
179 HMGetVmxExitName(a_uExitReason))); \
180 } while (0) \
181
182
183/*********************************************************************************************************************************
184* Structures and Typedefs *
185*********************************************************************************************************************************/
186/**
187 * VMX per-VCPU transient state.
188 *
189 * A state structure for holding miscellaneous information across
190 * VMX non-root operation and restored after the transition.
191 *
192 * Note: The members are ordered and aligned such that the most
193 * frequently used ones (in the guest execution loop) fall within
194 * the first cache line.
195 */
196typedef struct VMXTRANSIENT
197{
198 /** Mask of currently read VMCS fields; HMVMX_READ_XXX. */
199 uint32_t fVmcsFieldsRead;
200 /** The guest's TPR value used for TPR shadowing. */
201 uint8_t u8GuestTpr;
202 uint8_t abAlignment0[3];
203
204 /** Whether the VM-exit was caused by a page-fault during delivery of an
205 * external interrupt or NMI. */
206 bool fVectoringPF;
207 /** Whether the VM-exit was caused by a page-fault during delivery of a
208 * contributory exception or a page-fault. */
209 bool fVectoringDoublePF;
210 /** Whether the VM-entry failed or not. */
211 bool fVMEntryFailed;
212 /** Whether the TSC_AUX MSR needs to be removed from the auto-load/store MSR
213 * area after VM-exit. */
214 bool fRemoveTscAuxMsr;
215 /** Whether TSC-offsetting and VMX-preemption timer was updated before VM-entry. */
216 bool fUpdatedTscOffsettingAndPreemptTimer;
217 /** Whether we are currently executing a nested-guest. */
218 bool fIsNestedGuest;
219 /** Whether the guest debug state was active at the time of VM-exit. */
220 bool fWasGuestDebugStateActive;
221 /** Whether the hyper debug state was active at the time of VM-exit. */
222 bool fWasHyperDebugStateActive;
223
224 /** The basic VM-exit reason. */
225 uint32_t uExitReason;
226 /** The VM-exit interruption error code. */
227 uint32_t uExitIntErrorCode;
228
229 /** The host's rflags/eflags. */
230 RTCCUINTREG fEFlags;
231
232 /** The VM-exit exit code qualification. */
233 uint64_t uExitQual;
234
235 /** The VMCS info. object. */
236 PVMXVMCSINFO pVmcsInfo;
237
238 /** The VM-exit interruption-information field. */
239 uint32_t uExitIntInfo;
240 /** The VM-exit instruction-length field. */
241 uint32_t cbExitInstr;
242
243 /** The VM-exit instruction-information field. */
244 VMXEXITINSTRINFO ExitInstrInfo;
245 /** IDT-vectoring information field. */
246 uint32_t uIdtVectoringInfo;
247
248 /** IDT-vectoring error code. */
249 uint32_t uIdtVectoringErrorCode;
250 uint32_t u32Alignment0;
251
252 /** The Guest-linear address. */
253 uint64_t uGuestLinearAddr;
254
255 /** The Guest-physical address. */
256 uint64_t uGuestPhysicalAddr;
257
258 /** The Guest pending-debug exceptions. */
259 uint64_t uGuestPendingDbgXcpts;
260
261 /** The VM-entry interruption-information field. */
262 uint32_t uEntryIntInfo;
263 /** The VM-entry exception error code field. */
264 uint32_t uEntryXcptErrorCode;
265
266 /** The VM-entry instruction length field. */
267 uint32_t cbEntryInstr;
268} VMXTRANSIENT;
269AssertCompileMemberSize(VMXTRANSIENT, ExitInstrInfo, sizeof(uint32_t));
270AssertCompileMemberAlignment(VMXTRANSIENT, fVmcsFieldsRead, 8);
271AssertCompileMemberAlignment(VMXTRANSIENT, fVectoringPF, 8);
272AssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, 8);
273AssertCompileMemberAlignment(VMXTRANSIENT, fEFlags, 8);
274AssertCompileMemberAlignment(VMXTRANSIENT, uExitQual, 8);
275AssertCompileMemberAlignment(VMXTRANSIENT, pVmcsInfo, 8);
276AssertCompileMemberAlignment(VMXTRANSIENT, uExitIntInfo, 8);
277AssertCompileMemberAlignment(VMXTRANSIENT, ExitInstrInfo, 8);
278AssertCompileMemberAlignment(VMXTRANSIENT, uIdtVectoringErrorCode, 8);
279AssertCompileMemberAlignment(VMXTRANSIENT, uGuestLinearAddr, 8);
280AssertCompileMemberAlignment(VMXTRANSIENT, uGuestPhysicalAddr, 8);
281AssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntInfo, 8);
282AssertCompileMemberAlignment(VMXTRANSIENT, cbEntryInstr, 8);
283/** Pointer to VMX transient state. */
284typedef VMXTRANSIENT *PVMXTRANSIENT;
285/** Pointer to a const VMX transient state. */
286typedef const VMXTRANSIENT *PCVMXTRANSIENT;
287
288/**
289 * VMX page allocation information.
290 */
291typedef struct
292{
293 uint32_t fValid; /**< Whether to allocate this page (e.g, based on a CPU feature). */
294 uint32_t uPadding0; /**< Padding to ensure array of these structs are aligned to a multiple of 8. */
295 PRTHCPHYS pHCPhys; /**< Where to store the host-physical address of the allocation. */
296 PRTR0PTR ppVirt; /**< Where to store the host-virtual address of the allocation. */
297} VMXPAGEALLOCINFO;
298/** Pointer to VMX page-allocation info. */
299typedef VMXPAGEALLOCINFO *PVMXPAGEALLOCINFO;
300/** Pointer to a const VMX page-allocation info. */
301typedef const VMXPAGEALLOCINFO *PCVMXPAGEALLOCINFO;
302AssertCompileSizeAlignment(VMXPAGEALLOCINFO, 8);
303
304/**
305 * Memory operand read or write access.
306 */
307typedef enum VMXMEMACCESS
308{
309 VMXMEMACCESS_READ = 0,
310 VMXMEMACCESS_WRITE = 1
311} VMXMEMACCESS;
312
313/**
314 * VMX VM-exit handler.
315 *
316 * @returns Strict VBox status code (i.e. informational status codes too).
317 * @param pVCpu The cross context virtual CPU structure.
318 * @param pVmxTransient The VMX-transient structure.
319 */
320#ifndef HMVMX_USE_FUNCTION_TABLE
321typedef VBOXSTRICTRC FNVMXEXITHANDLER(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
322#else
323typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNVMXEXITHANDLER,(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient));
324/** Pointer to VM-exit handler. */
325typedef FNVMXEXITHANDLER *PFNVMXEXITHANDLER;
326#endif
327
328/**
329 * VMX VM-exit handler, non-strict status code.
330 *
331 * This is generally the same as FNVMXEXITHANDLER, the NSRC bit is just FYI.
332 *
333 * @returns VBox status code, no informational status code returned.
334 * @param pVCpu The cross context virtual CPU structure.
335 * @param pVmxTransient The VMX-transient structure.
336 *
337 * @remarks This is not used on anything returning VERR_EM_INTERPRETER as the
338 * use of that status code will be replaced with VINF_EM_SOMETHING
339 * later when switching over to IEM.
340 */
341#ifndef HMVMX_USE_FUNCTION_TABLE
342typedef int FNVMXEXITHANDLERNSRC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
343#else
344typedef FNVMXEXITHANDLER FNVMXEXITHANDLERNSRC;
345#endif
346
347
348/*********************************************************************************************************************************
349* Internal Functions *
350*********************************************************************************************************************************/
351#ifndef HMVMX_USE_FUNCTION_TABLE
352DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
353# define HMVMX_EXIT_DECL DECLINLINE(VBOXSTRICTRC)
354# define HMVMX_EXIT_NSRC_DECL DECLINLINE(int)
355#else
356# define HMVMX_EXIT_DECL static DECLCALLBACK(VBOXSTRICTRC)
357# define HMVMX_EXIT_NSRC_DECL HMVMX_EXIT_DECL
358#endif
359#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
360DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient);
361#endif
362
363static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat);
364
365/** @name VM-exit handler prototypes.
366 * @{
367 */
368static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmi;
369static FNVMXEXITHANDLER hmR0VmxExitExtInt;
370static FNVMXEXITHANDLER hmR0VmxExitTripleFault;
371static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindow;
372static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindow;
373static FNVMXEXITHANDLER hmR0VmxExitTaskSwitch;
374static FNVMXEXITHANDLER hmR0VmxExitCpuid;
375static FNVMXEXITHANDLER hmR0VmxExitGetsec;
376static FNVMXEXITHANDLER hmR0VmxExitHlt;
377static FNVMXEXITHANDLERNSRC hmR0VmxExitInvd;
378static FNVMXEXITHANDLER hmR0VmxExitInvlpg;
379static FNVMXEXITHANDLER hmR0VmxExitRdpmc;
380static FNVMXEXITHANDLER hmR0VmxExitVmcall;
381#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
382static FNVMXEXITHANDLER hmR0VmxExitVmclear;
383static FNVMXEXITHANDLER hmR0VmxExitVmlaunch;
384static FNVMXEXITHANDLER hmR0VmxExitVmptrld;
385static FNVMXEXITHANDLER hmR0VmxExitVmptrst;
386static FNVMXEXITHANDLER hmR0VmxExitVmread;
387static FNVMXEXITHANDLER hmR0VmxExitVmresume;
388static FNVMXEXITHANDLER hmR0VmxExitVmwrite;
389static FNVMXEXITHANDLER hmR0VmxExitVmxoff;
390static FNVMXEXITHANDLER hmR0VmxExitVmxon;
391static FNVMXEXITHANDLER hmR0VmxExitInvvpid;
392#endif
393static FNVMXEXITHANDLER hmR0VmxExitRdtsc;
394static FNVMXEXITHANDLER hmR0VmxExitMovCRx;
395static FNVMXEXITHANDLER hmR0VmxExitMovDRx;
396static FNVMXEXITHANDLER hmR0VmxExitIoInstr;
397static FNVMXEXITHANDLER hmR0VmxExitRdmsr;
398static FNVMXEXITHANDLER hmR0VmxExitWrmsr;
399static FNVMXEXITHANDLER hmR0VmxExitMwait;
400static FNVMXEXITHANDLER hmR0VmxExitMtf;
401static FNVMXEXITHANDLER hmR0VmxExitMonitor;
402static FNVMXEXITHANDLER hmR0VmxExitPause;
403static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThreshold;
404static FNVMXEXITHANDLER hmR0VmxExitApicAccess;
405static FNVMXEXITHANDLER hmR0VmxExitEptViolation;
406static FNVMXEXITHANDLER hmR0VmxExitEptMisconfig;
407static FNVMXEXITHANDLER hmR0VmxExitRdtscp;
408static FNVMXEXITHANDLER hmR0VmxExitPreemptTimer;
409static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvd;
410static FNVMXEXITHANDLER hmR0VmxExitXsetbv;
411static FNVMXEXITHANDLER hmR0VmxExitInvpcid;
412static FNVMXEXITHANDLERNSRC hmR0VmxExitSetPendingXcptUD;
413static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestState;
414static FNVMXEXITHANDLERNSRC hmR0VmxExitErrUnexpected;
415/** @} */
416
417#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
418/** @name Nested-guest VM-exit handler prototypes.
419 * @{
420 */
421static FNVMXEXITHANDLER hmR0VmxExitXcptOrNmiNested;
422static FNVMXEXITHANDLER hmR0VmxExitTripleFaultNested;
423static FNVMXEXITHANDLERNSRC hmR0VmxExitIntWindowNested;
424static FNVMXEXITHANDLERNSRC hmR0VmxExitNmiWindowNested;
425static FNVMXEXITHANDLER hmR0VmxExitTaskSwitchNested;
426static FNVMXEXITHANDLER hmR0VmxExitHltNested;
427static FNVMXEXITHANDLER hmR0VmxExitInvlpgNested;
428static FNVMXEXITHANDLER hmR0VmxExitRdpmcNested;
429static FNVMXEXITHANDLER hmR0VmxExitVmreadVmwriteNested;
430static FNVMXEXITHANDLER hmR0VmxExitRdtscNested;
431static FNVMXEXITHANDLER hmR0VmxExitMovCRxNested;
432static FNVMXEXITHANDLER hmR0VmxExitMovDRxNested;
433static FNVMXEXITHANDLER hmR0VmxExitIoInstrNested;
434static FNVMXEXITHANDLER hmR0VmxExitRdmsrNested;
435static FNVMXEXITHANDLER hmR0VmxExitWrmsrNested;
436static FNVMXEXITHANDLER hmR0VmxExitMwaitNested;
437static FNVMXEXITHANDLER hmR0VmxExitMtfNested;
438static FNVMXEXITHANDLER hmR0VmxExitMonitorNested;
439static FNVMXEXITHANDLER hmR0VmxExitPauseNested;
440static FNVMXEXITHANDLERNSRC hmR0VmxExitTprBelowThresholdNested;
441static FNVMXEXITHANDLER hmR0VmxExitApicAccessNested;
442static FNVMXEXITHANDLER hmR0VmxExitApicWriteNested;
443static FNVMXEXITHANDLER hmR0VmxExitVirtEoiNested;
444static FNVMXEXITHANDLER hmR0VmxExitRdtscpNested;
445static FNVMXEXITHANDLERNSRC hmR0VmxExitWbinvdNested;
446static FNVMXEXITHANDLER hmR0VmxExitInvpcidNested;
447static FNVMXEXITHANDLERNSRC hmR0VmxExitErrInvalidGuestStateNested;
448static FNVMXEXITHANDLER hmR0VmxExitInstrNested;
449static FNVMXEXITHANDLER hmR0VmxExitInstrWithInfoNested;
450/** @} */
451#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
452
453
454/*********************************************************************************************************************************
455* Global Variables *
456*********************************************************************************************************************************/
457#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
458/**
459 * Array of all VMCS fields.
460 * Any fields added to the VT-x spec. should be added here.
461 *
462 * Currently only used to derive shadow VMCS fields for hardware-assisted execution
463 * of nested-guests.
464 */
465static const uint32_t g_aVmcsFields[] =
466{
467 /* 16-bit control fields. */
468 VMX_VMCS16_VPID,
469 VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR,
470 VMX_VMCS16_EPTP_INDEX,
471
472 /* 16-bit guest-state fields. */
473 VMX_VMCS16_GUEST_ES_SEL,
474 VMX_VMCS16_GUEST_CS_SEL,
475 VMX_VMCS16_GUEST_SS_SEL,
476 VMX_VMCS16_GUEST_DS_SEL,
477 VMX_VMCS16_GUEST_FS_SEL,
478 VMX_VMCS16_GUEST_GS_SEL,
479 VMX_VMCS16_GUEST_LDTR_SEL,
480 VMX_VMCS16_GUEST_TR_SEL,
481 VMX_VMCS16_GUEST_INTR_STATUS,
482 VMX_VMCS16_GUEST_PML_INDEX,
483
484 /* 16-bits host-state fields. */
485 VMX_VMCS16_HOST_ES_SEL,
486 VMX_VMCS16_HOST_CS_SEL,
487 VMX_VMCS16_HOST_SS_SEL,
488 VMX_VMCS16_HOST_DS_SEL,
489 VMX_VMCS16_HOST_FS_SEL,
490 VMX_VMCS16_HOST_GS_SEL,
491 VMX_VMCS16_HOST_TR_SEL,
492
493 /* 64-bit control fields. */
494 VMX_VMCS64_CTRL_IO_BITMAP_A_FULL,
495 VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH,
496 VMX_VMCS64_CTRL_IO_BITMAP_B_FULL,
497 VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH,
498 VMX_VMCS64_CTRL_MSR_BITMAP_FULL,
499 VMX_VMCS64_CTRL_MSR_BITMAP_HIGH,
500 VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL,
501 VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH,
502 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL,
503 VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH,
504 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL,
505 VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH,
506 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL,
507 VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH,
508 VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL,
509 VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH,
510 VMX_VMCS64_CTRL_TSC_OFFSET_FULL,
511 VMX_VMCS64_CTRL_TSC_OFFSET_HIGH,
512 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL,
513 VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH,
514 VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL,
515 VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH,
516 VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL,
517 VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH,
518 VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL,
519 VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH,
520 VMX_VMCS64_CTRL_EPTP_FULL,
521 VMX_VMCS64_CTRL_EPTP_HIGH,
522 VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL,
523 VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH,
524 VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL,
525 VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH,
526 VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL,
527 VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH,
528 VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL,
529 VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH,
530 VMX_VMCS64_CTRL_EPTP_LIST_FULL,
531 VMX_VMCS64_CTRL_EPTP_LIST_HIGH,
532 VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL,
533 VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH,
534 VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL,
535 VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH,
536 VMX_VMCS64_CTRL_VIRTXCPT_INFO_ADDR_FULL,
537 VMX_VMCS64_CTRL_VIRTXCPT_INFO_ADDR_HIGH,
538 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL,
539 VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH,
540 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_FULL,
541 VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_HIGH,
542 VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL,
543 VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH,
544
545 /* 64-bit read-only data fields. */
546 VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL,
547 VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH,
548
549 /* 64-bit guest-state fields. */
550 VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL,
551 VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH,
552 VMX_VMCS64_GUEST_DEBUGCTL_FULL,
553 VMX_VMCS64_GUEST_DEBUGCTL_HIGH,
554 VMX_VMCS64_GUEST_PAT_FULL,
555 VMX_VMCS64_GUEST_PAT_HIGH,
556 VMX_VMCS64_GUEST_EFER_FULL,
557 VMX_VMCS64_GUEST_EFER_HIGH,
558 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL,
559 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH,
560 VMX_VMCS64_GUEST_PDPTE0_FULL,
561 VMX_VMCS64_GUEST_PDPTE0_HIGH,
562 VMX_VMCS64_GUEST_PDPTE1_FULL,
563 VMX_VMCS64_GUEST_PDPTE1_HIGH,
564 VMX_VMCS64_GUEST_PDPTE2_FULL,
565 VMX_VMCS64_GUEST_PDPTE2_HIGH,
566 VMX_VMCS64_GUEST_PDPTE3_FULL,
567 VMX_VMCS64_GUEST_PDPTE3_HIGH,
568 VMX_VMCS64_GUEST_BNDCFGS_FULL,
569 VMX_VMCS64_GUEST_BNDCFGS_HIGH,
570
571 /* 64-bit host-state fields. */
572 VMX_VMCS64_HOST_PAT_FULL,
573 VMX_VMCS64_HOST_PAT_HIGH,
574 VMX_VMCS64_HOST_EFER_FULL,
575 VMX_VMCS64_HOST_EFER_HIGH,
576 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL,
577 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH,
578
579 /* 32-bit control fields. */
580 VMX_VMCS32_CTRL_PIN_EXEC,
581 VMX_VMCS32_CTRL_PROC_EXEC,
582 VMX_VMCS32_CTRL_EXCEPTION_BITMAP,
583 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK,
584 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH,
585 VMX_VMCS32_CTRL_CR3_TARGET_COUNT,
586 VMX_VMCS32_CTRL_EXIT,
587 VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT,
588 VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT,
589 VMX_VMCS32_CTRL_ENTRY,
590 VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT,
591 VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO,
592 VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE,
593 VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH,
594 VMX_VMCS32_CTRL_TPR_THRESHOLD,
595 VMX_VMCS32_CTRL_PROC_EXEC2,
596 VMX_VMCS32_CTRL_PLE_GAP,
597 VMX_VMCS32_CTRL_PLE_WINDOW,
598
599 /* 32-bits read-only fields. */
600 VMX_VMCS32_RO_VM_INSTR_ERROR,
601 VMX_VMCS32_RO_EXIT_REASON,
602 VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO,
603 VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE,
604 VMX_VMCS32_RO_IDT_VECTORING_INFO,
605 VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE,
606 VMX_VMCS32_RO_EXIT_INSTR_LENGTH,
607 VMX_VMCS32_RO_EXIT_INSTR_INFO,
608
609 /* 32-bit guest-state fields. */
610 VMX_VMCS32_GUEST_ES_LIMIT,
611 VMX_VMCS32_GUEST_CS_LIMIT,
612 VMX_VMCS32_GUEST_SS_LIMIT,
613 VMX_VMCS32_GUEST_DS_LIMIT,
614 VMX_VMCS32_GUEST_FS_LIMIT,
615 VMX_VMCS32_GUEST_GS_LIMIT,
616 VMX_VMCS32_GUEST_LDTR_LIMIT,
617 VMX_VMCS32_GUEST_TR_LIMIT,
618 VMX_VMCS32_GUEST_GDTR_LIMIT,
619 VMX_VMCS32_GUEST_IDTR_LIMIT,
620 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
621 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
622 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
623 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
624 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
625 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS,
626 VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS,
627 VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS,
628 VMX_VMCS32_GUEST_INT_STATE,
629 VMX_VMCS32_GUEST_ACTIVITY_STATE,
630 VMX_VMCS32_GUEST_SMBASE,
631 VMX_VMCS32_GUEST_SYSENTER_CS,
632 VMX_VMCS32_PREEMPT_TIMER_VALUE,
633
634 /* 32-bit host-state fields. */
635 VMX_VMCS32_HOST_SYSENTER_CS,
636
637 /* Natural-width control fields. */
638 VMX_VMCS_CTRL_CR0_MASK,
639 VMX_VMCS_CTRL_CR4_MASK,
640 VMX_VMCS_CTRL_CR0_READ_SHADOW,
641 VMX_VMCS_CTRL_CR4_READ_SHADOW,
642 VMX_VMCS_CTRL_CR3_TARGET_VAL0,
643 VMX_VMCS_CTRL_CR3_TARGET_VAL1,
644 VMX_VMCS_CTRL_CR3_TARGET_VAL2,
645 VMX_VMCS_CTRL_CR3_TARGET_VAL3,
646
647 /* Natural-width read-only data fields. */
648 VMX_VMCS_RO_EXIT_QUALIFICATION,
649 VMX_VMCS_RO_IO_RCX,
650 VMX_VMCS_RO_IO_RSI,
651 VMX_VMCS_RO_IO_RDI,
652 VMX_VMCS_RO_IO_RIP,
653 VMX_VMCS_RO_GUEST_LINEAR_ADDR,
654
655 /* Natural-width guest-state field */
656 VMX_VMCS_GUEST_CR0,
657 VMX_VMCS_GUEST_CR3,
658 VMX_VMCS_GUEST_CR4,
659 VMX_VMCS_GUEST_ES_BASE,
660 VMX_VMCS_GUEST_CS_BASE,
661 VMX_VMCS_GUEST_SS_BASE,
662 VMX_VMCS_GUEST_DS_BASE,
663 VMX_VMCS_GUEST_FS_BASE,
664 VMX_VMCS_GUEST_GS_BASE,
665 VMX_VMCS_GUEST_LDTR_BASE,
666 VMX_VMCS_GUEST_TR_BASE,
667 VMX_VMCS_GUEST_GDTR_BASE,
668 VMX_VMCS_GUEST_IDTR_BASE,
669 VMX_VMCS_GUEST_DR7,
670 VMX_VMCS_GUEST_RSP,
671 VMX_VMCS_GUEST_RIP,
672 VMX_VMCS_GUEST_RFLAGS,
673 VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS,
674 VMX_VMCS_GUEST_SYSENTER_ESP,
675 VMX_VMCS_GUEST_SYSENTER_EIP,
676
677 /* Natural-width host-state fields */
678 VMX_VMCS_HOST_CR0,
679 VMX_VMCS_HOST_CR3,
680 VMX_VMCS_HOST_CR4,
681 VMX_VMCS_HOST_FS_BASE,
682 VMX_VMCS_HOST_GS_BASE,
683 VMX_VMCS_HOST_TR_BASE,
684 VMX_VMCS_HOST_GDTR_BASE,
685 VMX_VMCS_HOST_IDTR_BASE,
686 VMX_VMCS_HOST_SYSENTER_ESP,
687 VMX_VMCS_HOST_SYSENTER_EIP,
688 VMX_VMCS_HOST_RSP,
689 VMX_VMCS_HOST_RIP
690};
691#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
692
693#ifdef VBOX_STRICT
694static const uint32_t g_aVmcsSegBase[] =
695{
696 VMX_VMCS_GUEST_ES_BASE,
697 VMX_VMCS_GUEST_CS_BASE,
698 VMX_VMCS_GUEST_SS_BASE,
699 VMX_VMCS_GUEST_DS_BASE,
700 VMX_VMCS_GUEST_FS_BASE,
701 VMX_VMCS_GUEST_GS_BASE
702};
703static const uint32_t g_aVmcsSegSel[] =
704{
705 VMX_VMCS16_GUEST_ES_SEL,
706 VMX_VMCS16_GUEST_CS_SEL,
707 VMX_VMCS16_GUEST_SS_SEL,
708 VMX_VMCS16_GUEST_DS_SEL,
709 VMX_VMCS16_GUEST_FS_SEL,
710 VMX_VMCS16_GUEST_GS_SEL
711};
712static const uint32_t g_aVmcsSegLimit[] =
713{
714 VMX_VMCS32_GUEST_ES_LIMIT,
715 VMX_VMCS32_GUEST_CS_LIMIT,
716 VMX_VMCS32_GUEST_SS_LIMIT,
717 VMX_VMCS32_GUEST_DS_LIMIT,
718 VMX_VMCS32_GUEST_FS_LIMIT,
719 VMX_VMCS32_GUEST_GS_LIMIT
720};
721static const uint32_t g_aVmcsSegAttr[] =
722{
723 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
724 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
725 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
726 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
727 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
728 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS
729};
730AssertCompile(RT_ELEMENTS(g_aVmcsSegSel) == X86_SREG_COUNT);
731AssertCompile(RT_ELEMENTS(g_aVmcsSegLimit) == X86_SREG_COUNT);
732AssertCompile(RT_ELEMENTS(g_aVmcsSegBase) == X86_SREG_COUNT);
733AssertCompile(RT_ELEMENTS(g_aVmcsSegAttr) == X86_SREG_COUNT);
734#endif /* VBOX_STRICT */
735
736#ifdef HMVMX_USE_FUNCTION_TABLE
737/**
738 * VMX_EXIT dispatch table.
739 */
740static const struct CLANG11NOTHROWWEIRDNESS { PFNVMXEXITHANDLER pfn; } g_aVMExitHandlers[VMX_EXIT_MAX + 1] =
741{
742 /* 0 VMX_EXIT_XCPT_OR_NMI */ { hmR0VmxExitXcptOrNmi },
743 /* 1 VMX_EXIT_EXT_INT */ { hmR0VmxExitExtInt },
744 /* 2 VMX_EXIT_TRIPLE_FAULT */ { hmR0VmxExitTripleFault },
745 /* 3 VMX_EXIT_INIT_SIGNAL */ { hmR0VmxExitErrUnexpected },
746 /* 4 VMX_EXIT_SIPI */ { hmR0VmxExitErrUnexpected },
747 /* 5 VMX_EXIT_IO_SMI */ { hmR0VmxExitErrUnexpected },
748 /* 6 VMX_EXIT_SMI */ { hmR0VmxExitErrUnexpected },
749 /* 7 VMX_EXIT_INT_WINDOW */ { hmR0VmxExitIntWindow },
750 /* 8 VMX_EXIT_NMI_WINDOW */ { hmR0VmxExitNmiWindow },
751 /* 9 VMX_EXIT_TASK_SWITCH */ { hmR0VmxExitTaskSwitch },
752 /* 10 VMX_EXIT_CPUID */ { hmR0VmxExitCpuid },
753 /* 11 VMX_EXIT_GETSEC */ { hmR0VmxExitGetsec },
754 /* 12 VMX_EXIT_HLT */ { hmR0VmxExitHlt },
755 /* 13 VMX_EXIT_INVD */ { hmR0VmxExitInvd },
756 /* 14 VMX_EXIT_INVLPG */ { hmR0VmxExitInvlpg },
757 /* 15 VMX_EXIT_RDPMC */ { hmR0VmxExitRdpmc },
758 /* 16 VMX_EXIT_RDTSC */ { hmR0VmxExitRdtsc },
759 /* 17 VMX_EXIT_RSM */ { hmR0VmxExitErrUnexpected },
760 /* 18 VMX_EXIT_VMCALL */ { hmR0VmxExitVmcall },
761#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
762 /* 19 VMX_EXIT_VMCLEAR */ { hmR0VmxExitVmclear },
763 /* 20 VMX_EXIT_VMLAUNCH */ { hmR0VmxExitVmlaunch },
764 /* 21 VMX_EXIT_VMPTRLD */ { hmR0VmxExitVmptrld },
765 /* 22 VMX_EXIT_VMPTRST */ { hmR0VmxExitVmptrst },
766 /* 23 VMX_EXIT_VMREAD */ { hmR0VmxExitVmread },
767 /* 24 VMX_EXIT_VMRESUME */ { hmR0VmxExitVmresume },
768 /* 25 VMX_EXIT_VMWRITE */ { hmR0VmxExitVmwrite },
769 /* 26 VMX_EXIT_VMXOFF */ { hmR0VmxExitVmxoff },
770 /* 27 VMX_EXIT_VMXON */ { hmR0VmxExitVmxon },
771#else
772 /* 19 VMX_EXIT_VMCLEAR */ { hmR0VmxExitSetPendingXcptUD },
773 /* 20 VMX_EXIT_VMLAUNCH */ { hmR0VmxExitSetPendingXcptUD },
774 /* 21 VMX_EXIT_VMPTRLD */ { hmR0VmxExitSetPendingXcptUD },
775 /* 22 VMX_EXIT_VMPTRST */ { hmR0VmxExitSetPendingXcptUD },
776 /* 23 VMX_EXIT_VMREAD */ { hmR0VmxExitSetPendingXcptUD },
777 /* 24 VMX_EXIT_VMRESUME */ { hmR0VmxExitSetPendingXcptUD },
778 /* 25 VMX_EXIT_VMWRITE */ { hmR0VmxExitSetPendingXcptUD },
779 /* 26 VMX_EXIT_VMXOFF */ { hmR0VmxExitSetPendingXcptUD },
780 /* 27 VMX_EXIT_VMXON */ { hmR0VmxExitSetPendingXcptUD },
781#endif
782 /* 28 VMX_EXIT_MOV_CRX */ { hmR0VmxExitMovCRx },
783 /* 29 VMX_EXIT_MOV_DRX */ { hmR0VmxExitMovDRx },
784 /* 30 VMX_EXIT_IO_INSTR */ { hmR0VmxExitIoInstr },
785 /* 31 VMX_EXIT_RDMSR */ { hmR0VmxExitRdmsr },
786 /* 32 VMX_EXIT_WRMSR */ { hmR0VmxExitWrmsr },
787 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ { hmR0VmxExitErrInvalidGuestState },
788 /* 34 VMX_EXIT_ERR_MSR_LOAD */ { hmR0VmxExitErrUnexpected },
789 /* 35 UNDEFINED */ { hmR0VmxExitErrUnexpected },
790 /* 36 VMX_EXIT_MWAIT */ { hmR0VmxExitMwait },
791 /* 37 VMX_EXIT_MTF */ { hmR0VmxExitMtf },
792 /* 38 UNDEFINED */ { hmR0VmxExitErrUnexpected },
793 /* 39 VMX_EXIT_MONITOR */ { hmR0VmxExitMonitor },
794 /* 40 VMX_EXIT_PAUSE */ { hmR0VmxExitPause },
795 /* 41 VMX_EXIT_ERR_MACHINE_CHECK */ { hmR0VmxExitErrUnexpected },
796 /* 42 UNDEFINED */ { hmR0VmxExitErrUnexpected },
797 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ { hmR0VmxExitTprBelowThreshold },
798 /* 44 VMX_EXIT_APIC_ACCESS */ { hmR0VmxExitApicAccess },
799 /* 45 VMX_EXIT_VIRTUALIZED_EOI */ { hmR0VmxExitErrUnexpected },
800 /* 46 VMX_EXIT_GDTR_IDTR_ACCESS */ { hmR0VmxExitErrUnexpected },
801 /* 47 VMX_EXIT_LDTR_TR_ACCESS */ { hmR0VmxExitErrUnexpected },
802 /* 48 VMX_EXIT_EPT_VIOLATION */ { hmR0VmxExitEptViolation },
803 /* 49 VMX_EXIT_EPT_MISCONFIG */ { hmR0VmxExitEptMisconfig },
804 /* 50 VMX_EXIT_INVEPT */ { hmR0VmxExitSetPendingXcptUD },
805 /* 51 VMX_EXIT_RDTSCP */ { hmR0VmxExitRdtscp },
806 /* 52 VMX_EXIT_PREEMPT_TIMER */ { hmR0VmxExitPreemptTimer },
807#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
808 /* 53 VMX_EXIT_INVVPID */ { hmR0VmxExitInvvpid },
809#else
810 /* 53 VMX_EXIT_INVVPID */ { hmR0VmxExitSetPendingXcptUD },
811#endif
812 /* 54 VMX_EXIT_WBINVD */ { hmR0VmxExitWbinvd },
813 /* 55 VMX_EXIT_XSETBV */ { hmR0VmxExitXsetbv },
814 /* 56 VMX_EXIT_APIC_WRITE */ { hmR0VmxExitErrUnexpected },
815 /* 57 VMX_EXIT_RDRAND */ { hmR0VmxExitErrUnexpected },
816 /* 58 VMX_EXIT_INVPCID */ { hmR0VmxExitInvpcid },
817 /* 59 VMX_EXIT_VMFUNC */ { hmR0VmxExitErrUnexpected },
818 /* 60 VMX_EXIT_ENCLS */ { hmR0VmxExitErrUnexpected },
819 /* 61 VMX_EXIT_RDSEED */ { hmR0VmxExitErrUnexpected },
820 /* 62 VMX_EXIT_PML_FULL */ { hmR0VmxExitErrUnexpected },
821 /* 63 VMX_EXIT_XSAVES */ { hmR0VmxExitErrUnexpected },
822 /* 64 VMX_EXIT_XRSTORS */ { hmR0VmxExitErrUnexpected },
823 /* 65 UNDEFINED */ { hmR0VmxExitErrUnexpected },
824 /* 66 VMX_EXIT_SPP_EVENT */ { hmR0VmxExitErrUnexpected },
825 /* 67 VMX_EXIT_UMWAIT */ { hmR0VmxExitErrUnexpected },
826 /* 68 VMX_EXIT_TPAUSE */ { hmR0VmxExitErrUnexpected },
827};
828#endif /* HMVMX_USE_FUNCTION_TABLE */
829
830#if defined(VBOX_STRICT) && defined(LOG_ENABLED)
831static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
832{
833 /* 0 */ "(Not Used)",
834 /* 1 */ "VMCALL executed in VMX root operation.",
835 /* 2 */ "VMCLEAR with invalid physical address.",
836 /* 3 */ "VMCLEAR with VMXON pointer.",
837 /* 4 */ "VMLAUNCH with non-clear VMCS.",
838 /* 5 */ "VMRESUME with non-launched VMCS.",
839 /* 6 */ "VMRESUME after VMXOFF",
840 /* 7 */ "VM-entry with invalid control fields.",
841 /* 8 */ "VM-entry with invalid host state fields.",
842 /* 9 */ "VMPTRLD with invalid physical address.",
843 /* 10 */ "VMPTRLD with VMXON pointer.",
844 /* 11 */ "VMPTRLD with incorrect revision identifier.",
845 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
846 /* 13 */ "VMWRITE to read-only VMCS component.",
847 /* 14 */ "(Not Used)",
848 /* 15 */ "VMXON executed in VMX root operation.",
849 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
850 /* 17 */ "VM-entry with non-launched executing VMCS.",
851 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
852 /* 19 */ "VMCALL with non-clear VMCS.",
853 /* 20 */ "VMCALL with invalid VM-exit control fields.",
854 /* 21 */ "(Not Used)",
855 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
856 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
857 /* 24 */ "VMCALL with invalid SMM-monitor features.",
858 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
859 /* 26 */ "VM-entry with events blocked by MOV SS.",
860 /* 27 */ "(Not Used)",
861 /* 28 */ "Invalid operand to INVEPT/INVVPID."
862};
863#endif /* VBOX_STRICT && LOG_ENABLED */
864
865
866/**
867 * Checks if the given MSR is part of the lastbranch-from-IP MSR stack.
868 * @returns @c true if it's part of LBR stack, @c false otherwise.
869 *
870 * @param pVM The cross context VM structure.
871 * @param idMsr The MSR.
872 * @param pidxMsr Where to store the index of the MSR in the LBR MSR array.
873 * Optional, can be NULL.
874 *
875 * @remarks Must only be called when LBR is enabled.
876 */
877DECL_FORCE_INLINE(bool) hmR0VmxIsLbrBranchFromMsr(PCVM pVM, uint32_t idMsr, uint32_t *pidxMsr)
878{
879 Assert(pVM->hm.s.vmx.fLbr);
880 Assert(pVM->hm.s.vmx.idLbrFromIpMsrFirst);
881 uint32_t const cLbrStack = pVM->hm.s.vmx.idLbrFromIpMsrLast - pVM->hm.s.vmx.idLbrFromIpMsrFirst + 1;
882 uint32_t const idxMsr = idMsr - pVM->hm.s.vmx.idLbrFromIpMsrFirst;
883 if (idxMsr < cLbrStack)
884 {
885 if (pidxMsr)
886 *pidxMsr = idxMsr;
887 return true;
888 }
889 return false;
890}
891
892
893/**
894 * Checks if the given MSR is part of the lastbranch-to-IP MSR stack.
895 * @returns @c true if it's part of LBR stack, @c false otherwise.
896 *
897 * @param pVM The cross context VM structure.
898 * @param idMsr The MSR.
899 * @param pidxMsr Where to store the index of the MSR in the LBR MSR array.
900 * Optional, can be NULL.
901 *
902 * @remarks Must only be called when LBR is enabled and when lastbranch-to-IP MSRs
903 * are supported by the CPU (see hmR0VmxSetupLbrMsrRange).
904 */
905DECL_FORCE_INLINE(bool) hmR0VmxIsLbrBranchToMsr(PCVM pVM, uint32_t idMsr, uint32_t *pidxMsr)
906{
907 Assert(pVM->hm.s.vmx.fLbr);
908 if (pVM->hm.s.vmx.idLbrToIpMsrFirst)
909 {
910 uint32_t const cLbrStack = pVM->hm.s.vmx.idLbrToIpMsrLast - pVM->hm.s.vmx.idLbrToIpMsrFirst + 1;
911 uint32_t const idxMsr = idMsr - pVM->hm.s.vmx.idLbrToIpMsrFirst;
912 if (idxMsr < cLbrStack)
913 {
914 if (pidxMsr)
915 *pidxMsr = idxMsr;
916 return true;
917 }
918 }
919 return false;
920}
921
922
923/**
924 * Gets the CR0 guest/host mask.
925 *
926 * These bits typically does not change through the lifetime of a VM. Any bit set in
927 * this mask is owned by the host/hypervisor and would cause a VM-exit when modified
928 * by the guest.
929 *
930 * @returns The CR0 guest/host mask.
931 * @param pVCpu The cross context virtual CPU structure.
932 */
933static uint64_t hmR0VmxGetFixedCr0Mask(PCVMCPUCC pVCpu)
934{
935 /*
936 * Modifications to CR0 bits that VT-x ignores saving/restoring (CD, ET, NW) and
937 * to CR0 bits that we require for shadow paging (PG) by the guest must cause VM-exits.
938 *
939 * Furthermore, modifications to any bits that are reserved/unspecified currently
940 * by the Intel spec. must also cause a VM-exit. This prevents unpredictable behavior
941 * when future CPUs specify and use currently reserved/unspecified bits.
942 */
943 /** @todo Avoid intercepting CR0.PE with unrestricted guest execution. Fix PGM
944 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
945 * and @bugref{6944}. */
946 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
947 return ( X86_CR0_PE
948 | X86_CR0_NE
949 | (pVM->hmr0.s.fNestedPaging ? 0 : X86_CR0_WP)
950 | X86_CR0_PG
951 | VMX_EXIT_HOST_CR0_IGNORE_MASK);
952}
953
954
955/**
956 * Gets the CR4 guest/host mask.
957 *
958 * These bits typically does not change through the lifetime of a VM. Any bit set in
959 * this mask is owned by the host/hypervisor and would cause a VM-exit when modified
960 * by the guest.
961 *
962 * @returns The CR4 guest/host mask.
963 * @param pVCpu The cross context virtual CPU structure.
964 */
965static uint64_t hmR0VmxGetFixedCr4Mask(PCVMCPUCC pVCpu)
966{
967 /*
968 * We construct a mask of all CR4 bits that the guest can modify without causing
969 * a VM-exit. Then invert this mask to obtain all CR4 bits that should cause
970 * a VM-exit when the guest attempts to modify them when executing using
971 * hardware-assisted VMX.
972 *
973 * When a feature is not exposed to the guest (and may be present on the host),
974 * we want to intercept guest modifications to the bit so we can emulate proper
975 * behavior (e.g., #GP).
976 *
977 * Furthermore, only modifications to those bits that don't require immediate
978 * emulation is allowed. For e.g., PCIDE is excluded because the behavior
979 * depends on CR3 which might not always be the guest value while executing
980 * using hardware-assisted VMX.
981 */
982 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
983 bool const fFsGsBase = pVM->cpum.ro.GuestFeatures.fFsGsBase;
984 bool const fXSaveRstor = pVM->cpum.ro.GuestFeatures.fXSaveRstor;
985 bool const fFxSaveRstor = pVM->cpum.ro.GuestFeatures.fFxSaveRstor;
986
987 /*
988 * Paranoia.
989 * Ensure features exposed to the guest are present on the host.
990 */
991 Assert(!fFsGsBase || pVM->cpum.ro.HostFeatures.fFsGsBase);
992 Assert(!fXSaveRstor || pVM->cpum.ro.HostFeatures.fXSaveRstor);
993 Assert(!fFxSaveRstor || pVM->cpum.ro.HostFeatures.fFxSaveRstor);
994
995 uint64_t const fGstMask = ( X86_CR4_PVI
996 | X86_CR4_TSD
997 | X86_CR4_DE
998 | X86_CR4_MCE
999 | X86_CR4_PCE
1000 | X86_CR4_OSXMMEEXCPT
1001 | (fFsGsBase ? X86_CR4_FSGSBASE : 0)
1002 | (fXSaveRstor ? X86_CR4_OSXSAVE : 0)
1003 | (fFxSaveRstor ? X86_CR4_OSFXSR : 0));
1004 return ~fGstMask;
1005}
1006
1007
1008/**
1009 * Gets the active (in use) VMCS info. object for the specified VCPU.
1010 *
1011 * This is either the guest or nested-guest VMCS info. and need not necessarily
1012 * pertain to the "current" VMCS (in the VMX definition of the term). For instance,
1013 * if the VM-entry failed due to an invalid-guest state, we may have "cleared" the
1014 * current VMCS while returning to ring-3. However, the VMCS info. object for that
1015 * VMCS would still be active and returned here so that we could dump the VMCS
1016 * fields to ring-3 for diagnostics. This function is thus only used to
1017 * distinguish between the nested-guest or guest VMCS.
1018 *
1019 * @returns The active VMCS information.
1020 * @param pVCpu The cross context virtual CPU structure.
1021 *
1022 * @thread EMT.
1023 * @remarks This function may be called with preemption or interrupts disabled!
1024 */
1025DECLINLINE(PVMXVMCSINFO) hmGetVmxActiveVmcsInfo(PVMCPUCC pVCpu)
1026{
1027 if (!pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
1028 return &pVCpu->hmr0.s.vmx.VmcsInfo;
1029 return &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1030}
1031
1032
1033/**
1034 * Returns whether the the VM-exit MSR-store area differs from the VM-exit MSR-load
1035 * area.
1036 *
1037 * @returns @c true if it's different, @c false otherwise.
1038 * @param pVmcsInfo The VMCS info. object.
1039 */
1040DECL_FORCE_INLINE(bool) hmR0VmxIsSeparateExitMsrStoreAreaVmcs(PCVMXVMCSINFO pVmcsInfo)
1041{
1042 return RT_BOOL( pVmcsInfo->pvGuestMsrStore != pVmcsInfo->pvGuestMsrLoad
1043 && pVmcsInfo->pvGuestMsrStore);
1044}
1045
1046
1047/**
1048 * Sets the given Processor-based VM-execution controls.
1049 *
1050 * @param pVmxTransient The VMX-transient structure.
1051 * @param uProcCtls The Processor-based VM-execution controls to set.
1052 */
1053static void hmR0VmxSetProcCtlsVmcs(PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
1054{
1055 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1056 if ((pVmcsInfo->u32ProcCtls & uProcCtls) != uProcCtls)
1057 {
1058 pVmcsInfo->u32ProcCtls |= uProcCtls;
1059 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
1060 AssertRC(rc);
1061 }
1062}
1063
1064
1065/**
1066 * Removes the given Processor-based VM-execution controls.
1067 *
1068 * @param pVCpu The cross context virtual CPU structure.
1069 * @param pVmxTransient The VMX-transient structure.
1070 * @param uProcCtls The Processor-based VM-execution controls to remove.
1071 *
1072 * @remarks When executing a nested-guest, this will not remove any of the specified
1073 * controls if the nested hypervisor has set any one of them.
1074 */
1075static void hmR0VmxRemoveProcCtlsVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
1076{
1077 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1078 if (pVmcsInfo->u32ProcCtls & uProcCtls)
1079 {
1080#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1081 bool const fRemoveCtls = !pVmxTransient->fIsNestedGuest
1082 ? true
1083 : !CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uProcCtls);
1084#else
1085 NOREF(pVCpu);
1086 bool const fRemoveCtls = true;
1087#endif
1088 if (fRemoveCtls)
1089 {
1090 pVmcsInfo->u32ProcCtls &= ~uProcCtls;
1091 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
1092 AssertRC(rc);
1093 }
1094 }
1095}
1096
1097
1098/**
1099 * Sets the TSC offset for the current VMCS.
1100 *
1101 * @param uTscOffset The TSC offset to set.
1102 * @param pVmcsInfo The VMCS info. object.
1103 */
1104static void hmR0VmxSetTscOffsetVmcs(PVMXVMCSINFO pVmcsInfo, uint64_t uTscOffset)
1105{
1106 if (pVmcsInfo->u64TscOffset != uTscOffset)
1107 {
1108 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
1109 AssertRC(rc);
1110 pVmcsInfo->u64TscOffset = uTscOffset;
1111 }
1112}
1113
1114
1115/**
1116 * Adds one or more exceptions to the exception bitmap and commits it to the current
1117 * VMCS.
1118 *
1119 * @param pVmxTransient The VMX-transient structure.
1120 * @param uXcptMask The exception(s) to add.
1121 */
1122static void hmR0VmxAddXcptInterceptMask(PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1123{
1124 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1125 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
1126 if ((uXcptBitmap & uXcptMask) != uXcptMask)
1127 {
1128 uXcptBitmap |= uXcptMask;
1129 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
1130 AssertRC(rc);
1131 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
1132 }
1133}
1134
1135
1136/**
1137 * Adds an exception to the exception bitmap and commits it to the current VMCS.
1138 *
1139 * @param pVmxTransient The VMX-transient structure.
1140 * @param uXcpt The exception to add.
1141 */
1142static void hmR0VmxAddXcptIntercept(PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1143{
1144 Assert(uXcpt <= X86_XCPT_LAST);
1145 hmR0VmxAddXcptInterceptMask(pVmxTransient, RT_BIT_32(uXcpt));
1146}
1147
1148
1149/**
1150 * Remove one or more exceptions from the exception bitmap and commits it to the
1151 * current VMCS.
1152 *
1153 * This takes care of not removing the exception intercept if a nested-guest
1154 * requires the exception to be intercepted.
1155 *
1156 * @returns VBox status code.
1157 * @param pVCpu The cross context virtual CPU structure.
1158 * @param pVmxTransient The VMX-transient structure.
1159 * @param uXcptMask The exception(s) to remove.
1160 */
1161static int hmR0VmxRemoveXcptInterceptMask(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1162{
1163 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1164 uint32_t u32XcptBitmap = pVmcsInfo->u32XcptBitmap;
1165 if (u32XcptBitmap & uXcptMask)
1166 {
1167#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1168 if (!pVmxTransient->fIsNestedGuest)
1169 { /* likely */ }
1170 else
1171 {
1172 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
1173 uXcptMask &= ~pVmcsNstGst->u32XcptBitmap;
1174 }
1175#endif
1176#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
1177 uXcptMask &= ~( RT_BIT(X86_XCPT_BP)
1178 | RT_BIT(X86_XCPT_DE)
1179 | RT_BIT(X86_XCPT_NM)
1180 | RT_BIT(X86_XCPT_TS)
1181 | RT_BIT(X86_XCPT_UD)
1182 | RT_BIT(X86_XCPT_NP)
1183 | RT_BIT(X86_XCPT_SS)
1184 | RT_BIT(X86_XCPT_GP)
1185 | RT_BIT(X86_XCPT_PF)
1186 | RT_BIT(X86_XCPT_MF));
1187#elif defined(HMVMX_ALWAYS_TRAP_PF)
1188 uXcptMask &= ~RT_BIT(X86_XCPT_PF);
1189#endif
1190 if (uXcptMask)
1191 {
1192 /* Validate we are not removing any essential exception intercepts. */
1193 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging || !(uXcptMask & RT_BIT(X86_XCPT_PF)));
1194 NOREF(pVCpu);
1195 Assert(!(uXcptMask & RT_BIT(X86_XCPT_DB)));
1196 Assert(!(uXcptMask & RT_BIT(X86_XCPT_AC)));
1197
1198 /* Remove it from the exception bitmap. */
1199 u32XcptBitmap &= ~uXcptMask;
1200
1201 /* Commit and update the cache if necessary. */
1202 if (pVmcsInfo->u32XcptBitmap != u32XcptBitmap)
1203 {
1204 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
1205 AssertRC(rc);
1206 pVmcsInfo->u32XcptBitmap = u32XcptBitmap;
1207 }
1208 }
1209 }
1210 return VINF_SUCCESS;
1211}
1212
1213
1214/**
1215 * Remove an exceptions from the exception bitmap and commits it to the current
1216 * VMCS.
1217 *
1218 * @returns VBox status code.
1219 * @param pVCpu The cross context virtual CPU structure.
1220 * @param pVmxTransient The VMX-transient structure.
1221 * @param uXcpt The exception to remove.
1222 */
1223static int hmR0VmxRemoveXcptIntercept(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1224{
1225 return hmR0VmxRemoveXcptInterceptMask(pVCpu, pVmxTransient, RT_BIT(uXcpt));
1226}
1227
1228
1229/**
1230 * Loads the VMCS specified by the VMCS info. object.
1231 *
1232 * @returns VBox status code.
1233 * @param pVmcsInfo The VMCS info. object.
1234 *
1235 * @remarks Can be called with interrupts disabled.
1236 */
1237static int hmR0VmxLoadVmcs(PVMXVMCSINFO pVmcsInfo)
1238{
1239 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1240 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1241
1242 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysVmcs);
1243 if (RT_SUCCESS(rc))
1244 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1245 return rc;
1246}
1247
1248
1249/**
1250 * Clears the VMCS specified by the VMCS info. object.
1251 *
1252 * @returns VBox status code.
1253 * @param pVmcsInfo The VMCS info. object.
1254 *
1255 * @remarks Can be called with interrupts disabled.
1256 */
1257static int hmR0VmxClearVmcs(PVMXVMCSINFO pVmcsInfo)
1258{
1259 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1260 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1261
1262 int rc = VMXClearVmcs(pVmcsInfo->HCPhysVmcs);
1263 if (RT_SUCCESS(rc))
1264 pVmcsInfo->fVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1265 return rc;
1266}
1267
1268
1269#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1270/**
1271 * Loads the shadow VMCS specified by the VMCS info. object.
1272 *
1273 * @returns VBox status code.
1274 * @param pVmcsInfo The VMCS info. object.
1275 *
1276 * @remarks Can be called with interrupts disabled.
1277 */
1278static int hmR0VmxLoadShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1279{
1280 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1281 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1282
1283 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
1284 if (RT_SUCCESS(rc))
1285 pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1286 return rc;
1287}
1288
1289
1290/**
1291 * Clears the shadow VMCS specified by the VMCS info. object.
1292 *
1293 * @returns VBox status code.
1294 * @param pVmcsInfo The VMCS info. object.
1295 *
1296 * @remarks Can be called with interrupts disabled.
1297 */
1298static int hmR0VmxClearShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1299{
1300 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1301 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1302
1303 int rc = VMXClearVmcs(pVmcsInfo->HCPhysShadowVmcs);
1304 if (RT_SUCCESS(rc))
1305 pVmcsInfo->fShadowVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1306 return rc;
1307}
1308
1309
1310/**
1311 * Switches from and to the specified VMCSes.
1312 *
1313 * @returns VBox status code.
1314 * @param pVmcsInfoFrom The VMCS info. object we are switching from.
1315 * @param pVmcsInfoTo The VMCS info. object we are switching to.
1316 *
1317 * @remarks Called with interrupts disabled.
1318 */
1319static int hmR0VmxSwitchVmcs(PVMXVMCSINFO pVmcsInfoFrom, PVMXVMCSINFO pVmcsInfoTo)
1320{
1321 /*
1322 * Clear the VMCS we are switching out if it has not already been cleared.
1323 * This will sync any CPU internal data back to the VMCS.
1324 */
1325 if (pVmcsInfoFrom->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1326 {
1327 int rc = hmR0VmxClearVmcs(pVmcsInfoFrom);
1328 if (RT_SUCCESS(rc))
1329 {
1330 /*
1331 * The shadow VMCS, if any, would not be active at this point since we
1332 * would have cleared it while importing the virtual hardware-virtualization
1333 * state as part the VMLAUNCH/VMRESUME VM-exit. Hence, there's no need to
1334 * clear the shadow VMCS here, just assert for safety.
1335 */
1336 Assert(!pVmcsInfoFrom->pvShadowVmcs || pVmcsInfoFrom->fShadowVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR);
1337 }
1338 else
1339 return rc;
1340 }
1341
1342 /*
1343 * Clear the VMCS we are switching to if it has not already been cleared.
1344 * This will initialize the VMCS launch state to "clear" required for loading it.
1345 *
1346 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
1347 */
1348 if (pVmcsInfoTo->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1349 {
1350 int rc = hmR0VmxClearVmcs(pVmcsInfoTo);
1351 if (RT_SUCCESS(rc))
1352 { /* likely */ }
1353 else
1354 return rc;
1355 }
1356
1357 /*
1358 * Finally, load the VMCS we are switching to.
1359 */
1360 return hmR0VmxLoadVmcs(pVmcsInfoTo);
1361}
1362
1363
1364/**
1365 * Switches between the guest VMCS and the nested-guest VMCS as specified by the
1366 * caller.
1367 *
1368 * @returns VBox status code.
1369 * @param pVCpu The cross context virtual CPU structure.
1370 * @param fSwitchToNstGstVmcs Whether to switch to the nested-guest VMCS (pass
1371 * true) or guest VMCS (pass false).
1372 */
1373static int hmR0VmxSwitchToGstOrNstGstVmcs(PVMCPUCC pVCpu, bool fSwitchToNstGstVmcs)
1374{
1375 /* Ensure we have synced everything from the guest-CPU context to the VMCS before switching. */
1376 HMVMX_CPUMCTX_ASSERT(pVCpu, HMVMX_CPUMCTX_EXTRN_ALL);
1377
1378 PVMXVMCSINFO pVmcsInfoFrom;
1379 PVMXVMCSINFO pVmcsInfoTo;
1380 if (fSwitchToNstGstVmcs)
1381 {
1382 pVmcsInfoFrom = &pVCpu->hmr0.s.vmx.VmcsInfo;
1383 pVmcsInfoTo = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1384 }
1385 else
1386 {
1387 pVmcsInfoFrom = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1388 pVmcsInfoTo = &pVCpu->hmr0.s.vmx.VmcsInfo;
1389 }
1390
1391 /*
1392 * Disable interrupts to prevent being preempted while we switch the current VMCS as the
1393 * preemption hook code path acquires the current VMCS.
1394 */
1395 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1396
1397 int rc = hmR0VmxSwitchVmcs(pVmcsInfoFrom, pVmcsInfoTo);
1398 if (RT_SUCCESS(rc))
1399 {
1400 pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs = fSwitchToNstGstVmcs;
1401 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcsCopyForRing3 = fSwitchToNstGstVmcs;
1402
1403 /*
1404 * If we are switching to a VMCS that was executed on a different host CPU or was
1405 * never executed before, flag that we need to export the host state before executing
1406 * guest/nested-guest code using hardware-assisted VMX.
1407 *
1408 * This could probably be done in a preemptible context since the preemption hook
1409 * will flag the necessary change in host context. However, since preemption is
1410 * already disabled and to avoid making assumptions about host specific code in
1411 * RTMpCpuId when called with preemption enabled, we'll do this while preemption is
1412 * disabled.
1413 */
1414 if (pVmcsInfoTo->idHostCpuState == RTMpCpuId())
1415 { /* likely */ }
1416 else
1417 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE);
1418
1419 ASMSetFlags(fEFlags);
1420
1421 /*
1422 * We use a different VM-exit MSR-store areas for the guest and nested-guest. Hence,
1423 * flag that we need to update the host MSR values there. Even if we decide in the
1424 * future to share the VM-exit MSR-store area page between the guest and nested-guest,
1425 * if its content differs, we would have to update the host MSRs anyway.
1426 */
1427 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
1428 }
1429 else
1430 ASMSetFlags(fEFlags);
1431 return rc;
1432}
1433#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
1434
1435
1436/**
1437 * Updates the VM's last error record.
1438 *
1439 * If there was a VMX instruction error, reads the error data from the VMCS and
1440 * updates VCPU's last error record as well.
1441 *
1442 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1443 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
1444 * VERR_VMX_INVALID_VMCS_FIELD.
1445 * @param rc The error code.
1446 */
1447static void hmR0VmxUpdateErrorRecord(PVMCPUCC pVCpu, int rc)
1448{
1449 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
1450 || rc == VERR_VMX_UNABLE_TO_START_VM)
1451 {
1452 AssertPtrReturnVoid(pVCpu);
1453 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
1454 }
1455 pVCpu->CTX_SUFF(pVM)->hm.s.rcInit = rc;
1456}
1457
1458
1459#ifdef VBOX_STRICT
1460/**
1461 * Reads the VM-entry interruption-information field from the VMCS into the VMX
1462 * transient structure.
1463 *
1464 * @param pVmxTransient The VMX-transient structure.
1465 */
1466DECLINLINE(void) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1467{
1468 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
1469 AssertRC(rc);
1470}
1471
1472
1473/**
1474 * Reads the VM-entry exception error code field from the VMCS into
1475 * the VMX transient structure.
1476 *
1477 * @param pVmxTransient The VMX-transient structure.
1478 */
1479DECLINLINE(void) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1480{
1481 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
1482 AssertRC(rc);
1483}
1484
1485
1486/**
1487 * Reads the VM-entry exception error code field from the VMCS into
1488 * the VMX transient structure.
1489 *
1490 * @param pVmxTransient The VMX-transient structure.
1491 */
1492DECLINLINE(void) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1493{
1494 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
1495 AssertRC(rc);
1496}
1497#endif /* VBOX_STRICT */
1498
1499
1500/**
1501 * Reads the VM-exit interruption-information field from the VMCS into the VMX
1502 * transient structure.
1503 *
1504 * @param pVmxTransient The VMX-transient structure.
1505 */
1506DECLINLINE(void) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1507{
1508 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_INFO))
1509 {
1510 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1511 AssertRC(rc);
1512 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_INFO;
1513 }
1514}
1515
1516
1517/**
1518 * Reads the VM-exit interruption error code from the VMCS into the VMX
1519 * transient structure.
1520 *
1521 * @param pVmxTransient The VMX-transient structure.
1522 */
1523DECLINLINE(void) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1524{
1525 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE))
1526 {
1527 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1528 AssertRC(rc);
1529 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE;
1530 }
1531}
1532
1533
1534/**
1535 * Reads the VM-exit instruction length field from the VMCS into the VMX
1536 * transient structure.
1537 *
1538 * @param pVmxTransient The VMX-transient structure.
1539 */
1540DECLINLINE(void) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1541{
1542 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_LEN))
1543 {
1544 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1545 AssertRC(rc);
1546 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_LEN;
1547 }
1548}
1549
1550
1551/**
1552 * Reads the VM-exit instruction-information field from the VMCS into
1553 * the VMX transient structure.
1554 *
1555 * @param pVmxTransient The VMX-transient structure.
1556 */
1557DECLINLINE(void) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
1558{
1559 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_INFO))
1560 {
1561 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1562 AssertRC(rc);
1563 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_INFO;
1564 }
1565}
1566
1567
1568/**
1569 * Reads the Exit Qualification from the VMCS into the VMX transient structure.
1570 *
1571 * @param pVmxTransient The VMX-transient structure.
1572 */
1573DECLINLINE(void) hmR0VmxReadExitQualVmcs(PVMXTRANSIENT pVmxTransient)
1574{
1575 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_QUALIFICATION))
1576 {
1577 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1578 AssertRC(rc);
1579 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION;
1580 }
1581}
1582
1583
1584/**
1585 * Reads the Guest-linear address from the VMCS into the VMX transient structure.
1586 *
1587 * @param pVmxTransient The VMX-transient structure.
1588 */
1589DECLINLINE(void) hmR0VmxReadGuestLinearAddrVmcs(PVMXTRANSIENT pVmxTransient)
1590{
1591 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_LINEAR_ADDR))
1592 {
1593 int rc = VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1594 AssertRC(rc);
1595 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_LINEAR_ADDR;
1596 }
1597}
1598
1599
1600/**
1601 * Reads the Guest-physical address from the VMCS into the VMX transient structure.
1602 *
1603 * @param pVmxTransient The VMX-transient structure.
1604 */
1605DECLINLINE(void) hmR0VmxReadGuestPhysicalAddrVmcs(PVMXTRANSIENT pVmxTransient)
1606{
1607 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PHYSICAL_ADDR))
1608 {
1609 int rc = VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1610 AssertRC(rc);
1611 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PHYSICAL_ADDR;
1612 }
1613}
1614
1615#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1616/**
1617 * Reads the Guest pending-debug exceptions from the VMCS into the VMX transient
1618 * structure.
1619 *
1620 * @param pVmxTransient The VMX-transient structure.
1621 */
1622DECLINLINE(void) hmR0VmxReadGuestPendingDbgXctps(PVMXTRANSIENT pVmxTransient)
1623{
1624 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PENDING_DBG_XCPTS))
1625 {
1626 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &pVmxTransient->uGuestPendingDbgXcpts);
1627 AssertRC(rc);
1628 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PENDING_DBG_XCPTS;
1629 }
1630}
1631#endif
1632
1633/**
1634 * Reads the IDT-vectoring information field from the VMCS into the VMX
1635 * transient structure.
1636 *
1637 * @param pVmxTransient The VMX-transient structure.
1638 *
1639 * @remarks No-long-jump zone!!!
1640 */
1641DECLINLINE(void) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
1642{
1643 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_INFO))
1644 {
1645 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1646 AssertRC(rc);
1647 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_INFO;
1648 }
1649}
1650
1651
1652/**
1653 * Reads the IDT-vectoring error code from the VMCS into the VMX
1654 * transient structure.
1655 *
1656 * @param pVmxTransient The VMX-transient structure.
1657 */
1658DECLINLINE(void) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1659{
1660 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_ERROR_CODE))
1661 {
1662 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1663 AssertRC(rc);
1664 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_ERROR_CODE;
1665 }
1666}
1667
1668#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
1669/**
1670 * Reads all relevant read-only VMCS fields into the VMX transient structure.
1671 *
1672 * @param pVmxTransient The VMX-transient structure.
1673 */
1674static void hmR0VmxReadAllRoFieldsVmcs(PVMXTRANSIENT pVmxTransient)
1675{
1676 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1677 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1678 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1679 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1680 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1681 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1682 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1683 rc |= VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1684 rc |= VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1685 AssertRC(rc);
1686 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION
1687 | HMVMX_READ_EXIT_INSTR_LEN
1688 | HMVMX_READ_EXIT_INSTR_INFO
1689 | HMVMX_READ_IDT_VECTORING_INFO
1690 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1691 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1692 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1693 | HMVMX_READ_GUEST_LINEAR_ADDR
1694 | HMVMX_READ_GUEST_PHYSICAL_ADDR;
1695}
1696#endif
1697
1698/**
1699 * Enters VMX root mode operation on the current CPU.
1700 *
1701 * @returns VBox status code.
1702 * @param pHostCpu The HM physical-CPU structure.
1703 * @param pVM The cross context VM structure. Can be
1704 * NULL, after a resume.
1705 * @param HCPhysCpuPage Physical address of the VMXON region.
1706 * @param pvCpuPage Pointer to the VMXON region.
1707 */
1708static int hmR0VmxEnterRootMode(PHMPHYSCPU pHostCpu, PVMCC pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
1709{
1710 Assert(pHostCpu);
1711 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
1712 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
1713 Assert(pvCpuPage);
1714 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1715
1716 if (pVM)
1717 {
1718 /* Write the VMCS revision identifier to the VMXON region. */
1719 *(uint32_t *)pvCpuPage = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
1720 }
1721
1722 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
1723 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1724
1725 /* Enable the VMX bit in CR4 if necessary. */
1726 RTCCUINTREG const uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
1727
1728 /* Record whether VMXE was already prior to us enabling it above. */
1729 pHostCpu->fVmxeAlreadyEnabled = RT_BOOL(uOldCr4 & X86_CR4_VMXE);
1730
1731 /* Enter VMX root mode. */
1732 int rc = VMXEnable(HCPhysCpuPage);
1733 if (RT_FAILURE(rc))
1734 {
1735 /* Restore CR4.VMXE if it was not set prior to our attempt to set it above. */
1736 if (!pHostCpu->fVmxeAlreadyEnabled)
1737 SUPR0ChangeCR4(0 /* fOrMask */, ~(uint64_t)X86_CR4_VMXE);
1738
1739 if (pVM)
1740 pVM->hm.s.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
1741 }
1742
1743 /* Restore interrupts. */
1744 ASMSetFlags(fEFlags);
1745 return rc;
1746}
1747
1748
1749/**
1750 * Exits VMX root mode operation on the current CPU.
1751 *
1752 * @returns VBox status code.
1753 * @param pHostCpu The HM physical-CPU structure.
1754 */
1755static int hmR0VmxLeaveRootMode(PHMPHYSCPU pHostCpu)
1756{
1757 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1758
1759 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
1760 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1761
1762 /* If we're for some reason not in VMX root mode, then don't leave it. */
1763 RTCCUINTREG const uHostCr4 = ASMGetCR4();
1764
1765 int rc;
1766 if (uHostCr4 & X86_CR4_VMXE)
1767 {
1768 /* Exit VMX root mode and clear the VMX bit in CR4. */
1769 VMXDisable();
1770
1771 /* Clear CR4.VMXE only if it was clear prior to use setting it. */
1772 if (!pHostCpu->fVmxeAlreadyEnabled)
1773 SUPR0ChangeCR4(0 /* fOrMask */, ~(uint64_t)X86_CR4_VMXE);
1774
1775 rc = VINF_SUCCESS;
1776 }
1777 else
1778 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
1779
1780 /* Restore interrupts. */
1781 ASMSetFlags(fEFlags);
1782 return rc;
1783}
1784
1785
1786/**
1787 * Allocates pages specified as specified by an array of VMX page allocation info
1788 * objects.
1789 *
1790 * The pages contents are zero'd after allocation.
1791 *
1792 * @returns VBox status code.
1793 * @param phMemObj Where to return the handle to the allocation.
1794 * @param paAllocInfo The pointer to the first element of the VMX
1795 * page-allocation info object array.
1796 * @param cEntries The number of elements in the @a paAllocInfo array.
1797 */
1798static int hmR0VmxPagesAllocZ(PRTR0MEMOBJ phMemObj, PVMXPAGEALLOCINFO paAllocInfo, uint32_t cEntries)
1799{
1800 *phMemObj = NIL_RTR0MEMOBJ;
1801
1802 /* Figure out how many pages to allocate. */
1803 uint32_t cPages = 0;
1804 for (uint32_t iPage = 0; iPage < cEntries; iPage++)
1805 cPages += !!paAllocInfo[iPage].fValid;
1806
1807 /* Allocate the pages. */
1808 if (cPages)
1809 {
1810 size_t const cbPages = cPages << PAGE_SHIFT;
1811 int rc = RTR0MemObjAllocPage(phMemObj, cbPages, false /* fExecutable */);
1812 if (RT_FAILURE(rc))
1813 return rc;
1814
1815 /* Zero the contents and assign each page to the corresponding VMX page-allocation entry. */
1816 void *pvFirstPage = RTR0MemObjAddress(*phMemObj);
1817 RT_BZERO(pvFirstPage, cbPages);
1818
1819 uint32_t iPage = 0;
1820 for (uint32_t i = 0; i < cEntries; i++)
1821 if (paAllocInfo[i].fValid)
1822 {
1823 RTHCPHYS const HCPhysPage = RTR0MemObjGetPagePhysAddr(*phMemObj, iPage);
1824 void *pvPage = (void *)((uintptr_t)pvFirstPage + (iPage << X86_PAGE_4K_SHIFT));
1825 Assert(HCPhysPage && HCPhysPage != NIL_RTHCPHYS);
1826 AssertPtr(pvPage);
1827
1828 Assert(paAllocInfo[iPage].pHCPhys);
1829 Assert(paAllocInfo[iPage].ppVirt);
1830 *paAllocInfo[iPage].pHCPhys = HCPhysPage;
1831 *paAllocInfo[iPage].ppVirt = pvPage;
1832
1833 /* Move to next page. */
1834 ++iPage;
1835 }
1836
1837 /* Make sure all valid (requested) pages have been assigned. */
1838 Assert(iPage == cPages);
1839 }
1840 return VINF_SUCCESS;
1841}
1842
1843
1844/**
1845 * Frees pages allocated using hmR0VmxPagesAllocZ.
1846 *
1847 * @param phMemObj Pointer to the memory object handle. Will be set to
1848 * NIL.
1849 */
1850DECL_FORCE_INLINE(void) hmR0VmxPagesFree(PRTR0MEMOBJ phMemObj)
1851{
1852 /* We can cleanup wholesale since it's all one allocation. */
1853 if (*phMemObj != NIL_RTR0MEMOBJ)
1854 {
1855 RTR0MemObjFree(*phMemObj, true /* fFreeMappings */);
1856 *phMemObj = NIL_RTR0MEMOBJ;
1857 }
1858}
1859
1860
1861/**
1862 * Initializes a VMCS info. object.
1863 *
1864 * @param pVmcsInfo The VMCS info. object.
1865 * @param pVmcsInfoShared The VMCS info. object shared with ring-3.
1866 */
1867static void hmR0VmxVmcsInfoInit(PVMXVMCSINFO pVmcsInfo, PVMXVMCSINFOSHARED pVmcsInfoShared)
1868{
1869 RT_ZERO(*pVmcsInfo);
1870 RT_ZERO(*pVmcsInfoShared);
1871
1872 pVmcsInfo->pShared = pVmcsInfoShared;
1873 Assert(pVmcsInfo->hMemObj == NIL_RTR0MEMOBJ);
1874 pVmcsInfo->HCPhysVmcs = NIL_RTHCPHYS;
1875 pVmcsInfo->HCPhysShadowVmcs = NIL_RTHCPHYS;
1876 pVmcsInfo->HCPhysMsrBitmap = NIL_RTHCPHYS;
1877 pVmcsInfo->HCPhysGuestMsrLoad = NIL_RTHCPHYS;
1878 pVmcsInfo->HCPhysGuestMsrStore = NIL_RTHCPHYS;
1879 pVmcsInfo->HCPhysHostMsrLoad = NIL_RTHCPHYS;
1880 pVmcsInfo->HCPhysVirtApic = NIL_RTHCPHYS;
1881 pVmcsInfo->HCPhysEPTP = NIL_RTHCPHYS;
1882 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
1883 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
1884 pVmcsInfo->idHostCpuExec = NIL_RTCPUID;
1885}
1886
1887
1888/**
1889 * Frees the VT-x structures for a VMCS info. object.
1890 *
1891 * @param pVmcsInfo The VMCS info. object.
1892 * @param pVmcsInfoShared The VMCS info. object shared with ring-3.
1893 */
1894static void hmR0VmxVmcsInfoFree(PVMXVMCSINFO pVmcsInfo, PVMXVMCSINFOSHARED pVmcsInfoShared)
1895{
1896 hmR0VmxPagesFree(&pVmcsInfo->hMemObj);
1897 hmR0VmxVmcsInfoInit(pVmcsInfo, pVmcsInfoShared);
1898}
1899
1900
1901/**
1902 * Allocates the VT-x structures for a VMCS info. object.
1903 *
1904 * @returns VBox status code.
1905 * @param pVCpu The cross context virtual CPU structure.
1906 * @param pVmcsInfo The VMCS info. object.
1907 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
1908 *
1909 * @remarks The caller is expected to take care of any and all allocation failures.
1910 * This function will not perform any cleanup for failures half-way
1911 * through.
1912 */
1913static int hmR0VmxAllocVmcsInfo(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
1914{
1915 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
1916
1917 bool const fMsrBitmaps = RT_BOOL(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS);
1918 bool const fShadowVmcs = !fIsNstGstVmcs ? pVM->hm.s.vmx.fUseVmcsShadowing : pVM->cpum.ro.GuestFeatures.fVmxVmcsShadowing;
1919 Assert(!pVM->cpum.ro.GuestFeatures.fVmxVmcsShadowing); /* VMCS shadowing is not yet exposed to the guest. */
1920 VMXPAGEALLOCINFO aAllocInfo[] =
1921 {
1922 { true, 0 /* Unused */, &pVmcsInfo->HCPhysVmcs, &pVmcsInfo->pvVmcs },
1923 { true, 0 /* Unused */, &pVmcsInfo->HCPhysGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad },
1924 { true, 0 /* Unused */, &pVmcsInfo->HCPhysHostMsrLoad, &pVmcsInfo->pvHostMsrLoad },
1925 { fMsrBitmaps, 0 /* Unused */, &pVmcsInfo->HCPhysMsrBitmap, &pVmcsInfo->pvMsrBitmap },
1926 { fShadowVmcs, 0 /* Unused */, &pVmcsInfo->HCPhysShadowVmcs, &pVmcsInfo->pvShadowVmcs },
1927 };
1928
1929 int rc = hmR0VmxPagesAllocZ(&pVmcsInfo->hMemObj, &aAllocInfo[0], RT_ELEMENTS(aAllocInfo));
1930 if (RT_FAILURE(rc))
1931 return rc;
1932
1933 /*
1934 * We use the same page for VM-entry MSR-load and VM-exit MSR store areas.
1935 * Because they contain a symmetric list of guest MSRs to load on VM-entry and store on VM-exit.
1936 */
1937 AssertCompile(RT_ELEMENTS(aAllocInfo) > 0);
1938 Assert(pVmcsInfo->HCPhysGuestMsrLoad != NIL_RTHCPHYS);
1939 pVmcsInfo->pvGuestMsrStore = pVmcsInfo->pvGuestMsrLoad;
1940 pVmcsInfo->HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrLoad;
1941
1942 /*
1943 * Get the virtual-APIC page rather than allocating them again.
1944 */
1945 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
1946 {
1947 if (!fIsNstGstVmcs)
1948 {
1949 if (PDMHasApic(pVM))
1950 {
1951 rc = APICGetApicPageForCpu(pVCpu, &pVmcsInfo->HCPhysVirtApic, (PRTR0PTR)&pVmcsInfo->pbVirtApic, NULL /*pR3Ptr*/);
1952 if (RT_FAILURE(rc))
1953 return rc;
1954 Assert(pVmcsInfo->pbVirtApic);
1955 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1956 }
1957 }
1958 else
1959 {
1960 pVmcsInfo->pbVirtApic = (uint8_t *)CPUMGetGuestVmxVirtApicPage(&pVCpu->cpum.GstCtx, &pVmcsInfo->HCPhysVirtApic);
1961 Assert(pVmcsInfo->pbVirtApic);
1962 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1963 }
1964 }
1965
1966 return VINF_SUCCESS;
1967}
1968
1969
1970/**
1971 * Free all VT-x structures for the VM.
1972 *
1973 * @returns IPRT status code.
1974 * @param pVM The cross context VM structure.
1975 */
1976static void hmR0VmxStructsFree(PVMCC pVM)
1977{
1978 hmR0VmxPagesFree(&pVM->hmr0.s.vmx.hMemObj);
1979#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1980 if (pVM->hm.s.vmx.fUseVmcsShadowing)
1981 {
1982 RTMemFree(pVM->hmr0.s.vmx.paShadowVmcsFields);
1983 pVM->hmr0.s.vmx.paShadowVmcsFields = NULL;
1984 RTMemFree(pVM->hmr0.s.vmx.paShadowVmcsRoFields);
1985 pVM->hmr0.s.vmx.paShadowVmcsRoFields = NULL;
1986 }
1987#endif
1988
1989 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1990 {
1991 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
1992 hmR0VmxVmcsInfoFree(&pVCpu->hmr0.s.vmx.VmcsInfo, &pVCpu->hm.s.vmx.VmcsInfo);
1993#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1994 if (pVM->cpum.ro.GuestFeatures.fVmx)
1995 hmR0VmxVmcsInfoFree(&pVCpu->hmr0.s.vmx.VmcsInfoNstGst, &pVCpu->hm.s.vmx.VmcsInfoNstGst);
1996#endif
1997 }
1998}
1999
2000
2001/**
2002 * Allocate all VT-x structures for the VM.
2003 *
2004 * @returns IPRT status code.
2005 * @param pVM The cross context VM structure.
2006 *
2007 * @remarks This functions will cleanup on memory allocation failures.
2008 */
2009static int hmR0VmxStructsAlloc(PVMCC pVM)
2010{
2011 /*
2012 * Sanity check the VMCS size reported by the CPU as we assume 4KB allocations.
2013 * The VMCS size cannot be more than 4096 bytes.
2014 *
2015 * See Intel spec. Appendix A.1 "Basic VMX Information".
2016 */
2017 uint32_t const cbVmcs = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_SIZE);
2018 if (cbVmcs <= X86_PAGE_4K_SIZE)
2019 { /* likely */ }
2020 else
2021 {
2022 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_INVALID_VMCS_SIZE;
2023 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2024 }
2025
2026 /*
2027 * Allocate per-VM VT-x structures.
2028 */
2029 bool const fVirtApicAccess = RT_BOOL(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
2030 bool const fUseVmcsShadowing = pVM->hm.s.vmx.fUseVmcsShadowing;
2031 VMXPAGEALLOCINFO aAllocInfo[] =
2032 {
2033 { fVirtApicAccess, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysApicAccess, (PRTR0PTR)&pVM->hmr0.s.vmx.pbApicAccess },
2034 { fUseVmcsShadowing, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysVmreadBitmap, &pVM->hmr0.s.vmx.pvVmreadBitmap },
2035 { fUseVmcsShadowing, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysVmwriteBitmap, &pVM->hmr0.s.vmx.pvVmwriteBitmap },
2036#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2037 { true, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysScratch, (PRTR0PTR)&pVM->hmr0.s.vmx.pbScratch },
2038#endif
2039 };
2040
2041 int rc = hmR0VmxPagesAllocZ(&pVM->hmr0.s.vmx.hMemObj, &aAllocInfo[0], RT_ELEMENTS(aAllocInfo));
2042 if (RT_SUCCESS(rc))
2043 {
2044#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2045 /* Allocate the shadow VMCS-fields array. */
2046 if (fUseVmcsShadowing)
2047 {
2048 Assert(!pVM->hmr0.s.vmx.cShadowVmcsFields);
2049 Assert(!pVM->hmr0.s.vmx.cShadowVmcsRoFields);
2050 pVM->hmr0.s.vmx.paShadowVmcsFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
2051 pVM->hmr0.s.vmx.paShadowVmcsRoFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
2052 if (!pVM->hmr0.s.vmx.paShadowVmcsFields || !pVM->hmr0.s.vmx.paShadowVmcsRoFields)
2053 rc = VERR_NO_MEMORY;
2054 }
2055#endif
2056
2057 /*
2058 * Allocate per-VCPU VT-x structures.
2059 */
2060 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus && RT_SUCCESS(rc); idCpu++)
2061 {
2062 /* Allocate the guest VMCS structures. */
2063 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2064 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
2065
2066#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2067 /* Allocate the nested-guest VMCS structures, when the VMX feature is exposed to the guest. */
2068 if (pVM->cpum.ro.GuestFeatures.fVmx && RT_SUCCESS(rc))
2069 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
2070#endif
2071 }
2072 if (RT_SUCCESS(rc))
2073 return VINF_SUCCESS;
2074 }
2075 hmR0VmxStructsFree(pVM);
2076 return rc;
2077}
2078
2079
2080/**
2081 * Pre-initializes non-zero fields in VMX structures that will be allocated.
2082 *
2083 * @param pVM The cross context VM structure.
2084 */
2085static void hmR0VmxStructsInit(PVMCC pVM)
2086{
2087 /* Paranoia. */
2088 Assert(pVM->hmr0.s.vmx.pbApicAccess == NULL);
2089#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2090 Assert(pVM->hmr0.s.vmx.pbScratch == NULL);
2091#endif
2092
2093 /*
2094 * Initialize members up-front so we can cleanup en masse on allocation failures.
2095 */
2096#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2097 pVM->hmr0.s.vmx.HCPhysScratch = NIL_RTHCPHYS;
2098#endif
2099 pVM->hmr0.s.vmx.HCPhysApicAccess = NIL_RTHCPHYS;
2100 pVM->hmr0.s.vmx.HCPhysVmreadBitmap = NIL_RTHCPHYS;
2101 pVM->hmr0.s.vmx.HCPhysVmwriteBitmap = NIL_RTHCPHYS;
2102 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
2103 {
2104 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2105 hmR0VmxVmcsInfoInit(&pVCpu->hmr0.s.vmx.VmcsInfo, &pVCpu->hm.s.vmx.VmcsInfo);
2106 hmR0VmxVmcsInfoInit(&pVCpu->hmr0.s.vmx.VmcsInfoNstGst, &pVCpu->hm.s.vmx.VmcsInfoNstGst);
2107 }
2108}
2109
2110#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2111/**
2112 * Returns whether an MSR at the given MSR-bitmap offset is intercepted or not.
2113 *
2114 * @returns @c true if the MSR is intercepted, @c false otherwise.
2115 * @param pvMsrBitmap The MSR bitmap.
2116 * @param offMsr The MSR byte offset.
2117 * @param iBit The bit offset from the byte offset.
2118 */
2119DECLINLINE(bool) hmR0VmxIsMsrBitSet(const void *pvMsrBitmap, uint16_t offMsr, int32_t iBit)
2120{
2121 uint8_t const * const pbMsrBitmap = (uint8_t const * const)pvMsrBitmap;
2122 Assert(pbMsrBitmap);
2123 Assert(offMsr + (iBit >> 3) <= X86_PAGE_4K_SIZE);
2124 return ASMBitTest(pbMsrBitmap + offMsr, iBit);
2125}
2126#endif
2127
2128/**
2129 * Sets the permission bits for the specified MSR in the given MSR bitmap.
2130 *
2131 * If the passed VMCS is a nested-guest VMCS, this function ensures that the
2132 * read/write intercept is cleared from the MSR bitmap used for hardware-assisted
2133 * VMX execution of the nested-guest, only if nested-guest is also not intercepting
2134 * the read/write access of this MSR.
2135 *
2136 * @param pVCpu The cross context virtual CPU structure.
2137 * @param pVmcsInfo The VMCS info. object.
2138 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2139 * @param idMsr The MSR value.
2140 * @param fMsrpm The MSR permissions (see VMXMSRPM_XXX). This must
2141 * include both a read -and- a write permission!
2142 *
2143 * @sa CPUMGetVmxMsrPermission.
2144 * @remarks Can be called with interrupts disabled.
2145 */
2146static void hmR0VmxSetMsrPermission(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs, uint32_t idMsr, uint32_t fMsrpm)
2147{
2148 uint8_t *pbMsrBitmap = (uint8_t *)pVmcsInfo->pvMsrBitmap;
2149 Assert(pbMsrBitmap);
2150 Assert(VMXMSRPM_IS_FLAG_VALID(fMsrpm));
2151
2152 /*
2153 * MSR-bitmap Layout:
2154 * Byte index MSR range Interpreted as
2155 * 0x000 - 0x3ff 0x00000000 - 0x00001fff Low MSR read bits.
2156 * 0x400 - 0x7ff 0xc0000000 - 0xc0001fff High MSR read bits.
2157 * 0x800 - 0xbff 0x00000000 - 0x00001fff Low MSR write bits.
2158 * 0xc00 - 0xfff 0xc0000000 - 0xc0001fff High MSR write bits.
2159 *
2160 * A bit corresponding to an MSR within the above range causes a VM-exit
2161 * if the bit is 1 on executions of RDMSR/WRMSR. If an MSR falls out of
2162 * the MSR range, it always cause a VM-exit.
2163 *
2164 * See Intel spec. 24.6.9 "MSR-Bitmap Address".
2165 */
2166 uint16_t const offBitmapRead = 0;
2167 uint16_t const offBitmapWrite = 0x800;
2168 uint16_t offMsr;
2169 int32_t iBit;
2170 if (idMsr <= UINT32_C(0x00001fff))
2171 {
2172 offMsr = 0;
2173 iBit = idMsr;
2174 }
2175 else if (idMsr - UINT32_C(0xc0000000) <= UINT32_C(0x00001fff))
2176 {
2177 offMsr = 0x400;
2178 iBit = idMsr - UINT32_C(0xc0000000);
2179 }
2180 else
2181 AssertMsgFailedReturnVoid(("Invalid MSR %#RX32\n", idMsr));
2182
2183 /*
2184 * Set the MSR read permission.
2185 */
2186 uint16_t const offMsrRead = offBitmapRead + offMsr;
2187 Assert(offMsrRead + (iBit >> 3) < offBitmapWrite);
2188 if (fMsrpm & VMXMSRPM_ALLOW_RD)
2189 {
2190#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2191 bool const fClear = !fIsNstGstVmcs ? true
2192 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrRead, iBit);
2193#else
2194 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2195 bool const fClear = true;
2196#endif
2197 if (fClear)
2198 ASMBitClear(pbMsrBitmap + offMsrRead, iBit);
2199 }
2200 else
2201 ASMBitSet(pbMsrBitmap + offMsrRead, iBit);
2202
2203 /*
2204 * Set the MSR write permission.
2205 */
2206 uint16_t const offMsrWrite = offBitmapWrite + offMsr;
2207 Assert(offMsrWrite + (iBit >> 3) < X86_PAGE_4K_SIZE);
2208 if (fMsrpm & VMXMSRPM_ALLOW_WR)
2209 {
2210#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2211 bool const fClear = !fIsNstGstVmcs ? true
2212 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrWrite, iBit);
2213#else
2214 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2215 bool const fClear = true;
2216#endif
2217 if (fClear)
2218 ASMBitClear(pbMsrBitmap + offMsrWrite, iBit);
2219 }
2220 else
2221 ASMBitSet(pbMsrBitmap + offMsrWrite, iBit);
2222}
2223
2224
2225/**
2226 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
2227 * area.
2228 *
2229 * @returns VBox status code.
2230 * @param pVCpu The cross context virtual CPU structure.
2231 * @param pVmcsInfo The VMCS info. object.
2232 * @param cMsrs The number of MSRs.
2233 */
2234static int hmR0VmxSetAutoLoadStoreMsrCount(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t cMsrs)
2235{
2236 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
2237 uint32_t const cMaxSupportedMsrs = VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc);
2238 if (RT_LIKELY(cMsrs < cMaxSupportedMsrs))
2239 {
2240 /* Commit the MSR counts to the VMCS and update the cache. */
2241 if (pVmcsInfo->cEntryMsrLoad != cMsrs)
2242 {
2243 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2244 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs); AssertRC(rc);
2245 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2246 pVmcsInfo->cEntryMsrLoad = cMsrs;
2247 pVmcsInfo->cExitMsrStore = cMsrs;
2248 pVmcsInfo->cExitMsrLoad = cMsrs;
2249 }
2250 return VINF_SUCCESS;
2251 }
2252
2253 LogRel(("Auto-load/store MSR count exceeded! cMsrs=%u MaxSupported=%u\n", cMsrs, cMaxSupportedMsrs));
2254 pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
2255 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2256}
2257
2258
2259/**
2260 * Adds a new (or updates the value of an existing) guest/host MSR
2261 * pair to be swapped during the world-switch as part of the
2262 * auto-load/store MSR area in the VMCS.
2263 *
2264 * @returns VBox status code.
2265 * @param pVCpu The cross context virtual CPU structure.
2266 * @param pVmxTransient The VMX-transient structure.
2267 * @param idMsr The MSR.
2268 * @param uGuestMsrValue Value of the guest MSR.
2269 * @param fSetReadWrite Whether to set the guest read/write access of this
2270 * MSR (thus not causing a VM-exit).
2271 * @param fUpdateHostMsr Whether to update the value of the host MSR if
2272 * necessary.
2273 */
2274static int hmR0VmxAddAutoLoadStoreMsr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t idMsr, uint64_t uGuestMsrValue,
2275 bool fSetReadWrite, bool fUpdateHostMsr)
2276{
2277 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2278 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2279 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2280 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2281 uint32_t i;
2282
2283 /* Paranoia. */
2284 Assert(pGuestMsrLoad);
2285
2286 LogFlowFunc(("pVCpu=%p idMsr=%#RX32 uGuestMsrValue=%#RX64\n", pVCpu, idMsr, uGuestMsrValue));
2287
2288 /* Check if the MSR already exists in the VM-entry MSR-load area. */
2289 for (i = 0; i < cMsrs; i++)
2290 {
2291 if (pGuestMsrLoad[i].u32Msr == idMsr)
2292 break;
2293 }
2294
2295 bool fAdded = false;
2296 if (i == cMsrs)
2297 {
2298 /* The MSR does not exist, bump the MSR count to make room for the new MSR. */
2299 ++cMsrs;
2300 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2301 AssertMsgRCReturn(rc, ("Insufficient space to add MSR to VM-entry MSR-load/store area %u\n", idMsr), rc);
2302
2303 /* Set the guest to read/write this MSR without causing VM-exits. */
2304 if ( fSetReadWrite
2305 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
2306 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_ALLOW_RD_WR);
2307
2308 Log4Func(("Added MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2309 fAdded = true;
2310 }
2311
2312 /* Update the MSR value for the newly added or already existing MSR. */
2313 pGuestMsrLoad[i].u32Msr = idMsr;
2314 pGuestMsrLoad[i].u64Value = uGuestMsrValue;
2315
2316 /* Create the corresponding slot in the VM-exit MSR-store area if we use a different page. */
2317 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2318 {
2319 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2320 pGuestMsrStore[i].u32Msr = idMsr;
2321 pGuestMsrStore[i].u64Value = uGuestMsrValue;
2322 }
2323
2324 /* Update the corresponding slot in the host MSR area. */
2325 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2326 Assert(pHostMsr != pVmcsInfo->pvGuestMsrLoad);
2327 Assert(pHostMsr != pVmcsInfo->pvGuestMsrStore);
2328 pHostMsr[i].u32Msr = idMsr;
2329
2330 /*
2331 * Only if the caller requests to update the host MSR value AND we've newly added the
2332 * MSR to the host MSR area do we actually update the value. Otherwise, it will be
2333 * updated by hmR0VmxUpdateAutoLoadHostMsrs().
2334 *
2335 * We do this for performance reasons since reading MSRs may be quite expensive.
2336 */
2337 if (fAdded)
2338 {
2339 if (fUpdateHostMsr)
2340 {
2341 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2342 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2343 pHostMsr[i].u64Value = ASMRdMsr(idMsr);
2344 }
2345 else
2346 {
2347 /* Someone else can do the work. */
2348 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
2349 }
2350 }
2351 return VINF_SUCCESS;
2352}
2353
2354
2355/**
2356 * Removes a guest/host MSR pair to be swapped during the world-switch from the
2357 * auto-load/store MSR area in the VMCS.
2358 *
2359 * @returns VBox status code.
2360 * @param pVCpu The cross context virtual CPU structure.
2361 * @param pVmxTransient The VMX-transient structure.
2362 * @param idMsr The MSR.
2363 */
2364static int hmR0VmxRemoveAutoLoadStoreMsr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t idMsr)
2365{
2366 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2367 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2368 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2369 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2370
2371 LogFlowFunc(("pVCpu=%p idMsr=%#RX32\n", pVCpu, idMsr));
2372
2373 for (uint32_t i = 0; i < cMsrs; i++)
2374 {
2375 /* Find the MSR. */
2376 if (pGuestMsrLoad[i].u32Msr == idMsr)
2377 {
2378 /*
2379 * If it's the last MSR, we only need to reduce the MSR count.
2380 * If it's -not- the last MSR, copy the last MSR in place of it and reduce the MSR count.
2381 */
2382 if (i < cMsrs - 1)
2383 {
2384 /* Remove it from the VM-entry MSR-load area. */
2385 pGuestMsrLoad[i].u32Msr = pGuestMsrLoad[cMsrs - 1].u32Msr;
2386 pGuestMsrLoad[i].u64Value = pGuestMsrLoad[cMsrs - 1].u64Value;
2387
2388 /* Remove it from the VM-exit MSR-store area if it's in a different page. */
2389 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2390 {
2391 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2392 Assert(pGuestMsrStore[i].u32Msr == idMsr);
2393 pGuestMsrStore[i].u32Msr = pGuestMsrStore[cMsrs - 1].u32Msr;
2394 pGuestMsrStore[i].u64Value = pGuestMsrStore[cMsrs - 1].u64Value;
2395 }
2396
2397 /* Remove it from the VM-exit MSR-load area. */
2398 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2399 Assert(pHostMsr[i].u32Msr == idMsr);
2400 pHostMsr[i].u32Msr = pHostMsr[cMsrs - 1].u32Msr;
2401 pHostMsr[i].u64Value = pHostMsr[cMsrs - 1].u64Value;
2402 }
2403
2404 /* Reduce the count to reflect the removed MSR and bail. */
2405 --cMsrs;
2406 break;
2407 }
2408 }
2409
2410 /* Update the VMCS if the count changed (meaning the MSR was found and removed). */
2411 if (cMsrs != pVmcsInfo->cEntryMsrLoad)
2412 {
2413 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2414 AssertRCReturn(rc, rc);
2415
2416 /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
2417 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2418 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR);
2419
2420 Log4Func(("Removed MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2421 return VINF_SUCCESS;
2422 }
2423
2424 return VERR_NOT_FOUND;
2425}
2426
2427
2428/**
2429 * Checks if the specified guest MSR is part of the VM-entry MSR-load area.
2430 *
2431 * @returns @c true if found, @c false otherwise.
2432 * @param pVmcsInfo The VMCS info. object.
2433 * @param idMsr The MSR to find.
2434 */
2435static bool hmR0VmxIsAutoLoadGuestMsr(PCVMXVMCSINFO pVmcsInfo, uint32_t idMsr)
2436{
2437 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2438 uint32_t const cMsrs = pVmcsInfo->cEntryMsrLoad;
2439 Assert(pMsrs);
2440 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
2441 for (uint32_t i = 0; i < cMsrs; i++)
2442 {
2443 if (pMsrs[i].u32Msr == idMsr)
2444 return true;
2445 }
2446 return false;
2447}
2448
2449
2450/**
2451 * Updates the value of all host MSRs in the VM-exit MSR-load area.
2452 *
2453 * @param pVCpu The cross context virtual CPU structure.
2454 * @param pVmcsInfo The VMCS info. object.
2455 *
2456 * @remarks No-long-jump zone!!!
2457 */
2458static void hmR0VmxUpdateAutoLoadHostMsrs(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2459{
2460 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2461
2462 PVMXAUTOMSR pHostMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2463 uint32_t const cMsrs = pVmcsInfo->cExitMsrLoad;
2464 Assert(pHostMsrLoad);
2465 Assert(sizeof(*pHostMsrLoad) * cMsrs <= X86_PAGE_4K_SIZE);
2466 LogFlowFunc(("pVCpu=%p cMsrs=%u\n", pVCpu, cMsrs));
2467 for (uint32_t i = 0; i < cMsrs; i++)
2468 {
2469 /*
2470 * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
2471 * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
2472 */
2473 if (pHostMsrLoad[i].u32Msr == MSR_K6_EFER)
2474 pHostMsrLoad[i].u64Value = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer;
2475 else
2476 pHostMsrLoad[i].u64Value = ASMRdMsr(pHostMsrLoad[i].u32Msr);
2477 }
2478}
2479
2480
2481/**
2482 * Saves a set of host MSRs to allow read/write passthru access to the guest and
2483 * perform lazy restoration of the host MSRs while leaving VT-x.
2484 *
2485 * @param pVCpu The cross context virtual CPU structure.
2486 *
2487 * @remarks No-long-jump zone!!!
2488 */
2489static void hmR0VmxLazySaveHostMsrs(PVMCPUCC pVCpu)
2490{
2491 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2492
2493 /*
2494 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap accesses in hmR0VmxSetupVmcsProcCtls().
2495 */
2496 if (!(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST))
2497 {
2498 Assert(!(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)); /* Guest MSRs better not be loaded now. */
2499 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2500 {
2501 pVCpu->hmr0.s.vmx.u64HostMsrLStar = ASMRdMsr(MSR_K8_LSTAR);
2502 pVCpu->hmr0.s.vmx.u64HostMsrStar = ASMRdMsr(MSR_K6_STAR);
2503 pVCpu->hmr0.s.vmx.u64HostMsrSfMask = ASMRdMsr(MSR_K8_SF_MASK);
2504 pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
2505 }
2506 pVCpu->hmr0.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
2507 }
2508}
2509
2510
2511/**
2512 * Checks whether the MSR belongs to the set of guest MSRs that we restore
2513 * lazily while leaving VT-x.
2514 *
2515 * @returns true if it does, false otherwise.
2516 * @param pVCpu The cross context virtual CPU structure.
2517 * @param idMsr The MSR to check.
2518 */
2519static bool hmR0VmxIsLazyGuestMsr(PCVMCPUCC pVCpu, uint32_t idMsr)
2520{
2521 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2522 {
2523 switch (idMsr)
2524 {
2525 case MSR_K8_LSTAR:
2526 case MSR_K6_STAR:
2527 case MSR_K8_SF_MASK:
2528 case MSR_K8_KERNEL_GS_BASE:
2529 return true;
2530 }
2531 }
2532 return false;
2533}
2534
2535
2536/**
2537 * Loads a set of guests MSRs to allow read/passthru to the guest.
2538 *
2539 * The name of this function is slightly confusing. This function does NOT
2540 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
2541 * common prefix for functions dealing with "lazy restoration" of the shared
2542 * MSRs.
2543 *
2544 * @param pVCpu The cross context virtual CPU structure.
2545 *
2546 * @remarks No-long-jump zone!!!
2547 */
2548static void hmR0VmxLazyLoadGuestMsrs(PVMCPUCC pVCpu)
2549{
2550 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2551 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2552
2553 Assert(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2554 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2555 {
2556 /*
2557 * If the guest MSRs are not loaded -and- if all the guest MSRs are identical
2558 * to the MSRs on the CPU (which are the saved host MSRs, see assertion above) then
2559 * we can skip a few MSR writes.
2560 *
2561 * Otherwise, it implies either 1. they're not loaded, or 2. they're loaded but the
2562 * guest MSR values in the guest-CPU context might be different to what's currently
2563 * loaded in the CPU. In either case, we need to write the new guest MSR values to the
2564 * CPU, see @bugref{8728}.
2565 */
2566 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2567 if ( !(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2568 && pCtx->msrKERNELGSBASE == pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase
2569 && pCtx->msrLSTAR == pVCpu->hmr0.s.vmx.u64HostMsrLStar
2570 && pCtx->msrSTAR == pVCpu->hmr0.s.vmx.u64HostMsrStar
2571 && pCtx->msrSFMASK == pVCpu->hmr0.s.vmx.u64HostMsrSfMask)
2572 {
2573#ifdef VBOX_STRICT
2574 Assert(ASMRdMsr(MSR_K8_KERNEL_GS_BASE) == pCtx->msrKERNELGSBASE);
2575 Assert(ASMRdMsr(MSR_K8_LSTAR) == pCtx->msrLSTAR);
2576 Assert(ASMRdMsr(MSR_K6_STAR) == pCtx->msrSTAR);
2577 Assert(ASMRdMsr(MSR_K8_SF_MASK) == pCtx->msrSFMASK);
2578#endif
2579 }
2580 else
2581 {
2582 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pCtx->msrKERNELGSBASE);
2583 ASMWrMsr(MSR_K8_LSTAR, pCtx->msrLSTAR);
2584 ASMWrMsr(MSR_K6_STAR, pCtx->msrSTAR);
2585 ASMWrMsr(MSR_K8_SF_MASK, pCtx->msrSFMASK);
2586 }
2587 }
2588 pVCpu->hmr0.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
2589}
2590
2591
2592/**
2593 * Performs lazy restoration of the set of host MSRs if they were previously
2594 * loaded with guest MSR values.
2595 *
2596 * @param pVCpu The cross context virtual CPU structure.
2597 *
2598 * @remarks No-long-jump zone!!!
2599 * @remarks The guest MSRs should have been saved back into the guest-CPU
2600 * context by hmR0VmxImportGuestState()!!!
2601 */
2602static void hmR0VmxLazyRestoreHostMsrs(PVMCPUCC pVCpu)
2603{
2604 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2605 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2606
2607 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2608 {
2609 Assert(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2610 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2611 {
2612 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hmr0.s.vmx.u64HostMsrLStar);
2613 ASMWrMsr(MSR_K6_STAR, pVCpu->hmr0.s.vmx.u64HostMsrStar);
2614 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hmr0.s.vmx.u64HostMsrSfMask);
2615 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase);
2616 }
2617 }
2618 pVCpu->hmr0.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
2619}
2620
2621
2622/**
2623 * Verifies that our cached values of the VMCS fields are all consistent with
2624 * what's actually present in the VMCS.
2625 *
2626 * @returns VBox status code.
2627 * @retval VINF_SUCCESS if all our caches match their respective VMCS fields.
2628 * @retval VERR_VMX_VMCS_FIELD_CACHE_INVALID if a cache field doesn't match the
2629 * VMCS content. HMCPU error-field is
2630 * updated, see VMX_VCI_XXX.
2631 * @param pVCpu The cross context virtual CPU structure.
2632 * @param pVmcsInfo The VMCS info. object.
2633 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2634 */
2635static int hmR0VmxCheckCachedVmcsCtls(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2636{
2637 const char * const pcszVmcs = fIsNstGstVmcs ? "Nested-guest VMCS" : "VMCS";
2638
2639 uint32_t u32Val;
2640 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
2641 AssertRC(rc);
2642 AssertMsgReturnStmt(pVmcsInfo->u32EntryCtls == u32Val,
2643 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32EntryCtls, u32Val),
2644 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_ENTRY,
2645 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2646
2647 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
2648 AssertRC(rc);
2649 AssertMsgReturnStmt(pVmcsInfo->u32ExitCtls == u32Val,
2650 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ExitCtls, u32Val),
2651 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_EXIT,
2652 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2653
2654 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
2655 AssertRC(rc);
2656 AssertMsgReturnStmt(pVmcsInfo->u32PinCtls == u32Val,
2657 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32PinCtls, u32Val),
2658 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PIN_EXEC,
2659 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2660
2661 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
2662 AssertRC(rc);
2663 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls == u32Val,
2664 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls, u32Val),
2665 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC,
2666 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2667
2668 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2669 {
2670 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
2671 AssertRC(rc);
2672 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls2 == u32Val,
2673 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls2, u32Val),
2674 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC2,
2675 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2676 }
2677
2678 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val);
2679 AssertRC(rc);
2680 AssertMsgReturnStmt(pVmcsInfo->u32XcptBitmap == u32Val,
2681 ("%s exception bitmap mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32XcptBitmap, u32Val),
2682 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_XCPT_BITMAP,
2683 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2684
2685 uint64_t u64Val;
2686 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, &u64Val);
2687 AssertRC(rc);
2688 AssertMsgReturnStmt(pVmcsInfo->u64TscOffset == u64Val,
2689 ("%s TSC offset mismatch: Cache=%#RX64 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64TscOffset, u64Val),
2690 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_TSC_OFFSET,
2691 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2692
2693 NOREF(pcszVmcs);
2694 return VINF_SUCCESS;
2695}
2696
2697#ifdef VBOX_STRICT
2698
2699/**
2700 * Verifies that our cached host EFER MSR value has not changed since we cached it.
2701 *
2702 * @param pVCpu The cross context virtual CPU structure.
2703 * @param pVmcsInfo The VMCS info. object.
2704 */
2705static void hmR0VmxCheckHostEferMsr(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2706{
2707 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2708
2709 if (pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
2710 {
2711 uint64_t const uHostEferMsr = ASMRdMsr(MSR_K6_EFER);
2712 uint64_t const uHostEferMsrCache = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer;
2713 uint64_t uVmcsEferMsrVmcs;
2714 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &uVmcsEferMsrVmcs);
2715 AssertRC(rc);
2716
2717 AssertMsgReturnVoid(uHostEferMsr == uVmcsEferMsrVmcs,
2718 ("EFER Host/VMCS mismatch! host=%#RX64 vmcs=%#RX64\n", uHostEferMsr, uVmcsEferMsrVmcs));
2719 AssertMsgReturnVoid(uHostEferMsr == uHostEferMsrCache,
2720 ("EFER Host/Cache mismatch! host=%#RX64 cache=%#RX64\n", uHostEferMsr, uHostEferMsrCache));
2721 }
2722}
2723
2724
2725/**
2726 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
2727 * VMCS are correct.
2728 *
2729 * @param pVCpu The cross context virtual CPU structure.
2730 * @param pVmcsInfo The VMCS info. object.
2731 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2732 */
2733static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2734{
2735 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2736
2737 /* Read the various MSR-area counts from the VMCS. */
2738 uint32_t cEntryLoadMsrs;
2739 uint32_t cExitStoreMsrs;
2740 uint32_t cExitLoadMsrs;
2741 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cEntryLoadMsrs); AssertRC(rc);
2742 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cExitStoreMsrs); AssertRC(rc);
2743 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cExitLoadMsrs); AssertRC(rc);
2744
2745 /* Verify all the MSR counts are the same. */
2746 Assert(cEntryLoadMsrs == cExitStoreMsrs);
2747 Assert(cExitStoreMsrs == cExitLoadMsrs);
2748 uint32_t const cMsrs = cExitLoadMsrs;
2749
2750 /* Verify the MSR counts do not exceed the maximum count supported by the hardware. */
2751 Assert(cMsrs < VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc));
2752
2753 /* Verify the MSR counts are within the allocated page size. */
2754 Assert(sizeof(VMXAUTOMSR) * cMsrs <= X86_PAGE_4K_SIZE);
2755
2756 /* Verify the relevant contents of the MSR areas match. */
2757 PCVMXAUTOMSR pGuestMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2758 PCVMXAUTOMSR pGuestMsrStore = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2759 PCVMXAUTOMSR pHostMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2760 bool const fSeparateExitMsrStorePage = hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo);
2761 for (uint32_t i = 0; i < cMsrs; i++)
2762 {
2763 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
2764 if (fSeparateExitMsrStorePage)
2765 {
2766 AssertMsgReturnVoid(pGuestMsrLoad->u32Msr == pGuestMsrStore->u32Msr,
2767 ("GuestMsrLoad=%#RX32 GuestMsrStore=%#RX32 cMsrs=%u\n",
2768 pGuestMsrLoad->u32Msr, pGuestMsrStore->u32Msr, cMsrs));
2769 }
2770
2771 AssertMsgReturnVoid(pHostMsrLoad->u32Msr == pGuestMsrLoad->u32Msr,
2772 ("HostMsrLoad=%#RX32 GuestMsrLoad=%#RX32 cMsrs=%u\n",
2773 pHostMsrLoad->u32Msr, pGuestMsrLoad->u32Msr, cMsrs));
2774
2775 uint64_t const u64HostMsr = ASMRdMsr(pHostMsrLoad->u32Msr);
2776 AssertMsgReturnVoid(pHostMsrLoad->u64Value == u64HostMsr,
2777 ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2778 pHostMsrLoad->u32Msr, pHostMsrLoad->u64Value, u64HostMsr, cMsrs));
2779
2780 /* Verify that cached host EFER MSR matches what's loaded the CPU. */
2781 bool const fIsEferMsr = RT_BOOL(pHostMsrLoad->u32Msr == MSR_K6_EFER);
2782 if (fIsEferMsr)
2783 {
2784 AssertMsgReturnVoid(u64HostMsr == pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer,
2785 ("Cached=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2786 pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostMsrEfer, u64HostMsr, cMsrs));
2787 }
2788
2789 /* Verify that the accesses are as expected in the MSR bitmap for auto-load/store MSRs. */
2790 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2791 {
2792 uint32_t const fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, pGuestMsrLoad->u32Msr);
2793 if (fIsEferMsr)
2794 {
2795 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_RD), ("Passthru read for EFER MSR!?\n"));
2796 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_WR), ("Passthru write for EFER MSR!?\n"));
2797 }
2798 else
2799 {
2800 /* Verify LBR MSRs (used only for debugging) are intercepted. We don't passthru these MSRs to the guest yet. */
2801 PCVM pVM = pVCpu->CTX_SUFF(pVM);
2802 if ( pVM->hm.s.vmx.fLbr
2803 && ( hmR0VmxIsLbrBranchFromMsr(pVM, pGuestMsrLoad->u32Msr, NULL /* pidxMsr */)
2804 || hmR0VmxIsLbrBranchToMsr(pVM, pGuestMsrLoad->u32Msr, NULL /* pidxMsr */)
2805 || pGuestMsrLoad->u32Msr == pVM->hm.s.vmx.idLbrTosMsr))
2806 {
2807 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_MASK) == VMXMSRPM_EXIT_RD_WR,
2808 ("u32Msr=%#RX32 cMsrs=%u Passthru read/write for LBR MSRs!\n",
2809 pGuestMsrLoad->u32Msr, cMsrs));
2810 }
2811 else if (!fIsNstGstVmcs)
2812 {
2813 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_MASK) == VMXMSRPM_ALLOW_RD_WR,
2814 ("u32Msr=%#RX32 cMsrs=%u No passthru read/write!\n", pGuestMsrLoad->u32Msr, cMsrs));
2815 }
2816 else
2817 {
2818 /*
2819 * A nested-guest VMCS must -also- allow read/write passthrough for the MSR for us to
2820 * execute a nested-guest with MSR passthrough.
2821 *
2822 * Check if the nested-guest MSR bitmap allows passthrough, and if so, assert that we
2823 * allow passthrough too.
2824 */
2825 void const *pvMsrBitmapNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
2826 Assert(pvMsrBitmapNstGst);
2827 uint32_t const fMsrpmNstGst = CPUMGetVmxMsrPermission(pvMsrBitmapNstGst, pGuestMsrLoad->u32Msr);
2828 AssertMsgReturnVoid(fMsrpm == fMsrpmNstGst,
2829 ("u32Msr=%#RX32 cMsrs=%u Permission mismatch fMsrpm=%#x fMsrpmNstGst=%#x!\n",
2830 pGuestMsrLoad->u32Msr, cMsrs, fMsrpm, fMsrpmNstGst));
2831 }
2832 }
2833 }
2834
2835 /* Move to the next MSR. */
2836 pHostMsrLoad++;
2837 pGuestMsrLoad++;
2838 pGuestMsrStore++;
2839 }
2840}
2841
2842#endif /* VBOX_STRICT */
2843
2844/**
2845 * Flushes the TLB using EPT.
2846 *
2847 * @returns VBox status code.
2848 * @param pVCpu The cross context virtual CPU structure of the calling
2849 * EMT. Can be NULL depending on @a enmTlbFlush.
2850 * @param pVmcsInfo The VMCS info. object. Can be NULL depending on @a
2851 * enmTlbFlush.
2852 * @param enmTlbFlush Type of flush.
2853 *
2854 * @remarks Caller is responsible for making sure this function is called only
2855 * when NestedPaging is supported and providing @a enmTlbFlush that is
2856 * supported by the CPU.
2857 * @remarks Can be called with interrupts disabled.
2858 */
2859static void hmR0VmxFlushEpt(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, VMXTLBFLUSHEPT enmTlbFlush)
2860{
2861 uint64_t au64Descriptor[2];
2862 if (enmTlbFlush == VMXTLBFLUSHEPT_ALL_CONTEXTS)
2863 au64Descriptor[0] = 0;
2864 else
2865 {
2866 Assert(pVCpu);
2867 Assert(pVmcsInfo);
2868 au64Descriptor[0] = pVmcsInfo->HCPhysEPTP;
2869 }
2870 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
2871
2872 int rc = VMXR0InvEPT(enmTlbFlush, &au64Descriptor[0]);
2873 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %#RHp failed. rc=%Rrc\n", enmTlbFlush, au64Descriptor[0], rc));
2874
2875 if ( RT_SUCCESS(rc)
2876 && pVCpu)
2877 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
2878}
2879
2880
2881/**
2882 * Flushes the TLB using VPID.
2883 *
2884 * @returns VBox status code.
2885 * @param pVCpu The cross context virtual CPU structure of the calling
2886 * EMT. Can be NULL depending on @a enmTlbFlush.
2887 * @param enmTlbFlush Type of flush.
2888 * @param GCPtr Virtual address of the page to flush (can be 0 depending
2889 * on @a enmTlbFlush).
2890 *
2891 * @remarks Can be called with interrupts disabled.
2892 */
2893static void hmR0VmxFlushVpid(PVMCPUCC pVCpu, VMXTLBFLUSHVPID enmTlbFlush, RTGCPTR GCPtr)
2894{
2895 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid);
2896
2897 uint64_t au64Descriptor[2];
2898 if (enmTlbFlush == VMXTLBFLUSHVPID_ALL_CONTEXTS)
2899 {
2900 au64Descriptor[0] = 0;
2901 au64Descriptor[1] = 0;
2902 }
2903 else
2904 {
2905 AssertPtr(pVCpu);
2906 AssertMsg(pVCpu->hmr0.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hmr0.s.uCurrentAsid));
2907 AssertMsg(pVCpu->hmr0.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hmr0.s.uCurrentAsid));
2908 au64Descriptor[0] = pVCpu->hmr0.s.uCurrentAsid;
2909 au64Descriptor[1] = GCPtr;
2910 }
2911
2912 int rc = VMXR0InvVPID(enmTlbFlush, &au64Descriptor[0]);
2913 AssertMsg(rc == VINF_SUCCESS,
2914 ("VMXR0InvVPID %#x %u %RGv failed with %Rrc\n", enmTlbFlush, pVCpu ? pVCpu->hmr0.s.uCurrentAsid : 0, GCPtr, rc));
2915
2916 if ( RT_SUCCESS(rc)
2917 && pVCpu)
2918 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
2919 NOREF(rc);
2920}
2921
2922
2923/**
2924 * Invalidates a guest page by guest virtual address. Only relevant for EPT/VPID,
2925 * otherwise there is nothing really to invalidate.
2926 *
2927 * @returns VBox status code.
2928 * @param pVCpu The cross context virtual CPU structure.
2929 * @param GCVirt Guest virtual address of the page to invalidate.
2930 */
2931VMMR0DECL(int) VMXR0InvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt)
2932{
2933 AssertPtr(pVCpu);
2934 LogFlowFunc(("pVCpu=%p GCVirt=%RGv\n", pVCpu, GCVirt));
2935
2936 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TLB_FLUSH))
2937 {
2938 /*
2939 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for
2940 * the EPT case. See @bugref{6043} and @bugref{6177}.
2941 *
2942 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*()
2943 * as this function maybe called in a loop with individual addresses.
2944 */
2945 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2946 if (pVM->hmr0.s.vmx.fVpid)
2947 {
2948 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
2949 {
2950 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_INDIV_ADDR, GCVirt);
2951 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
2952 }
2953 else
2954 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2955 }
2956 else if (pVM->hmr0.s.fNestedPaging)
2957 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2958 }
2959
2960 return VINF_SUCCESS;
2961}
2962
2963
2964/**
2965 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
2966 * case where neither EPT nor VPID is supported by the CPU.
2967 *
2968 * @param pHostCpu The HM physical-CPU structure.
2969 * @param pVCpu The cross context virtual CPU structure.
2970 *
2971 * @remarks Called with interrupts disabled.
2972 */
2973static void hmR0VmxFlushTaggedTlbNone(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
2974{
2975 AssertPtr(pVCpu);
2976 AssertPtr(pHostCpu);
2977
2978 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2979
2980 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2981 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
2982 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
2983 pVCpu->hmr0.s.fForceTLBFlush = false;
2984 return;
2985}
2986
2987
2988/**
2989 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
2990 *
2991 * @param pHostCpu The HM physical-CPU structure.
2992 * @param pVCpu The cross context virtual CPU structure.
2993 * @param pVmcsInfo The VMCS info. object.
2994 *
2995 * @remarks All references to "ASID" in this function pertains to "VPID" in Intel's
2996 * nomenclature. The reason is, to avoid confusion in compare statements
2997 * since the host-CPU copies are named "ASID".
2998 *
2999 * @remarks Called with interrupts disabled.
3000 */
3001static void hmR0VmxFlushTaggedTlbBoth(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3002{
3003#ifdef VBOX_WITH_STATISTICS
3004 bool fTlbFlushed = false;
3005# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
3006# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
3007 if (!fTlbFlushed) \
3008 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
3009 } while (0)
3010#else
3011# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
3012# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
3013#endif
3014
3015 AssertPtr(pVCpu);
3016 AssertPtr(pHostCpu);
3017 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3018
3019 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3020 AssertMsg(pVM->hmr0.s.fNestedPaging && pVM->hmr0.s.vmx.fVpid,
3021 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
3022 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hmr0.s.fNestedPaging, pVM->hmr0.s.vmx.fVpid));
3023
3024 /*
3025 * Force a TLB flush for the first world-switch if the current CPU differs from the one we
3026 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3027 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3028 * cannot reuse the current ASID anymore.
3029 */
3030 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3031 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3032 {
3033 ++pHostCpu->uCurrentAsid;
3034 if (pHostCpu->uCurrentAsid >= g_uHmMaxAsid)
3035 {
3036 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
3037 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3038 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3039 }
3040
3041 pVCpu->hmr0.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3042 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3043 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3044
3045 /*
3046 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
3047 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
3048 */
3049 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3050 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3051 HMVMX_SET_TAGGED_TLB_FLUSHED();
3052 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
3053 }
3054 else if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH)) /* Check for explicit TLB flushes. */
3055 {
3056 /*
3057 * Changes to the EPT paging structure by VMM requires flushing-by-EPT as the CPU
3058 * creates guest-physical (ie. only EPT-tagged) mappings while traversing the EPT
3059 * tables when EPT is in use. Flushing-by-VPID will only flush linear (only
3060 * VPID-tagged) and combined (EPT+VPID tagged) mappings but not guest-physical
3061 * mappings, see @bugref{6568}.
3062 *
3063 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information".
3064 */
3065 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3066 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3067 HMVMX_SET_TAGGED_TLB_FLUSHED();
3068 }
3069 else if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3070 {
3071 /*
3072 * The nested-guest specifies its own guest-physical address to use as the APIC-access
3073 * address which requires flushing the TLB of EPT cached structures.
3074 *
3075 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
3076 */
3077 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3078 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3079 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3080 HMVMX_SET_TAGGED_TLB_FLUSHED();
3081 }
3082
3083
3084 pVCpu->hmr0.s.fForceTLBFlush = false;
3085 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
3086
3087 Assert(pVCpu->hmr0.s.idLastCpu == pHostCpu->idCpu);
3088 Assert(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes);
3089 AssertMsg(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3090 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hmr0.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3091 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < g_uHmMaxAsid,
3092 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3093 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hmr0.s.idLastCpu, pVCpu->hmr0.s.cTlbFlushes));
3094 AssertMsg(pVCpu->hmr0.s.uCurrentAsid >= 1 && pVCpu->hmr0.s.uCurrentAsid < g_uHmMaxAsid,
3095 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hmr0.s.uCurrentAsid));
3096
3097 /* Update VMCS with the VPID. */
3098 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hmr0.s.uCurrentAsid);
3099 AssertRC(rc);
3100
3101#undef HMVMX_SET_TAGGED_TLB_FLUSHED
3102}
3103
3104
3105/**
3106 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
3107 *
3108 * @param pHostCpu The HM physical-CPU structure.
3109 * @param pVCpu The cross context virtual CPU structure.
3110 * @param pVmcsInfo The VMCS info. object.
3111 *
3112 * @remarks Called with interrupts disabled.
3113 */
3114static void hmR0VmxFlushTaggedTlbEpt(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3115{
3116 AssertPtr(pVCpu);
3117 AssertPtr(pHostCpu);
3118 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3119 AssertMsg(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked without NestedPaging."));
3120 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID."));
3121
3122 /*
3123 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
3124 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
3125 */
3126 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3127 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3128 {
3129 pVCpu->hmr0.s.fForceTLBFlush = true;
3130 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3131 }
3132
3133 /* Check for explicit TLB flushes. */
3134 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3135 {
3136 pVCpu->hmr0.s.fForceTLBFlush = true;
3137 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3138 }
3139
3140 /* Check for TLB flushes while switching to/from a nested-guest. */
3141 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3142 {
3143 pVCpu->hmr0.s.fForceTLBFlush = true;
3144 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3145 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3146 }
3147
3148 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3149 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3150
3151 if (pVCpu->hmr0.s.fForceTLBFlush)
3152 {
3153 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.enmTlbFlushEpt);
3154 pVCpu->hmr0.s.fForceTLBFlush = false;
3155 }
3156}
3157
3158
3159/**
3160 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
3161 *
3162 * @param pHostCpu The HM physical-CPU structure.
3163 * @param pVCpu The cross context virtual CPU structure.
3164 *
3165 * @remarks Called with interrupts disabled.
3166 */
3167static void hmR0VmxFlushTaggedTlbVpid(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
3168{
3169 AssertPtr(pVCpu);
3170 AssertPtr(pHostCpu);
3171 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3172 AssertMsg(pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked without VPID."));
3173 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging"));
3174
3175 /*
3176 * Force a TLB flush for the first world switch if the current CPU differs from the one we
3177 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3178 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3179 * cannot reuse the current ASID anymore.
3180 */
3181 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3182 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3183 {
3184 pVCpu->hmr0.s.fForceTLBFlush = true;
3185 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3186 }
3187
3188 /* Check for explicit TLB flushes. */
3189 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3190 {
3191 /*
3192 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see
3193 * hmR0VmxSetupTaggedTlb()) we would need to explicitly flush in this case (add an
3194 * fExplicitFlush = true here and change the pHostCpu->fFlushAsidBeforeUse check below to
3195 * include fExplicitFlush's too) - an obscure corner case.
3196 */
3197 pVCpu->hmr0.s.fForceTLBFlush = true;
3198 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3199 }
3200
3201 /* Check for TLB flushes while switching to/from a nested-guest. */
3202 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3203 {
3204 pVCpu->hmr0.s.fForceTLBFlush = true;
3205 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3206 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3207 }
3208
3209 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3210 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3211 if (pVCpu->hmr0.s.fForceTLBFlush)
3212 {
3213 ++pHostCpu->uCurrentAsid;
3214 if (pHostCpu->uCurrentAsid >= g_uHmMaxAsid)
3215 {
3216 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
3217 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3218 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3219 }
3220
3221 pVCpu->hmr0.s.fForceTLBFlush = false;
3222 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3223 pVCpu->hmr0.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3224 if (pHostCpu->fFlushAsidBeforeUse)
3225 {
3226 if (pVM->hmr0.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_SINGLE_CONTEXT)
3227 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
3228 else if (pVM->hmr0.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_ALL_CONTEXTS)
3229 {
3230 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
3231 pHostCpu->fFlushAsidBeforeUse = false;
3232 }
3233 else
3234 {
3235 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
3236 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
3237 }
3238 }
3239 }
3240
3241 AssertMsg(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3242 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hmr0.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3243 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < g_uHmMaxAsid,
3244 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3245 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hmr0.s.idLastCpu, pVCpu->hmr0.s.cTlbFlushes));
3246 AssertMsg(pVCpu->hmr0.s.uCurrentAsid >= 1 && pVCpu->hmr0.s.uCurrentAsid < g_uHmMaxAsid,
3247 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hmr0.s.uCurrentAsid));
3248
3249 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hmr0.s.uCurrentAsid);
3250 AssertRC(rc);
3251}
3252
3253
3254/**
3255 * Flushes the guest TLB entry based on CPU capabilities.
3256 *
3257 * @param pHostCpu The HM physical-CPU structure.
3258 * @param pVCpu The cross context virtual CPU structure.
3259 * @param pVmcsInfo The VMCS info. object.
3260 *
3261 * @remarks Called with interrupts disabled.
3262 */
3263static void hmR0VmxFlushTaggedTlb(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3264{
3265#ifdef HMVMX_ALWAYS_FLUSH_TLB
3266 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
3267#endif
3268 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3269 switch (pVM->hmr0.s.vmx.enmTlbFlushType)
3270 {
3271 case VMXTLBFLUSHTYPE_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pHostCpu, pVCpu, pVmcsInfo); break;
3272 case VMXTLBFLUSHTYPE_EPT: hmR0VmxFlushTaggedTlbEpt(pHostCpu, pVCpu, pVmcsInfo); break;
3273 case VMXTLBFLUSHTYPE_VPID: hmR0VmxFlushTaggedTlbVpid(pHostCpu, pVCpu); break;
3274 case VMXTLBFLUSHTYPE_NONE: hmR0VmxFlushTaggedTlbNone(pHostCpu, pVCpu); break;
3275 default:
3276 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
3277 break;
3278 }
3279 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
3280}
3281
3282
3283/**
3284 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
3285 * TLB entries from the host TLB before VM-entry.
3286 *
3287 * @returns VBox status code.
3288 * @param pVM The cross context VM structure.
3289 */
3290static int hmR0VmxSetupTaggedTlb(PVMCC pVM)
3291{
3292 /*
3293 * Determine optimal flush type for nested paging.
3294 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup
3295 * unrestricted guest execution (see hmR3InitFinalizeR0()).
3296 */
3297 if (pVM->hmr0.s.fNestedPaging)
3298 {
3299 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
3300 {
3301 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
3302 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_SINGLE_CONTEXT;
3303 else if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
3304 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_ALL_CONTEXTS;
3305 else
3306 {
3307 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
3308 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3309 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
3310 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3311 }
3312
3313 /* Make sure the write-back cacheable memory type for EPT is supported. */
3314 if (RT_UNLIKELY(!(g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB)))
3315 {
3316 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3317 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
3318 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3319 }
3320
3321 /* EPT requires a page-walk length of 4. */
3322 if (RT_UNLIKELY(!(g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
3323 {
3324 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3325 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
3326 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3327 }
3328 }
3329 else
3330 {
3331 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
3332 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3333 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
3334 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3335 }
3336 }
3337
3338 /*
3339 * Determine optimal flush type for VPID.
3340 */
3341 if (pVM->hmr0.s.vmx.fVpid)
3342 {
3343 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
3344 {
3345 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
3346 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_SINGLE_CONTEXT;
3347 else if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
3348 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_ALL_CONTEXTS;
3349 else
3350 {
3351 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
3352 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
3353 LogRelFunc(("Only INDIV_ADDR supported. Ignoring VPID.\n"));
3354 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
3355 LogRelFunc(("Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
3356 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3357 pVM->hm.s.vmx.fVpidForRing3 = pVM->hmr0.s.vmx.fVpid = false;
3358 }
3359 }
3360 else
3361 {
3362 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
3363 Log4Func(("VPID supported without INVEPT support. Ignoring VPID.\n"));
3364 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3365 pVM->hm.s.vmx.fVpidForRing3 = pVM->hmr0.s.vmx.fVpid = false;
3366 }
3367 }
3368
3369 /*
3370 * Setup the handler for flushing tagged-TLBs.
3371 */
3372 if (pVM->hmr0.s.fNestedPaging && pVM->hmr0.s.vmx.fVpid)
3373 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT_VPID;
3374 else if (pVM->hmr0.s.fNestedPaging)
3375 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT;
3376 else if (pVM->hmr0.s.vmx.fVpid)
3377 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_VPID;
3378 else
3379 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_NONE;
3380
3381
3382 /*
3383 * Copy out the result to ring-3.
3384 */
3385 pVM->hm.s.vmx.fVpidForRing3 = pVM->hmr0.s.vmx.fVpid;
3386 pVM->hm.s.vmx.enmTlbFlushTypeForRing3 = pVM->hmr0.s.vmx.enmTlbFlushType;
3387 pVM->hm.s.vmx.enmTlbFlushEptForRing3 = pVM->hmr0.s.vmx.enmTlbFlushEpt;
3388 pVM->hm.s.vmx.enmTlbFlushVpidForRing3 = pVM->hmr0.s.vmx.enmTlbFlushVpid;
3389 return VINF_SUCCESS;
3390}
3391
3392
3393/**
3394 * Sets up the LBR MSR ranges based on the host CPU.
3395 *
3396 * @returns VBox status code.
3397 * @param pVM The cross context VM structure.
3398 */
3399static int hmR0VmxSetupLbrMsrRange(PVMCC pVM)
3400{
3401 Assert(pVM->hm.s.vmx.fLbr);
3402 uint32_t idLbrFromIpMsrFirst;
3403 uint32_t idLbrFromIpMsrLast;
3404 uint32_t idLbrToIpMsrFirst;
3405 uint32_t idLbrToIpMsrLast;
3406 uint32_t idLbrTosMsr;
3407
3408 /*
3409 * Determine the LBR MSRs supported for this host CPU family and model.
3410 *
3411 * See Intel spec. 17.4.8 "LBR Stack".
3412 * See Intel "Model-Specific Registers" spec.
3413 */
3414 uint32_t const uFamilyModel = (pVM->cpum.ro.HostFeatures.uFamily << 8)
3415 | pVM->cpum.ro.HostFeatures.uModel;
3416 switch (uFamilyModel)
3417 {
3418 case 0x0f01: case 0x0f02:
3419 idLbrFromIpMsrFirst = MSR_P4_LASTBRANCH_0;
3420 idLbrFromIpMsrLast = MSR_P4_LASTBRANCH_3;
3421 idLbrToIpMsrFirst = 0x0;
3422 idLbrToIpMsrLast = 0x0;
3423 idLbrTosMsr = MSR_P4_LASTBRANCH_TOS;
3424 break;
3425
3426 case 0x065c: case 0x065f: case 0x064e: case 0x065e: case 0x068e:
3427 case 0x069e: case 0x0655: case 0x0666: case 0x067a: case 0x0667:
3428 case 0x066a: case 0x066c: case 0x067d: case 0x067e:
3429 idLbrFromIpMsrFirst = MSR_LASTBRANCH_0_FROM_IP;
3430 idLbrFromIpMsrLast = MSR_LASTBRANCH_31_FROM_IP;
3431 idLbrToIpMsrFirst = MSR_LASTBRANCH_0_TO_IP;
3432 idLbrToIpMsrLast = MSR_LASTBRANCH_31_TO_IP;
3433 idLbrTosMsr = MSR_LASTBRANCH_TOS;
3434 break;
3435
3436 case 0x063d: case 0x0647: case 0x064f: case 0x0656: case 0x063c:
3437 case 0x0645: case 0x0646: case 0x063f: case 0x062a: case 0x062d:
3438 case 0x063a: case 0x063e: case 0x061a: case 0x061e: case 0x061f:
3439 case 0x062e: case 0x0625: case 0x062c: case 0x062f:
3440 idLbrFromIpMsrFirst = MSR_LASTBRANCH_0_FROM_IP;
3441 idLbrFromIpMsrLast = MSR_LASTBRANCH_15_FROM_IP;
3442 idLbrToIpMsrFirst = MSR_LASTBRANCH_0_TO_IP;
3443 idLbrToIpMsrLast = MSR_LASTBRANCH_15_TO_IP;
3444 idLbrTosMsr = MSR_LASTBRANCH_TOS;
3445 break;
3446
3447 case 0x0617: case 0x061d: case 0x060f:
3448 idLbrFromIpMsrFirst = MSR_CORE2_LASTBRANCH_0_FROM_IP;
3449 idLbrFromIpMsrLast = MSR_CORE2_LASTBRANCH_3_FROM_IP;
3450 idLbrToIpMsrFirst = MSR_CORE2_LASTBRANCH_0_TO_IP;
3451 idLbrToIpMsrLast = MSR_CORE2_LASTBRANCH_3_TO_IP;
3452 idLbrTosMsr = MSR_CORE2_LASTBRANCH_TOS;
3453 break;
3454
3455 /* Atom and related microarchitectures we don't care about:
3456 case 0x0637: case 0x064a: case 0x064c: case 0x064d: case 0x065a:
3457 case 0x065d: case 0x061c: case 0x0626: case 0x0627: case 0x0635:
3458 case 0x0636: */
3459 /* All other CPUs: */
3460 default:
3461 {
3462 LogRelFunc(("Could not determine LBR stack size for the CPU model %#x\n", uFamilyModel));
3463 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_LBR_STACK_SIZE_UNKNOWN;
3464 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3465 }
3466 }
3467
3468 /*
3469 * Validate.
3470 */
3471 uint32_t const cLbrStack = idLbrFromIpMsrLast - idLbrFromIpMsrFirst + 1;
3472 PCVMCPU pVCpu0 = VMCC_GET_CPU_0(pVM);
3473 AssertCompile( RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrFromIpMsr)
3474 == RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrToIpMsr));
3475 if (cLbrStack > RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrFromIpMsr))
3476 {
3477 LogRelFunc(("LBR stack size of the CPU (%u) exceeds our buffer size\n", cLbrStack));
3478 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_LBR_STACK_SIZE_OVERFLOW;
3479 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3480 }
3481 NOREF(pVCpu0);
3482
3483 /*
3484 * Update the LBR info. to the VM struct. for use later.
3485 */
3486 pVM->hm.s.vmx.idLbrTosMsr = idLbrTosMsr;
3487 pVM->hm.s.vmx.idLbrFromIpMsrFirst = idLbrFromIpMsrFirst;
3488 pVM->hm.s.vmx.idLbrFromIpMsrLast = idLbrFromIpMsrLast;
3489
3490 pVM->hm.s.vmx.idLbrToIpMsrFirst = idLbrToIpMsrFirst;
3491 pVM->hm.s.vmx.idLbrToIpMsrLast = idLbrToIpMsrLast;
3492 return VINF_SUCCESS;
3493}
3494
3495
3496#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3497/**
3498 * Sets up the shadow VMCS fields arrays.
3499 *
3500 * This function builds arrays of VMCS fields to sync the shadow VMCS later while
3501 * executing the guest.
3502 *
3503 * @returns VBox status code.
3504 * @param pVM The cross context VM structure.
3505 */
3506static int hmR0VmxSetupShadowVmcsFieldsArrays(PVMCC pVM)
3507{
3508 /*
3509 * Paranoia. Ensure we haven't exposed the VMWRITE-All VMX feature to the guest
3510 * when the host does not support it.
3511 */
3512 bool const fGstVmwriteAll = pVM->cpum.ro.GuestFeatures.fVmxVmwriteAll;
3513 if ( !fGstVmwriteAll
3514 || (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL))
3515 { /* likely. */ }
3516 else
3517 {
3518 LogRelFunc(("VMX VMWRITE-All feature exposed to the guest but host CPU does not support it!\n"));
3519 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_GST_HOST_VMWRITE_ALL;
3520 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3521 }
3522
3523 uint32_t const cVmcsFields = RT_ELEMENTS(g_aVmcsFields);
3524 uint32_t cRwFields = 0;
3525 uint32_t cRoFields = 0;
3526 for (uint32_t i = 0; i < cVmcsFields; i++)
3527 {
3528 VMXVMCSFIELD VmcsField;
3529 VmcsField.u = g_aVmcsFields[i];
3530
3531 /*
3532 * We will be writing "FULL" (64-bit) fields while syncing the shadow VMCS.
3533 * Therefore, "HIGH" (32-bit portion of 64-bit) fields must not be included
3534 * in the shadow VMCS fields array as they would be redundant.
3535 *
3536 * If the VMCS field depends on a CPU feature that is not exposed to the guest,
3537 * we must not include it in the shadow VMCS fields array. Guests attempting to
3538 * VMREAD/VMWRITE such VMCS fields would cause a VM-exit and we shall emulate
3539 * the required behavior.
3540 */
3541 if ( VmcsField.n.fAccessType == VMX_VMCSFIELD_ACCESS_FULL
3542 && CPUMIsGuestVmxVmcsFieldValid(pVM, VmcsField.u))
3543 {
3544 /*
3545 * Read-only fields are placed in a separate array so that while syncing shadow
3546 * VMCS fields later (which is more performance critical) we can avoid branches.
3547 *
3548 * However, if the guest can write to all fields (including read-only fields),
3549 * we treat it a as read/write field. Otherwise, writing to these fields would
3550 * cause a VMWRITE instruction error while syncing the shadow VMCS.
3551 */
3552 if ( fGstVmwriteAll
3553 || !VMXIsVmcsFieldReadOnly(VmcsField.u))
3554 pVM->hmr0.s.vmx.paShadowVmcsFields[cRwFields++] = VmcsField.u;
3555 else
3556 pVM->hmr0.s.vmx.paShadowVmcsRoFields[cRoFields++] = VmcsField.u;
3557 }
3558 }
3559
3560 /* Update the counts. */
3561 pVM->hmr0.s.vmx.cShadowVmcsFields = cRwFields;
3562 pVM->hmr0.s.vmx.cShadowVmcsRoFields = cRoFields;
3563 return VINF_SUCCESS;
3564}
3565
3566
3567/**
3568 * Sets up the VMREAD and VMWRITE bitmaps.
3569 *
3570 * @param pVM The cross context VM structure.
3571 */
3572static void hmR0VmxSetupVmreadVmwriteBitmaps(PVMCC pVM)
3573{
3574 /*
3575 * By default, ensure guest attempts to access any VMCS fields cause VM-exits.
3576 */
3577 uint32_t const cbBitmap = X86_PAGE_4K_SIZE;
3578 uint8_t *pbVmreadBitmap = (uint8_t *)pVM->hmr0.s.vmx.pvVmreadBitmap;
3579 uint8_t *pbVmwriteBitmap = (uint8_t *)pVM->hmr0.s.vmx.pvVmwriteBitmap;
3580 ASMMemFill32(pbVmreadBitmap, cbBitmap, UINT32_C(0xffffffff));
3581 ASMMemFill32(pbVmwriteBitmap, cbBitmap, UINT32_C(0xffffffff));
3582
3583 /*
3584 * Skip intercepting VMREAD/VMWRITE to guest read/write fields in the
3585 * VMREAD and VMWRITE bitmaps.
3586 */
3587 {
3588 uint32_t const *paShadowVmcsFields = pVM->hmr0.s.vmx.paShadowVmcsFields;
3589 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
3590 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
3591 {
3592 uint32_t const uVmcsField = paShadowVmcsFields[i];
3593 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3594 Assert(uVmcsField >> 3 < cbBitmap);
3595 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3596 ASMBitClear(pbVmwriteBitmap + (uVmcsField >> 3), uVmcsField & 7);
3597 }
3598 }
3599
3600 /*
3601 * Skip intercepting VMREAD for guest read-only fields in the VMREAD bitmap
3602 * if the host supports VMWRITE to all supported VMCS fields.
3603 */
3604 if (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL)
3605 {
3606 uint32_t const *paShadowVmcsRoFields = pVM->hmr0.s.vmx.paShadowVmcsRoFields;
3607 uint32_t const cShadowVmcsRoFields = pVM->hmr0.s.vmx.cShadowVmcsRoFields;
3608 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
3609 {
3610 uint32_t const uVmcsField = paShadowVmcsRoFields[i];
3611 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3612 Assert(uVmcsField >> 3 < cbBitmap);
3613 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3614 }
3615 }
3616}
3617#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
3618
3619
3620/**
3621 * Sets up the virtual-APIC page address for the VMCS.
3622 *
3623 * @param pVmcsInfo The VMCS info. object.
3624 */
3625DECLINLINE(void) hmR0VmxSetupVmcsVirtApicAddr(PCVMXVMCSINFO pVmcsInfo)
3626{
3627 RTHCPHYS const HCPhysVirtApic = pVmcsInfo->HCPhysVirtApic;
3628 Assert(HCPhysVirtApic != NIL_RTHCPHYS);
3629 Assert(!(HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
3630 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
3631 AssertRC(rc);
3632}
3633
3634
3635/**
3636 * Sets up the MSR-bitmap address for the VMCS.
3637 *
3638 * @param pVmcsInfo The VMCS info. object.
3639 */
3640DECLINLINE(void) hmR0VmxSetupVmcsMsrBitmapAddr(PCVMXVMCSINFO pVmcsInfo)
3641{
3642 RTHCPHYS const HCPhysMsrBitmap = pVmcsInfo->HCPhysMsrBitmap;
3643 Assert(HCPhysMsrBitmap != NIL_RTHCPHYS);
3644 Assert(!(HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3645 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, HCPhysMsrBitmap);
3646 AssertRC(rc);
3647}
3648
3649
3650/**
3651 * Sets up the APIC-access page address for the VMCS.
3652 *
3653 * @param pVCpu The cross context virtual CPU structure.
3654 */
3655DECLINLINE(void) hmR0VmxSetupVmcsApicAccessAddr(PVMCPUCC pVCpu)
3656{
3657 RTHCPHYS const HCPhysApicAccess = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysApicAccess;
3658 Assert(HCPhysApicAccess != NIL_RTHCPHYS);
3659 Assert(!(HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
3660 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
3661 AssertRC(rc);
3662}
3663
3664
3665#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3666/**
3667 * Sets up the VMREAD bitmap address for the VMCS.
3668 *
3669 * @param pVCpu The cross context virtual CPU structure.
3670 */
3671DECLINLINE(void) hmR0VmxSetupVmcsVmreadBitmapAddr(PVMCPUCC pVCpu)
3672{
3673 RTHCPHYS const HCPhysVmreadBitmap = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysVmreadBitmap;
3674 Assert(HCPhysVmreadBitmap != NIL_RTHCPHYS);
3675 Assert(!(HCPhysVmreadBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3676 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL, HCPhysVmreadBitmap);
3677 AssertRC(rc);
3678}
3679
3680
3681/**
3682 * Sets up the VMWRITE bitmap address for the VMCS.
3683 *
3684 * @param pVCpu The cross context virtual CPU structure.
3685 */
3686DECLINLINE(void) hmR0VmxSetupVmcsVmwriteBitmapAddr(PVMCPUCC pVCpu)
3687{
3688 RTHCPHYS const HCPhysVmwriteBitmap = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysVmwriteBitmap;
3689 Assert(HCPhysVmwriteBitmap != NIL_RTHCPHYS);
3690 Assert(!(HCPhysVmwriteBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3691 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL, HCPhysVmwriteBitmap);
3692 AssertRC(rc);
3693}
3694#endif
3695
3696
3697/**
3698 * Sets up the VM-entry MSR load, VM-exit MSR-store and VM-exit MSR-load addresses
3699 * in the VMCS.
3700 *
3701 * @returns VBox status code.
3702 * @param pVmcsInfo The VMCS info. object.
3703 */
3704DECLINLINE(int) hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(PVMXVMCSINFO pVmcsInfo)
3705{
3706 RTHCPHYS const HCPhysGuestMsrLoad = pVmcsInfo->HCPhysGuestMsrLoad;
3707 Assert(HCPhysGuestMsrLoad != NIL_RTHCPHYS);
3708 Assert(!(HCPhysGuestMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3709
3710 RTHCPHYS const HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrStore;
3711 Assert(HCPhysGuestMsrStore != NIL_RTHCPHYS);
3712 Assert(!(HCPhysGuestMsrStore & 0xf)); /* Bits 3:0 MBZ. */
3713
3714 RTHCPHYS const HCPhysHostMsrLoad = pVmcsInfo->HCPhysHostMsrLoad;
3715 Assert(HCPhysHostMsrLoad != NIL_RTHCPHYS);
3716 Assert(!(HCPhysHostMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3717
3718 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, HCPhysGuestMsrLoad); AssertRC(rc);
3719 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, HCPhysGuestMsrStore); AssertRC(rc);
3720 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, HCPhysHostMsrLoad); AssertRC(rc);
3721 return VINF_SUCCESS;
3722}
3723
3724
3725/**
3726 * Sets up MSR permissions in the MSR bitmap of a VMCS info. object.
3727 *
3728 * @param pVCpu The cross context virtual CPU structure.
3729 * @param pVmcsInfo The VMCS info. object.
3730 */
3731static void hmR0VmxSetupVmcsMsrPermissions(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3732{
3733 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS);
3734
3735 /*
3736 * By default, ensure guest attempts to access any MSR cause VM-exits.
3737 * This shall later be relaxed for specific MSRs as necessary.
3738 *
3739 * Note: For nested-guests, the entire bitmap will be merged prior to
3740 * executing the nested-guest using hardware-assisted VMX and hence there
3741 * is no need to perform this operation. See hmR0VmxMergeMsrBitmapNested.
3742 */
3743 Assert(pVmcsInfo->pvMsrBitmap);
3744 ASMMemFill32(pVmcsInfo->pvMsrBitmap, X86_PAGE_4K_SIZE, UINT32_C(0xffffffff));
3745
3746 /*
3747 * The guest can access the following MSRs (read, write) without causing
3748 * VM-exits; they are loaded/stored automatically using fields in the VMCS.
3749 */
3750 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3751 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_CS, VMXMSRPM_ALLOW_RD_WR);
3752 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_ESP, VMXMSRPM_ALLOW_RD_WR);
3753 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_EIP, VMXMSRPM_ALLOW_RD_WR);
3754 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3755 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_FS_BASE, VMXMSRPM_ALLOW_RD_WR);
3756
3757 /*
3758 * The IA32_PRED_CMD and IA32_FLUSH_CMD MSRs are write-only and has no state
3759 * associated with then. We never need to intercept access (writes need to be
3760 * executed without causing a VM-exit, reads will #GP fault anyway).
3761 *
3762 * The IA32_SPEC_CTRL MSR is read/write and has state. We allow the guest to
3763 * read/write them. We swap the the guest/host MSR value using the
3764 * auto-load/store MSR area.
3765 */
3766 if (pVM->cpum.ro.GuestFeatures.fIbpb)
3767 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_PRED_CMD, VMXMSRPM_ALLOW_RD_WR);
3768 if (pVM->cpum.ro.GuestFeatures.fFlushCmd)
3769 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_FLUSH_CMD, VMXMSRPM_ALLOW_RD_WR);
3770 if (pVM->cpum.ro.GuestFeatures.fIbrs)
3771 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SPEC_CTRL, VMXMSRPM_ALLOW_RD_WR);
3772
3773 /*
3774 * Allow full read/write access for the following MSRs (mandatory for VT-x)
3775 * required for 64-bit guests.
3776 */
3777 if (pVM->hmr0.s.fAllow64BitGuests)
3778 {
3779 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_LSTAR, VMXMSRPM_ALLOW_RD_WR);
3780 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K6_STAR, VMXMSRPM_ALLOW_RD_WR);
3781 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_SF_MASK, VMXMSRPM_ALLOW_RD_WR);
3782 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_KERNEL_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3783 }
3784
3785 /*
3786 * IA32_EFER MSR is always intercepted, see @bugref{9180#c37}.
3787 */
3788#ifdef VBOX_STRICT
3789 Assert(pVmcsInfo->pvMsrBitmap);
3790 uint32_t const fMsrpmEfer = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, MSR_K6_EFER);
3791 Assert(fMsrpmEfer == VMXMSRPM_EXIT_RD_WR);
3792#endif
3793}
3794
3795
3796/**
3797 * Sets up pin-based VM-execution controls in the VMCS.
3798 *
3799 * @returns VBox status code.
3800 * @param pVCpu The cross context virtual CPU structure.
3801 * @param pVmcsInfo The VMCS info. object.
3802 */
3803static int hmR0VmxSetupVmcsPinCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3804{
3805 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3806 uint32_t fVal = g_HmMsrs.u.vmx.PinCtls.n.allowed0; /* Bits set here must always be set. */
3807 uint32_t const fZap = g_HmMsrs.u.vmx.PinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
3808
3809 fVal |= VMX_PIN_CTLS_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
3810 | VMX_PIN_CTLS_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
3811
3812 if (g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_VIRT_NMI)
3813 fVal |= VMX_PIN_CTLS_VIRT_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
3814
3815 /* Enable the VMX-preemption timer. */
3816 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
3817 {
3818 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_PREEMPT_TIMER);
3819 fVal |= VMX_PIN_CTLS_PREEMPT_TIMER;
3820 }
3821
3822#if 0
3823 /* Enable posted-interrupt processing. */
3824 if (pVM->hm.s.fPostedIntrs)
3825 {
3826 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_POSTED_INT);
3827 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT);
3828 fVal |= VMX_PIN_CTLS_POSTED_INT;
3829 }
3830#endif
3831
3832 if ((fVal & fZap) != fVal)
3833 {
3834 LogRelFunc(("Invalid pin-based VM-execution controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3835 g_HmMsrs.u.vmx.PinCtls.n.allowed0, fVal, fZap));
3836 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
3837 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3838 }
3839
3840 /* Commit it to the VMCS and update our cache. */
3841 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, fVal);
3842 AssertRC(rc);
3843 pVmcsInfo->u32PinCtls = fVal;
3844
3845 return VINF_SUCCESS;
3846}
3847
3848
3849/**
3850 * Sets up secondary processor-based VM-execution controls in the VMCS.
3851 *
3852 * @returns VBox status code.
3853 * @param pVCpu The cross context virtual CPU structure.
3854 * @param pVmcsInfo The VMCS info. object.
3855 */
3856static int hmR0VmxSetupVmcsProcCtls2(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3857{
3858 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3859 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls2.n.allowed0; /* Bits set here must be set in the VMCS. */
3860 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3861
3862 /* WBINVD causes a VM-exit. */
3863 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_WBINVD_EXIT)
3864 fVal |= VMX_PROC_CTLS2_WBINVD_EXIT;
3865
3866 /* Enable EPT (aka nested-paging). */
3867 if (pVM->hmr0.s.fNestedPaging)
3868 fVal |= VMX_PROC_CTLS2_EPT;
3869
3870 /* Enable the INVPCID instruction if we expose it to the guest and is supported
3871 by the hardware. Without this, guest executing INVPCID would cause a #UD. */
3872 if ( pVM->cpum.ro.GuestFeatures.fInvpcid
3873 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_INVPCID))
3874 fVal |= VMX_PROC_CTLS2_INVPCID;
3875
3876 /* Enable VPID. */
3877 if (pVM->hmr0.s.vmx.fVpid)
3878 fVal |= VMX_PROC_CTLS2_VPID;
3879
3880 /* Enable unrestricted guest execution. */
3881 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
3882 fVal |= VMX_PROC_CTLS2_UNRESTRICTED_GUEST;
3883
3884#if 0
3885 if (pVM->hm.s.fVirtApicRegs)
3886 {
3887 /* Enable APIC-register virtualization. */
3888 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT);
3889 fVal |= VMX_PROC_CTLS2_APIC_REG_VIRT;
3890
3891 /* Enable virtual-interrupt delivery. */
3892 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY);
3893 fVal |= VMX_PROC_CTLS2_VIRT_INTR_DELIVERY;
3894 }
3895#endif
3896
3897 /* Virtualize-APIC accesses if supported by the CPU. The virtual-APIC page is
3898 where the TPR shadow resides. */
3899 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
3900 * done dynamically. */
3901 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
3902 {
3903 fVal |= VMX_PROC_CTLS2_VIRT_APIC_ACCESS;
3904 hmR0VmxSetupVmcsApicAccessAddr(pVCpu);
3905 }
3906
3907 /* Enable the RDTSCP instruction if we expose it to the guest and is supported
3908 by the hardware. Without this, guest executing RDTSCP would cause a #UD. */
3909 if ( pVM->cpum.ro.GuestFeatures.fRdTscP
3910 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_RDTSCP))
3911 fVal |= VMX_PROC_CTLS2_RDTSCP;
3912
3913 /* Enable Pause-Loop exiting. */
3914 if ( (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
3915 && pVM->hm.s.vmx.cPleGapTicks
3916 && pVM->hm.s.vmx.cPleWindowTicks)
3917 {
3918 fVal |= VMX_PROC_CTLS2_PAUSE_LOOP_EXIT;
3919
3920 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks); AssertRC(rc);
3921 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks); AssertRC(rc);
3922 }
3923
3924 if ((fVal & fZap) != fVal)
3925 {
3926 LogRelFunc(("Invalid secondary processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3927 g_HmMsrs.u.vmx.ProcCtls2.n.allowed0, fVal, fZap));
3928 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
3929 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3930 }
3931
3932 /* Commit it to the VMCS and update our cache. */
3933 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, fVal);
3934 AssertRC(rc);
3935 pVmcsInfo->u32ProcCtls2 = fVal;
3936
3937 return VINF_SUCCESS;
3938}
3939
3940
3941/**
3942 * Sets up processor-based VM-execution controls in the VMCS.
3943 *
3944 * @returns VBox status code.
3945 * @param pVCpu The cross context virtual CPU structure.
3946 * @param pVmcsInfo The VMCS info. object.
3947 */
3948static int hmR0VmxSetupVmcsProcCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3949{
3950 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3951 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
3952 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3953
3954 fVal |= VMX_PROC_CTLS_HLT_EXIT /* HLT causes a VM-exit. */
3955 | VMX_PROC_CTLS_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
3956 | VMX_PROC_CTLS_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
3957 | VMX_PROC_CTLS_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
3958 | VMX_PROC_CTLS_RDPMC_EXIT /* RDPMC causes a VM-exit. */
3959 | VMX_PROC_CTLS_MONITOR_EXIT /* MONITOR causes a VM-exit. */
3960 | VMX_PROC_CTLS_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
3961
3962 /* We toggle VMX_PROC_CTLS_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
3963 if ( !(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MOV_DR_EXIT)
3964 || (g_HmMsrs.u.vmx.ProcCtls.n.allowed0 & VMX_PROC_CTLS_MOV_DR_EXIT))
3965 {
3966 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
3967 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3968 }
3969
3970 /* Without nested paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
3971 if (!pVM->hmr0.s.fNestedPaging)
3972 {
3973 Assert(!pVM->hmr0.s.vmx.fUnrestrictedGuest);
3974 fVal |= VMX_PROC_CTLS_INVLPG_EXIT
3975 | VMX_PROC_CTLS_CR3_LOAD_EXIT
3976 | VMX_PROC_CTLS_CR3_STORE_EXIT;
3977 }
3978
3979 /* Use TPR shadowing if supported by the CPU. */
3980 if ( PDMHasApic(pVM)
3981 && (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
3982 {
3983 fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
3984 /* CR8 writes cause a VM-exit based on TPR threshold. */
3985 Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
3986 Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
3987 hmR0VmxSetupVmcsVirtApicAddr(pVmcsInfo);
3988 }
3989 else
3990 {
3991 /* Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is
3992 invalid on 32-bit Intel CPUs. Set this control only for 64-bit guests. */
3993 if (pVM->hmr0.s.fAllow64BitGuests)
3994 fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
3995 | VMX_PROC_CTLS_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
3996 }
3997
3998 /* Use MSR-bitmaps if supported by the CPU. */
3999 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4000 {
4001 fVal |= VMX_PROC_CTLS_USE_MSR_BITMAPS;
4002 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
4003 }
4004
4005 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
4006 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
4007 fVal |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
4008
4009 if ((fVal & fZap) != fVal)
4010 {
4011 LogRelFunc(("Invalid processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
4012 g_HmMsrs.u.vmx.ProcCtls.n.allowed0, fVal, fZap));
4013 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
4014 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4015 }
4016
4017 /* Commit it to the VMCS and update our cache. */
4018 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, fVal);
4019 AssertRC(rc);
4020 pVmcsInfo->u32ProcCtls = fVal;
4021
4022 /* Set up MSR permissions that don't change through the lifetime of the VM. */
4023 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4024 hmR0VmxSetupVmcsMsrPermissions(pVCpu, pVmcsInfo);
4025
4026 /* Set up secondary processor-based VM-execution controls if the CPU supports it. */
4027 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
4028 return hmR0VmxSetupVmcsProcCtls2(pVCpu, pVmcsInfo);
4029
4030 /* Sanity check, should not really happen. */
4031 if (RT_LIKELY(!pVM->hmr0.s.vmx.fUnrestrictedGuest))
4032 { /* likely */ }
4033 else
4034 {
4035 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
4036 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4037 }
4038
4039 /* Old CPUs without secondary processor-based VM-execution controls would end up here. */
4040 return VINF_SUCCESS;
4041}
4042
4043
4044/**
4045 * Sets up miscellaneous (everything other than Pin, Processor and secondary
4046 * Processor-based VM-execution) control fields in the VMCS.
4047 *
4048 * @returns VBox status code.
4049 * @param pVCpu The cross context virtual CPU structure.
4050 * @param pVmcsInfo The VMCS info. object.
4051 */
4052static int hmR0VmxSetupVmcsMiscCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4053{
4054#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4055 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
4056 {
4057 hmR0VmxSetupVmcsVmreadBitmapAddr(pVCpu);
4058 hmR0VmxSetupVmcsVmwriteBitmapAddr(pVCpu);
4059 }
4060#endif
4061
4062 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
4063 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
4064 AssertRC(rc);
4065
4066 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
4067 if (RT_SUCCESS(rc))
4068 {
4069 uint64_t const u64Cr0Mask = hmR0VmxGetFixedCr0Mask(pVCpu);
4070 uint64_t const u64Cr4Mask = hmR0VmxGetFixedCr4Mask(pVCpu);
4071
4072 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask); AssertRC(rc);
4073 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask); AssertRC(rc);
4074
4075 pVmcsInfo->u64Cr0Mask = u64Cr0Mask;
4076 pVmcsInfo->u64Cr4Mask = u64Cr4Mask;
4077
4078 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fLbr)
4079 {
4080 rc = VMXWriteVmcsNw(VMX_VMCS64_GUEST_DEBUGCTL_FULL, MSR_IA32_DEBUGCTL_LBR);
4081 AssertRC(rc);
4082 }
4083 return VINF_SUCCESS;
4084 }
4085 else
4086 LogRelFunc(("Failed to initialize VMCS auto-load/store MSR addresses. rc=%Rrc\n", rc));
4087 return rc;
4088}
4089
4090
4091/**
4092 * Sets up the initial exception bitmap in the VMCS based on static conditions.
4093 *
4094 * We shall setup those exception intercepts that don't change during the
4095 * lifetime of the VM here. The rest are done dynamically while loading the
4096 * guest state.
4097 *
4098 * @param pVCpu The cross context virtual CPU structure.
4099 * @param pVmcsInfo The VMCS info. object.
4100 */
4101static void hmR0VmxSetupVmcsXcptBitmap(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4102{
4103 /*
4104 * The following exceptions are always intercepted:
4105 *
4106 * #AC - To prevent the guest from hanging the CPU.
4107 * #DB - To maintain the DR6 state even when intercepting DRx reads/writes and
4108 * recursive #DBs can cause a CPU hang.
4109 * #PF - To sync our shadow page tables when nested-paging is not used.
4110 */
4111 bool const fNestedPaging = pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging;
4112 uint32_t const uXcptBitmap = RT_BIT(X86_XCPT_AC)
4113 | RT_BIT(X86_XCPT_DB)
4114 | (fNestedPaging ? 0 : RT_BIT(X86_XCPT_PF));
4115
4116 /* Commit it to the VMCS. */
4117 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
4118 AssertRC(rc);
4119
4120 /* Update our cache of the exception bitmap. */
4121 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
4122}
4123
4124
4125#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4126/**
4127 * Sets up the VMCS for executing a nested-guest using hardware-assisted VMX.
4128 *
4129 * @returns VBox status code.
4130 * @param pVmcsInfo The VMCS info. object.
4131 */
4132static int hmR0VmxSetupVmcsCtlsNested(PVMXVMCSINFO pVmcsInfo)
4133{
4134 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
4135 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
4136 AssertRC(rc);
4137
4138 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
4139 if (RT_SUCCESS(rc))
4140 {
4141 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4142 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
4143
4144 /* Paranoia - We've not yet initialized these, they shall be done while merging the VMCS. */
4145 Assert(!pVmcsInfo->u64Cr0Mask);
4146 Assert(!pVmcsInfo->u64Cr4Mask);
4147 return VINF_SUCCESS;
4148 }
4149 LogRelFunc(("Failed to set up the VMCS link pointer in the nested-guest VMCS. rc=%Rrc\n", rc));
4150 return rc;
4151}
4152#endif
4153
4154
4155/**
4156 * Sets pfnStartVm to the best suited variant.
4157 *
4158 * This must be called whenever anything changes relative to the hmR0VmXStartVm
4159 * variant selection:
4160 * - pVCpu->hm.s.fLoadSaveGuestXcr0
4161 * - HM_WSF_IBPB_ENTRY in pVCpu->hmr0.s.fWorldSwitcher
4162 * - HM_WSF_IBPB_EXIT in pVCpu->hmr0.s.fWorldSwitcher
4163 * - Perhaps: CPUMIsGuestFPUStateActive() (windows only)
4164 * - Perhaps: CPUMCTX.fXStateMask (windows only)
4165 *
4166 * We currently ASSUME that neither HM_WSF_IBPB_ENTRY nor HM_WSF_IBPB_EXIT
4167 * cannot be changed at runtime.
4168 */
4169static void hmR0VmxUpdateStartVmFunction(PVMCPUCC pVCpu)
4170{
4171 static const struct CLANGWORKAROUND { PFNHMVMXSTARTVM pfn; } s_aHmR0VmxStartVmFunctions[] =
4172 {
4173 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4174 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4175 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4176 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4177 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4178 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4179 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4180 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4181 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4182 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4183 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4184 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4185 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4186 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4187 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4188 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4189 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4190 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4191 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4192 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4193 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4194 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4195 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4196 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4197 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4198 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4199 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4200 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4201 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4202 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4203 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4204 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4205 };
4206 uintptr_t const idx = (pVCpu->hmr0.s.fLoadSaveGuestXcr0 ? 1 : 0)
4207 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_IBPB_ENTRY ? 2 : 0)
4208 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_L1D_ENTRY ? 4 : 0)
4209 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_MDS_ENTRY ? 8 : 0)
4210 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_IBPB_EXIT ? 16 : 0);
4211 PFNHMVMXSTARTVM const pfnStartVm = s_aHmR0VmxStartVmFunctions[idx].pfn;
4212 if (pVCpu->hmr0.s.vmx.pfnStartVm != pfnStartVm)
4213 pVCpu->hmr0.s.vmx.pfnStartVm = pfnStartVm;
4214}
4215
4216
4217/**
4218 * Selector FNHMSVMVMRUN implementation.
4219 */
4220static DECLCALLBACK(int) hmR0VmxStartVmSelector(PVMXVMCSINFO pVmcsInfo, PVMCPUCC pVCpu, bool fResume)
4221{
4222 hmR0VmxUpdateStartVmFunction(pVCpu);
4223 return pVCpu->hmr0.s.vmx.pfnStartVm(pVmcsInfo, pVCpu, fResume);
4224}
4225
4226
4227/**
4228 * Sets up the VMCS for executing a guest (or nested-guest) using hardware-assisted
4229 * VMX.
4230 *
4231 * @returns VBox status code.
4232 * @param pVCpu The cross context virtual CPU structure.
4233 * @param pVmcsInfo The VMCS info. object.
4234 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
4235 */
4236static int hmR0VmxSetupVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
4237{
4238 Assert(pVmcsInfo->pvVmcs);
4239 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4240
4241 /* Set the CPU specified revision identifier at the beginning of the VMCS structure. */
4242 *(uint32_t *)pVmcsInfo->pvVmcs = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
4243 const char * const pszVmcs = fIsNstGstVmcs ? "nested-guest VMCS" : "guest VMCS";
4244
4245 LogFlowFunc(("\n"));
4246
4247 /*
4248 * Initialize the VMCS using VMCLEAR before loading the VMCS.
4249 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
4250 */
4251 int rc = hmR0VmxClearVmcs(pVmcsInfo);
4252 if (RT_SUCCESS(rc))
4253 {
4254 rc = hmR0VmxLoadVmcs(pVmcsInfo);
4255 if (RT_SUCCESS(rc))
4256 {
4257 /*
4258 * Initialize the hardware-assisted VMX execution handler for guest and nested-guest VMCS.
4259 * The host is always 64-bit since we no longer support 32-bit hosts.
4260 * Currently we have just a single handler for all guest modes as well, see @bugref{6208#c73}.
4261 */
4262 if (!fIsNstGstVmcs)
4263 {
4264 rc = hmR0VmxSetupVmcsPinCtls(pVCpu, pVmcsInfo);
4265 if (RT_SUCCESS(rc))
4266 {
4267 rc = hmR0VmxSetupVmcsProcCtls(pVCpu, pVmcsInfo);
4268 if (RT_SUCCESS(rc))
4269 {
4270 rc = hmR0VmxSetupVmcsMiscCtls(pVCpu, pVmcsInfo);
4271 if (RT_SUCCESS(rc))
4272 {
4273 hmR0VmxSetupVmcsXcptBitmap(pVCpu, pVmcsInfo);
4274#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4275 /*
4276 * If a shadow VMCS is allocated for the VMCS info. object, initialize the
4277 * VMCS revision ID and shadow VMCS indicator bit. Also, clear the VMCS
4278 * making it fit for use when VMCS shadowing is later enabled.
4279 */
4280 if (pVmcsInfo->pvShadowVmcs)
4281 {
4282 VMXVMCSREVID VmcsRevId;
4283 VmcsRevId.u = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
4284 VmcsRevId.n.fIsShadowVmcs = 1;
4285 *(uint32_t *)pVmcsInfo->pvShadowVmcs = VmcsRevId.u;
4286 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
4287 if (RT_SUCCESS(rc))
4288 { /* likely */ }
4289 else
4290 LogRelFunc(("Failed to initialize shadow VMCS. rc=%Rrc\n", rc));
4291 }
4292#endif
4293 }
4294 else
4295 LogRelFunc(("Failed to setup miscellaneous controls. rc=%Rrc\n", rc));
4296 }
4297 else
4298 LogRelFunc(("Failed to setup processor-based VM-execution controls. rc=%Rrc\n", rc));
4299 }
4300 else
4301 LogRelFunc(("Failed to setup pin-based controls. rc=%Rrc\n", rc));
4302 }
4303 else
4304 {
4305#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4306 rc = hmR0VmxSetupVmcsCtlsNested(pVmcsInfo);
4307 if (RT_SUCCESS(rc))
4308 { /* likely */ }
4309 else
4310 LogRelFunc(("Failed to initialize nested-guest VMCS. rc=%Rrc\n", rc));
4311#else
4312 AssertFailed();
4313#endif
4314 }
4315 }
4316 else
4317 LogRelFunc(("Failed to load the %s. rc=%Rrc\n", rc, pszVmcs));
4318 }
4319 else
4320 LogRelFunc(("Failed to clear the %s. rc=%Rrc\n", rc, pszVmcs));
4321
4322 /* Sync any CPU internal VMCS data back into our VMCS in memory. */
4323 if (RT_SUCCESS(rc))
4324 {
4325 rc = hmR0VmxClearVmcs(pVmcsInfo);
4326 if (RT_SUCCESS(rc))
4327 { /* likely */ }
4328 else
4329 LogRelFunc(("Failed to clear the %s post setup. rc=%Rrc\n", rc, pszVmcs));
4330 }
4331
4332 /*
4333 * Update the last-error record both for failures and success, so we
4334 * can propagate the status code back to ring-3 for diagnostics.
4335 */
4336 hmR0VmxUpdateErrorRecord(pVCpu, rc);
4337 NOREF(pszVmcs);
4338 return rc;
4339}
4340
4341
4342/**
4343 * Does global VT-x initialization (called during module initialization).
4344 *
4345 * @returns VBox status code.
4346 */
4347VMMR0DECL(int) VMXR0GlobalInit(void)
4348{
4349#ifdef HMVMX_USE_FUNCTION_TABLE
4350 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_aVMExitHandlers));
4351# ifdef VBOX_STRICT
4352 for (unsigned i = 0; i < RT_ELEMENTS(g_aVMExitHandlers); i++)
4353 Assert(g_aVMExitHandlers[i].pfn);
4354# endif
4355#endif
4356 return VINF_SUCCESS;
4357}
4358
4359
4360/**
4361 * Does global VT-x termination (called during module termination).
4362 */
4363VMMR0DECL(void) VMXR0GlobalTerm()
4364{
4365 /* Nothing to do currently. */
4366}
4367
4368
4369/**
4370 * Sets up and activates VT-x on the current CPU.
4371 *
4372 * @returns VBox status code.
4373 * @param pHostCpu The HM physical-CPU structure.
4374 * @param pVM The cross context VM structure. Can be
4375 * NULL after a host resume operation.
4376 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
4377 * fEnabledByHost is @c true).
4378 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
4379 * @a fEnabledByHost is @c true).
4380 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
4381 * enable VT-x on the host.
4382 * @param pHwvirtMsrs Pointer to the hardware-virtualization MSRs.
4383 */
4384VMMR0DECL(int) VMXR0EnableCpu(PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
4385 PCSUPHWVIRTMSRS pHwvirtMsrs)
4386{
4387 AssertPtr(pHostCpu);
4388 AssertPtr(pHwvirtMsrs);
4389 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4390
4391 /* Enable VT-x if it's not already enabled by the host. */
4392 if (!fEnabledByHost)
4393 {
4394 int rc = hmR0VmxEnterRootMode(pHostCpu, pVM, HCPhysCpuPage, pvCpuPage);
4395 if (RT_FAILURE(rc))
4396 return rc;
4397 }
4398
4399 /*
4400 * Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been
4401 * using EPTPs) so we don't retain any stale guest-physical mappings which won't get
4402 * invalidated when flushing by VPID.
4403 */
4404 if (pHwvirtMsrs->u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
4405 {
4406 hmR0VmxFlushEpt(NULL /* pVCpu */, NULL /* pVmcsInfo */, VMXTLBFLUSHEPT_ALL_CONTEXTS);
4407 pHostCpu->fFlushAsidBeforeUse = false;
4408 }
4409 else
4410 pHostCpu->fFlushAsidBeforeUse = true;
4411
4412 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
4413 ++pHostCpu->cTlbFlushes;
4414
4415 return VINF_SUCCESS;
4416}
4417
4418
4419/**
4420 * Deactivates VT-x on the current CPU.
4421 *
4422 * @returns VBox status code.
4423 * @param pHostCpu The HM physical-CPU structure.
4424 * @param pvCpuPage Pointer to the VMXON region.
4425 * @param HCPhysCpuPage Physical address of the VMXON region.
4426 *
4427 * @remarks This function should never be called when SUPR0EnableVTx() or
4428 * similar was used to enable VT-x on the host.
4429 */
4430VMMR0DECL(int) VMXR0DisableCpu(PHMPHYSCPU pHostCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
4431{
4432 RT_NOREF2(pvCpuPage, HCPhysCpuPage);
4433
4434 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4435 return hmR0VmxLeaveRootMode(pHostCpu);
4436}
4437
4438
4439/**
4440 * Does per-VM VT-x initialization.
4441 *
4442 * @returns VBox status code.
4443 * @param pVM The cross context VM structure.
4444 */
4445VMMR0DECL(int) VMXR0InitVM(PVMCC pVM)
4446{
4447 AssertPtr(pVM);
4448 LogFlowFunc(("pVM=%p\n", pVM));
4449
4450 hmR0VmxStructsInit(pVM);
4451 int rc = hmR0VmxStructsAlloc(pVM);
4452 if (RT_FAILURE(rc))
4453 {
4454 LogRelFunc(("Failed to allocated VMX structures. rc=%Rrc\n", rc));
4455 return rc;
4456 }
4457
4458 /* Setup the crash dump page. */
4459#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4460 strcpy((char *)pVM->hmr0.s.vmx.pbScratch, "SCRATCH Magic");
4461 *(uint64_t *)(pVM->hmr0.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
4462#endif
4463 return VINF_SUCCESS;
4464}
4465
4466
4467/**
4468 * Does per-VM VT-x termination.
4469 *
4470 * @returns VBox status code.
4471 * @param pVM The cross context VM structure.
4472 */
4473VMMR0DECL(int) VMXR0TermVM(PVMCC pVM)
4474{
4475 AssertPtr(pVM);
4476 LogFlowFunc(("pVM=%p\n", pVM));
4477
4478#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4479 if (pVM->hmr0.s.vmx.pbScratch)
4480 RT_BZERO(pVM->hmr0.s.vmx.pbScratch, X86_PAGE_4K_SIZE);
4481#endif
4482 hmR0VmxStructsFree(pVM);
4483 return VINF_SUCCESS;
4484}
4485
4486
4487/**
4488 * Sets up the VM for execution using hardware-assisted VMX.
4489 * This function is only called once per-VM during initialization.
4490 *
4491 * @returns VBox status code.
4492 * @param pVM The cross context VM structure.
4493 */
4494VMMR0DECL(int) VMXR0SetupVM(PVMCC pVM)
4495{
4496 AssertPtr(pVM);
4497 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4498
4499 LogFlowFunc(("pVM=%p\n", pVM));
4500
4501 /*
4502 * At least verify if VMX is enabled, since we can't check if we're in VMX root mode or not
4503 * without causing a #GP.
4504 */
4505 RTCCUINTREG const uHostCr4 = ASMGetCR4();
4506 if (RT_LIKELY(uHostCr4 & X86_CR4_VMXE))
4507 { /* likely */ }
4508 else
4509 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
4510
4511 /*
4512 * Check that nested paging is supported if enabled and copy over the flag to the
4513 * ring-0 only structure.
4514 */
4515 bool const fNestedPaging = pVM->hm.s.fNestedPagingCfg;
4516 AssertReturn( !fNestedPaging
4517 || (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_EPT), /** @todo use a ring-0 copy of ProcCtls2.n.allowed1 */
4518 VERR_INCOMPATIBLE_CONFIG);
4519 pVM->hmr0.s.fNestedPaging = fNestedPaging;
4520 pVM->hmr0.s.fAllow64BitGuests = pVM->hm.s.fAllow64BitGuestsCfg;
4521
4522 /*
4523 * Without unrestricted guest execution, pRealModeTSS and pNonPagingModeEPTPageTable *must*
4524 * always be allocated. We no longer support the highly unlikely case of unrestricted guest
4525 * without pRealModeTSS, see hmR3InitFinalizeR0Intel().
4526 */
4527 bool const fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuestCfg;
4528 AssertReturn( !fUnrestrictedGuest
4529 || ( (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST)
4530 && fNestedPaging),
4531 VERR_INCOMPATIBLE_CONFIG);
4532 if ( !fUnrestrictedGuest
4533 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
4534 || !pVM->hm.s.vmx.pRealModeTSS))
4535 {
4536 LogRelFunc(("Invalid real-on-v86 state.\n"));
4537 return VERR_INTERNAL_ERROR;
4538 }
4539 pVM->hmr0.s.vmx.fUnrestrictedGuest = fUnrestrictedGuest;
4540
4541 /* Initialize these always, see hmR3InitFinalizeR0().*/
4542 pVM->hm.s.vmx.enmTlbFlushEptForRing3 = pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NONE;
4543 pVM->hm.s.vmx.enmTlbFlushVpidForRing3 = pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NONE;
4544
4545 /* Setup the tagged-TLB flush handlers. */
4546 int rc = hmR0VmxSetupTaggedTlb(pVM);
4547 if (RT_FAILURE(rc))
4548 {
4549 LogRelFunc(("Failed to setup tagged TLB. rc=%Rrc\n", rc));
4550 return rc;
4551 }
4552
4553 /* Determine LBR capabilities. */
4554 if (pVM->hm.s.vmx.fLbr)
4555 {
4556 rc = hmR0VmxSetupLbrMsrRange(pVM);
4557 if (RT_FAILURE(rc))
4558 {
4559 LogRelFunc(("Failed to setup LBR MSR range. rc=%Rrc\n", rc));
4560 return rc;
4561 }
4562 }
4563
4564#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4565 /* Setup the shadow VMCS fields array and VMREAD/VMWRITE bitmaps. */
4566 if (pVM->hm.s.vmx.fUseVmcsShadowing)
4567 {
4568 rc = hmR0VmxSetupShadowVmcsFieldsArrays(pVM);
4569 if (RT_SUCCESS(rc))
4570 hmR0VmxSetupVmreadVmwriteBitmaps(pVM);
4571 else
4572 {
4573 LogRelFunc(("Failed to setup shadow VMCS fields arrays. rc=%Rrc\n", rc));
4574 return rc;
4575 }
4576 }
4577#endif
4578
4579 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
4580 {
4581 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
4582 Log4Func(("pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
4583
4584 pVCpu->hmr0.s.vmx.pfnStartVm = hmR0VmxStartVmSelector;
4585
4586 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
4587 if (RT_SUCCESS(rc))
4588 {
4589#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4590 if (pVM->cpum.ro.GuestFeatures.fVmx)
4591 {
4592 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
4593 if (RT_SUCCESS(rc))
4594 { /* likely */ }
4595 else
4596 {
4597 LogRelFunc(("Nested-guest VMCS setup failed. rc=%Rrc\n", rc));
4598 return rc;
4599 }
4600 }
4601#endif
4602 }
4603 else
4604 {
4605 LogRelFunc(("VMCS setup failed. rc=%Rrc\n", rc));
4606 return rc;
4607 }
4608 }
4609
4610 return VINF_SUCCESS;
4611}
4612
4613
4614/**
4615 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
4616 * the VMCS.
4617 * @returns CR4 for passing along to hmR0VmxExportHostSegmentRegs.
4618 */
4619static uint64_t hmR0VmxExportHostControlRegs(void)
4620{
4621 int rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR0, ASMGetCR0()); AssertRC(rc);
4622 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR3, ASMGetCR3()); AssertRC(rc);
4623 uint64_t uHostCr4 = ASMGetCR4();
4624 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR4, uHostCr4); AssertRC(rc);
4625 return uHostCr4;
4626}
4627
4628
4629/**
4630 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
4631 * the host-state area in the VMCS.
4632 *
4633 * @returns VBox status code.
4634 * @param pVCpu The cross context virtual CPU structure.
4635 * @param uHostCr4 The host CR4 value.
4636 */
4637static int hmR0VmxExportHostSegmentRegs(PVMCPUCC pVCpu, uint64_t uHostCr4)
4638{
4639 /*
4640 * If we've executed guest code using hardware-assisted VMX, the host-state bits
4641 * will be messed up. We should -not- save the messed up state without restoring
4642 * the original host-state, see @bugref{7240}.
4643 *
4644 * This apparently can happen (most likely the FPU changes), deal with it rather than
4645 * asserting. Was observed booting Solaris 10u10 32-bit guest.
4646 */
4647 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
4648 {
4649 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hmr0.s.vmx.fRestoreHostFlags,
4650 pVCpu->idCpu));
4651 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
4652 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
4653 }
4654
4655 /*
4656 * Get all the host info.
4657 * ASSUME it is safe to use rdfsbase and friends if the CR4.FSGSBASE bit is set
4658 * without also checking the cpuid bit.
4659 */
4660 uint32_t fRestoreHostFlags;
4661#if RT_INLINE_ASM_EXTERNAL
4662 if (uHostCr4 & X86_CR4_FSGSBASE)
4663 {
4664 hmR0VmxExportHostSegmentRegsAsmHlp(&pVCpu->hmr0.s.vmx.RestoreHost, true /*fHaveFsGsBase*/);
4665 fRestoreHostFlags = VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE;
4666 }
4667 else
4668 {
4669 hmR0VmxExportHostSegmentRegsAsmHlp(&pVCpu->hmr0.s.vmx.RestoreHost, false /*fHaveFsGsBase*/);
4670 fRestoreHostFlags = 0;
4671 }
4672 RTSEL uSelES = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelES;
4673 RTSEL uSelDS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelDS;
4674 RTSEL uSelFS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelFS;
4675 RTSEL uSelGS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelGS;
4676#else
4677 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR = ASMGetTR();
4678 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS = ASMGetSS();
4679 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS = ASMGetCS();
4680 ASMGetGDTR((PRTGDTR)&pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr);
4681 ASMGetIDTR((PRTIDTR)&pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr);
4682 if (uHostCr4 & X86_CR4_FSGSBASE)
4683 {
4684 pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase = ASMGetFSBase();
4685 pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase = ASMGetGSBase();
4686 fRestoreHostFlags = VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE;
4687 }
4688 else
4689 {
4690 pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase = ASMRdMsr(MSR_K8_FS_BASE);
4691 pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase = ASMRdMsr(MSR_K8_GS_BASE);
4692 fRestoreHostFlags = 0;
4693 }
4694 RTSEL uSelES, uSelDS, uSelFS, uSelGS;
4695 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelDS = uSelDS = ASMGetDS();
4696 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelES = uSelES = ASMGetES();
4697 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelFS = uSelFS = ASMGetFS();
4698 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelGS = uSelGS = ASMGetGS();
4699#endif
4700
4701 /*
4702 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to
4703 * gain VM-entry and restore them before we get preempted.
4704 *
4705 * See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
4706 */
4707 RTSEL const uSelAll = uSelFS | uSelGS | uSelES | uSelDS;
4708 if (uSelAll & (X86_SEL_RPL | X86_SEL_LDT))
4709 {
4710 if (!(uSelAll & X86_SEL_LDT))
4711 {
4712#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_uVmcsVar) \
4713 do { \
4714 (a_uVmcsVar) = pVCpu->hmr0.s.vmx.RestoreHost.uHostSel##a_Seg; \
4715 if ((a_uVmcsVar) & X86_SEL_RPL) \
4716 { \
4717 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4718 (a_uVmcsVar) = 0; \
4719 } \
4720 } while (0)
4721 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4722 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4723 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4724 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4725#undef VMXLOCAL_ADJUST_HOST_SEG
4726 }
4727 else
4728 {
4729#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_uVmcsVar) \
4730 do { \
4731 (a_uVmcsVar) = pVCpu->hmr0.s.vmx.RestoreHost.uHostSel##a_Seg; \
4732 if ((a_uVmcsVar) & (X86_SEL_RPL | X86_SEL_LDT)) \
4733 { \
4734 if (!((a_uVmcsVar) & X86_SEL_LDT)) \
4735 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4736 else \
4737 { \
4738 uint32_t const fAttr = ASMGetSegAttr(a_uVmcsVar); \
4739 if ((fAttr & X86_DESC_P) && fAttr != UINT32_MAX) \
4740 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4741 } \
4742 (a_uVmcsVar) = 0; \
4743 } \
4744 } while (0)
4745 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4746 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4747 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4748 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4749#undef VMXLOCAL_ADJUST_HOST_SEG
4750 }
4751 }
4752
4753 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
4754 Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR & X86_SEL_RPL)); Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR & X86_SEL_LDT)); Assert(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR);
4755 Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS & X86_SEL_RPL)); Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS & X86_SEL_LDT)); Assert(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS);
4756 Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS & X86_SEL_RPL)); Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS & X86_SEL_LDT));
4757 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
4758 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
4759 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
4760 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
4761
4762 /*
4763 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps
4764 * them to the maximum limit (0xffff) on every VM-exit.
4765 */
4766 if (pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb != 0xffff)
4767 fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
4768
4769 /*
4770 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT" and
4771 * Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit
4772 * as 0xfff, VT-x bloating the limit to 0xffff shouldn't cause any different CPU behavior.
4773 * However, several hosts either insists on 0xfff being the limit (Windows Patch Guard) or
4774 * uses the limit for other purposes (darwin puts the CPU ID in there but botches sidt
4775 * alignment in at least one consumer). So, we're only allowing the IDTR.LIMIT to be left
4776 * at 0xffff on hosts where we are sure it won't cause trouble.
4777 */
4778#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
4779 if (pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.cb < 0x0fff)
4780#else
4781 if (pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.cb != 0xffff)
4782#endif
4783 fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
4784
4785 /*
4786 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI
4787 * and RPL bits is effectively what the CPU does for "scaling by 8". TI is always 0 and
4788 * RPL should be too in most cases.
4789 */
4790 RTSEL const uSelTR = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR;
4791 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb,
4792 ("TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb),
4793 VERR_VMX_INVALID_HOST_STATE);
4794
4795 PCX86DESCHC pDesc = (PCX86DESCHC)(pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.uAddr + (uSelTR & X86_SEL_MASK));
4796 uintptr_t const uTRBase = X86DESC64_BASE(pDesc);
4797
4798 /*
4799 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on
4800 * all VM-exits. The type is the same for 64-bit busy TSS[1]. The limit needs manual
4801 * restoration if the host has something else. Task switching is not supported in 64-bit
4802 * mode[2], but the limit still matters as IOPM is supported in 64-bit mode. Restoring the
4803 * limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
4804 *
4805 * [1] See Intel spec. 3.5 "System Descriptor Types".
4806 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
4807 */
4808 Assert(pDesc->System.u4Type == 11);
4809 if ( pDesc->System.u16LimitLow != 0x67
4810 || pDesc->System.u4LimitHigh)
4811 {
4812 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
4813
4814 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
4815 if (g_fHmHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
4816 fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
4817 if (g_fHmHostKernelFeatures & SUPKERNELFEATURES_GDT_NEED_WRITABLE)
4818 {
4819 /* The GDT is read-only but the writable GDT is available. */
4820 fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_NEED_WRITABLE;
4821 pVCpu->hmr0.s.vmx.RestoreHost.HostGdtrRw.cb = pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb;
4822 int rc = SUPR0GetCurrentGdtRw(&pVCpu->hmr0.s.vmx.RestoreHost.HostGdtrRw.uAddr);
4823 AssertRCReturn(rc, rc);
4824 }
4825 }
4826
4827 pVCpu->hmr0.s.vmx.fRestoreHostFlags = fRestoreHostFlags;
4828
4829 /*
4830 * Do all the VMCS updates in one block to assist nested virtualization.
4831 */
4832 int rc;
4833 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_CS_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS); AssertRC(rc);
4834 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_SS_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS); AssertRC(rc);
4835 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_DS_SEL, uSelDS); AssertRC(rc);
4836 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_ES_SEL, uSelES); AssertRC(rc);
4837 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_FS_SEL, uSelFS); AssertRC(rc);
4838 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_GS_SEL, uSelGS); AssertRC(rc);
4839 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_TR_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR); AssertRC(rc);
4840 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GDTR_BASE, pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.uAddr); AssertRC(rc);
4841 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_IDTR_BASE, pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.uAddr); AssertRC(rc);
4842 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_TR_BASE, uTRBase); AssertRC(rc);
4843 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_FS_BASE, pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase); AssertRC(rc);
4844 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GS_BASE, pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase); AssertRC(rc);
4845
4846 return VINF_SUCCESS;
4847}
4848
4849
4850/**
4851 * Exports certain host MSRs in the VM-exit MSR-load area and some in the
4852 * host-state area of the VMCS.
4853 *
4854 * These MSRs will be automatically restored on the host after every successful
4855 * VM-exit.
4856 *
4857 * @param pVCpu The cross context virtual CPU structure.
4858 *
4859 * @remarks No-long-jump zone!!!
4860 */
4861static void hmR0VmxExportHostMsrs(PVMCPUCC pVCpu)
4862{
4863 AssertPtr(pVCpu);
4864
4865 /*
4866 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
4867 * rather than swapping them on every VM-entry.
4868 */
4869 hmR0VmxLazySaveHostMsrs(pVCpu);
4870
4871 /*
4872 * Host Sysenter MSRs.
4873 */
4874 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS)); AssertRC(rc);
4875 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP)); AssertRC(rc);
4876 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP)); AssertRC(rc);
4877
4878 /*
4879 * Host EFER MSR.
4880 *
4881 * If the CPU supports the newer VMCS controls for managing EFER, use it. Otherwise it's
4882 * done as part of auto-load/store MSR area in the VMCS, see hmR0VmxExportGuestMsrs().
4883 */
4884 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4885 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
4886 {
4887 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, pVM->hm.s.vmx.u64HostMsrEfer);
4888 AssertRC(rc);
4889 }
4890
4891 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
4892 * hmR0VmxExportGuestEntryExitCtls(). */
4893}
4894
4895
4896/**
4897 * Figures out if we need to swap the EFER MSR which is particularly expensive.
4898 *
4899 * We check all relevant bits. For now, that's everything besides LMA/LME, as
4900 * these two bits are handled by VM-entry, see hmR0VMxExportGuestEntryExitCtls().
4901 *
4902 * @returns true if we need to load guest EFER, false otherwise.
4903 * @param pVCpu The cross context virtual CPU structure.
4904 * @param pVmxTransient The VMX-transient structure.
4905 *
4906 * @remarks Requires EFER, CR4.
4907 * @remarks No-long-jump zone!!!
4908 */
4909static bool hmR0VmxShouldSwapEferMsr(PCVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
4910{
4911#ifdef HMVMX_ALWAYS_SWAP_EFER
4912 RT_NOREF2(pVCpu, pVmxTransient);
4913 return true;
4914#else
4915 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4916 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4917 uint64_t const u64HostEfer = pVM->hm.s.vmx.u64HostMsrEfer;
4918 uint64_t const u64GuestEfer = pCtx->msrEFER;
4919
4920# ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4921 /*
4922 * For nested-guests, we shall honor swapping the EFER MSR when requested by
4923 * the nested-guest.
4924 */
4925 if ( pVmxTransient->fIsNestedGuest
4926 && ( CPUMIsGuestVmxEntryCtlsSet(pCtx, VMX_ENTRY_CTLS_LOAD_EFER_MSR)
4927 || CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_SAVE_EFER_MSR)
4928 || CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_LOAD_EFER_MSR)))
4929 return true;
4930# else
4931 RT_NOREF(pVmxTransient);
4932#endif
4933
4934 /*
4935 * For 64-bit guests, if EFER.SCE bit differs, we need to swap the EFER MSR
4936 * to ensure that the guest's SYSCALL behaviour isn't broken, see @bugref{7386}.
4937 */
4938 if ( CPUMIsGuestInLongModeEx(pCtx)
4939 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
4940 return true;
4941
4942 /*
4943 * If the guest uses PAE and EFER.NXE bit differs, we need to swap the EFER MSR
4944 * as it affects guest paging. 64-bit paging implies CR4.PAE as well.
4945 *
4946 * See Intel spec. 4.5 "IA-32e Paging".
4947 * See Intel spec. 4.1.1 "Three Paging Modes".
4948 *
4949 * Verify that we always intercept CR4.PAE and CR0.PG bits, so we don't need to
4950 * import CR4 and CR0 from the VMCS here as those bits are always up to date.
4951 */
4952 Assert(hmR0VmxGetFixedCr4Mask(pVCpu) & X86_CR4_PAE);
4953 Assert(hmR0VmxGetFixedCr0Mask(pVCpu) & X86_CR0_PG);
4954 if ( (pCtx->cr4 & X86_CR4_PAE)
4955 && (pCtx->cr0 & X86_CR0_PG))
4956 {
4957 /*
4958 * If nested paging is not used, verify that the guest paging mode matches the
4959 * shadow paging mode which is/will be placed in the VMCS (which is what will
4960 * actually be used while executing the guest and not the CR4 shadow value).
4961 */
4962 AssertMsg( pVM->hmr0.s.fNestedPaging
4963 || pVCpu->hm.s.enmShadowMode == PGMMODE_PAE
4964 || pVCpu->hm.s.enmShadowMode == PGMMODE_PAE_NX
4965 || pVCpu->hm.s.enmShadowMode == PGMMODE_AMD64
4966 || pVCpu->hm.s.enmShadowMode == PGMMODE_AMD64_NX,
4967 ("enmShadowMode=%u\n", pVCpu->hm.s.enmShadowMode));
4968 if ((u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
4969 {
4970 /* Verify that the host is NX capable. */
4971 Assert(pVCpu->CTX_SUFF(pVM)->cpum.ro.HostFeatures.fNoExecute);
4972 return true;
4973 }
4974 }
4975
4976 return false;
4977#endif
4978}
4979
4980
4981/**
4982 * Exports the guest state with appropriate VM-entry and VM-exit controls in the
4983 * VMCS.
4984 *
4985 * This is typically required when the guest changes paging mode.
4986 *
4987 * @returns VBox status code.
4988 * @param pVCpu The cross context virtual CPU structure.
4989 * @param pVmxTransient The VMX-transient structure.
4990 *
4991 * @remarks Requires EFER.
4992 * @remarks No-long-jump zone!!!
4993 */
4994static int hmR0VmxExportGuestEntryExitCtls(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
4995{
4996 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS)
4997 {
4998 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
4999 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5000
5001 /*
5002 * VM-entry controls.
5003 */
5004 {
5005 uint32_t fVal = g_HmMsrs.u.vmx.EntryCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
5006 uint32_t const fZap = g_HmMsrs.u.vmx.EntryCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
5007
5008 /*
5009 * Load the guest debug controls (DR7 and IA32_DEBUGCTL MSR) on VM-entry.
5010 * The first VT-x capable CPUs only supported the 1-setting of this bit.
5011 *
5012 * For nested-guests, this is a mandatory VM-entry control. It's also
5013 * required because we do not want to leak host bits to the nested-guest.
5014 */
5015 fVal |= VMX_ENTRY_CTLS_LOAD_DEBUG;
5016
5017 /*
5018 * Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry.
5019 *
5020 * For nested-guests, the "IA-32e mode guest" control we initialize with what is
5021 * required to get the nested-guest working with hardware-assisted VMX execution.
5022 * It depends on the nested-guest's IA32_EFER.LMA bit. Remember, a nested hypervisor
5023 * can skip intercepting changes to the EFER MSR. This is why it it needs to be done
5024 * here rather than while merging the guest VMCS controls.
5025 */
5026 if (CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
5027 {
5028 Assert(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LME);
5029 fVal |= VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
5030 }
5031 else
5032 Assert(!(fVal & VMX_ENTRY_CTLS_IA32E_MODE_GUEST));
5033
5034 /*
5035 * If the CPU supports the newer VMCS controls for managing guest/host EFER, use it.
5036 *
5037 * For nested-guests, we use the "load IA32_EFER" if the hardware supports it,
5038 * regardless of whether the nested-guest VMCS specifies it because we are free to
5039 * load whatever MSRs we require and we do not need to modify the guest visible copy
5040 * of the VM-entry MSR load area.
5041 */
5042 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
5043 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
5044 fVal |= VMX_ENTRY_CTLS_LOAD_EFER_MSR;
5045 else
5046 Assert(!(fVal & VMX_ENTRY_CTLS_LOAD_EFER_MSR));
5047
5048 /*
5049 * The following should -not- be set (since we're not in SMM mode):
5050 * - VMX_ENTRY_CTLS_ENTRY_TO_SMM
5051 * - VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON
5052 */
5053
5054 /** @todo VMX_ENTRY_CTLS_LOAD_PERF_MSR,
5055 * VMX_ENTRY_CTLS_LOAD_PAT_MSR. */
5056
5057 if ((fVal & fZap) == fVal)
5058 { /* likely */ }
5059 else
5060 {
5061 Log4Func(("Invalid VM-entry controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
5062 g_HmMsrs.u.vmx.EntryCtls.n.allowed0, fVal, fZap));
5063 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
5064 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
5065 }
5066
5067 /* Commit it to the VMCS. */
5068 if (pVmcsInfo->u32EntryCtls != fVal)
5069 {
5070 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, fVal);
5071 AssertRC(rc);
5072 pVmcsInfo->u32EntryCtls = fVal;
5073 }
5074 }
5075
5076 /*
5077 * VM-exit controls.
5078 */
5079 {
5080 uint32_t fVal = g_HmMsrs.u.vmx.ExitCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
5081 uint32_t const fZap = g_HmMsrs.u.vmx.ExitCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
5082
5083 /*
5084 * Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only
5085 * supported the 1-setting of this bit.
5086 *
5087 * For nested-guests, we set the "save debug controls" as the converse
5088 * "load debug controls" is mandatory for nested-guests anyway.
5089 */
5090 fVal |= VMX_EXIT_CTLS_SAVE_DEBUG;
5091
5092 /*
5093 * Set the host long mode active (EFER.LMA) bit (which Intel calls
5094 * "Host address-space size") if necessary. On VM-exit, VT-x sets both the
5095 * host EFER.LMA and EFER.LME bit to this value. See assertion in
5096 * hmR0VmxExportHostMsrs().
5097 *
5098 * For nested-guests, we always set this bit as we do not support 32-bit
5099 * hosts.
5100 */
5101 fVal |= VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE;
5102
5103 /*
5104 * If the VMCS EFER MSR fields are supported by the hardware, we use it.
5105 *
5106 * For nested-guests, we should use the "save IA32_EFER" control if we also
5107 * used the "load IA32_EFER" control while exporting VM-entry controls.
5108 */
5109 if ( pVM->hm.s.vmx.fSupportsVmcsEfer
5110 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
5111 {
5112 fVal |= VMX_EXIT_CTLS_SAVE_EFER_MSR
5113 | VMX_EXIT_CTLS_LOAD_EFER_MSR;
5114 }
5115
5116 /*
5117 * Enable saving of the VMX-preemption timer value on VM-exit.
5118 * For nested-guests, currently not exposed/used.
5119 */
5120 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
5121 {
5122 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER);
5123 fVal |= VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER;
5124 }
5125
5126 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
5127 Assert(!(fVal & VMX_EXIT_CTLS_ACK_EXT_INT));
5128
5129 /** @todo VMX_EXIT_CTLS_LOAD_PERF_MSR,
5130 * VMX_EXIT_CTLS_SAVE_PAT_MSR,
5131 * VMX_EXIT_CTLS_LOAD_PAT_MSR. */
5132
5133 if ((fVal & fZap) == fVal)
5134 { /* likely */ }
5135 else
5136 {
5137 Log4Func(("Invalid VM-exit controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%R#X32\n",
5138 g_HmMsrs.u.vmx.ExitCtls.n.allowed0, fVal, fZap));
5139 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
5140 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
5141 }
5142
5143 /* Commit it to the VMCS. */
5144 if (pVmcsInfo->u32ExitCtls != fVal)
5145 {
5146 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, fVal);
5147 AssertRC(rc);
5148 pVmcsInfo->u32ExitCtls = fVal;
5149 }
5150 }
5151
5152 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
5153 }
5154 return VINF_SUCCESS;
5155}
5156
5157
5158/**
5159 * Sets the TPR threshold in the VMCS.
5160 *
5161 * @param pVmcsInfo The VMCS info. object.
5162 * @param u32TprThreshold The TPR threshold (task-priority class only).
5163 */
5164DECLINLINE(void) hmR0VmxApicSetTprThreshold(PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
5165{
5166 Assert(!(u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)); /* Bits 31:4 MBZ. */
5167 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
5168 RT_NOREF(pVmcsInfo);
5169 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
5170 AssertRC(rc);
5171}
5172
5173
5174/**
5175 * Exports the guest APIC TPR state into the VMCS.
5176 *
5177 * @param pVCpu The cross context virtual CPU structure.
5178 * @param pVmxTransient The VMX-transient structure.
5179 *
5180 * @remarks No-long-jump zone!!!
5181 */
5182static void hmR0VmxExportGuestApicTpr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5183{
5184 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_APIC_TPR)
5185 {
5186 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
5187
5188 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5189 if (!pVmxTransient->fIsNestedGuest)
5190 {
5191 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
5192 && APICIsEnabled(pVCpu))
5193 {
5194 /*
5195 * Setup TPR shadowing.
5196 */
5197 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
5198 {
5199 bool fPendingIntr = false;
5200 uint8_t u8Tpr = 0;
5201 uint8_t u8PendingIntr = 0;
5202 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
5203 AssertRC(rc);
5204
5205 /*
5206 * If there are interrupts pending but masked by the TPR, instruct VT-x to
5207 * cause a TPR-below-threshold VM-exit when the guest lowers its TPR below the
5208 * priority of the pending interrupt so we can deliver the interrupt. If there
5209 * are no interrupts pending, set threshold to 0 to not cause any
5210 * TPR-below-threshold VM-exits.
5211 */
5212 uint32_t u32TprThreshold = 0;
5213 if (fPendingIntr)
5214 {
5215 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR
5216 (which is the Task-Priority Class). */
5217 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
5218 const uint8_t u8TprPriority = u8Tpr >> 4;
5219 if (u8PendingPriority <= u8TprPriority)
5220 u32TprThreshold = u8PendingPriority;
5221 }
5222
5223 hmR0VmxApicSetTprThreshold(pVmcsInfo, u32TprThreshold);
5224 }
5225 }
5226 }
5227 /* else: the TPR threshold has already been updated while merging the nested-guest VMCS. */
5228 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
5229 }
5230}
5231
5232
5233/**
5234 * Gets the guest interruptibility-state and updates related force-flags.
5235 *
5236 * @returns Guest's interruptibility-state.
5237 * @param pVCpu The cross context virtual CPU structure.
5238 *
5239 * @remarks No-long-jump zone!!!
5240 */
5241static uint32_t hmR0VmxGetGuestIntrStateAndUpdateFFs(PVMCPUCC pVCpu)
5242{
5243 /*
5244 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
5245 */
5246 uint32_t fIntrState = 0;
5247 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
5248 {
5249 /* If inhibition is active, RIP and RFLAGS should've been imported from the VMCS already. */
5250 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
5251
5252 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5253 if (pCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
5254 {
5255 if (pCtx->eflags.Bits.u1IF)
5256 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
5257 else
5258 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS;
5259 }
5260 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
5261 {
5262 /*
5263 * We can clear the inhibit force flag as even if we go back to the recompiler
5264 * without executing guest code in VT-x, the flag's condition to be cleared is
5265 * met and thus the cleared state is correct.
5266 */
5267 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
5268 }
5269 }
5270
5271 /*
5272 * Check if we should inhibit NMI delivery.
5273 */
5274 if (CPUMIsGuestNmiBlocking(pVCpu))
5275 fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
5276
5277 /*
5278 * Validate.
5279 */
5280#ifdef VBOX_STRICT
5281 /* We don't support block-by-SMI yet.*/
5282 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI));
5283
5284 /* Block-by-STI must not be set when interrupts are disabled. */
5285 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
5286 {
5287 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
5288 Assert(pVCpu->cpum.GstCtx.eflags.u & X86_EFL_IF);
5289 }
5290#endif
5291
5292 return fIntrState;
5293}
5294
5295
5296/**
5297 * Exports the exception intercepts required for guest execution in the VMCS.
5298 *
5299 * @param pVCpu The cross context virtual CPU structure.
5300 * @param pVmxTransient The VMX-transient structure.
5301 *
5302 * @remarks No-long-jump zone!!!
5303 */
5304static void hmR0VmxExportGuestXcptIntercepts(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5305{
5306 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_XCPT_INTERCEPTS)
5307 {
5308 /* When executing a nested-guest, we do not need to trap GIM hypercalls by intercepting #UD. */
5309 if ( !pVmxTransient->fIsNestedGuest
5310 && pVCpu->hm.s.fGIMTrapXcptUD)
5311 hmR0VmxAddXcptIntercept(pVmxTransient, X86_XCPT_UD);
5312 else
5313 hmR0VmxRemoveXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
5314
5315 /* Other exception intercepts are handled elsewhere, e.g. while exporting guest CR0. */
5316 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_XCPT_INTERCEPTS);
5317 }
5318}
5319
5320
5321/**
5322 * Exports the guest's RIP into the guest-state area in the VMCS.
5323 *
5324 * @param pVCpu The cross context virtual CPU structure.
5325 *
5326 * @remarks No-long-jump zone!!!
5327 */
5328static void hmR0VmxExportGuestRip(PVMCPUCC pVCpu)
5329{
5330 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RIP)
5331 {
5332 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
5333
5334 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RIP, pVCpu->cpum.GstCtx.rip);
5335 AssertRC(rc);
5336
5337 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RIP);
5338 Log4Func(("rip=%#RX64\n", pVCpu->cpum.GstCtx.rip));
5339 }
5340}
5341
5342
5343/**
5344 * Exports the guest's RSP into the guest-state area in the VMCS.
5345 *
5346 * @param pVCpu The cross context virtual CPU structure.
5347 *
5348 * @remarks No-long-jump zone!!!
5349 */
5350static void hmR0VmxExportGuestRsp(PVMCPUCC pVCpu)
5351{
5352 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RSP)
5353 {
5354 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RSP);
5355
5356 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RSP, pVCpu->cpum.GstCtx.rsp);
5357 AssertRC(rc);
5358
5359 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RSP);
5360 Log4Func(("rsp=%#RX64\n", pVCpu->cpum.GstCtx.rsp));
5361 }
5362}
5363
5364
5365/**
5366 * Exports the guest's RFLAGS into the guest-state area in the VMCS.
5367 *
5368 * @param pVCpu The cross context virtual CPU structure.
5369 * @param pVmxTransient The VMX-transient structure.
5370 *
5371 * @remarks No-long-jump zone!!!
5372 */
5373static void hmR0VmxExportGuestRflags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5374{
5375 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RFLAGS)
5376 {
5377 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
5378
5379 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
5380 Let us assert it as such and use 32-bit VMWRITE. */
5381 Assert(!RT_HI_U32(pVCpu->cpum.GstCtx.rflags.u64));
5382 X86EFLAGS fEFlags = pVCpu->cpum.GstCtx.eflags;
5383 Assert(fEFlags.u32 & X86_EFL_RA1_MASK);
5384 Assert(!(fEFlags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
5385
5386 /*
5387 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so
5388 * we can restore them on VM-exit. Modify the real-mode guest's eflags so that VT-x
5389 * can run the real-mode guest code under Virtual 8086 mode.
5390 */
5391 PVMXVMCSINFOSHARED pVmcsInfo = pVmxTransient->pVmcsInfo->pShared;
5392 if (pVmcsInfo->RealMode.fRealOnV86Active)
5393 {
5394 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
5395 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
5396 Assert(!pVmxTransient->fIsNestedGuest);
5397 pVmcsInfo->RealMode.Eflags.u32 = fEFlags.u32; /* Save the original eflags of the real-mode guest. */
5398 fEFlags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
5399 fEFlags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
5400 }
5401
5402 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RFLAGS, fEFlags.u32);
5403 AssertRC(rc);
5404
5405 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
5406 Log4Func(("eflags=%#RX32\n", fEFlags.u32));
5407 }
5408}
5409
5410
5411#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5412/**
5413 * Copies the nested-guest VMCS to the shadow VMCS.
5414 *
5415 * @returns VBox status code.
5416 * @param pVCpu The cross context virtual CPU structure.
5417 * @param pVmcsInfo The VMCS info. object.
5418 *
5419 * @remarks No-long-jump zone!!!
5420 */
5421static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5422{
5423 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5424 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5425
5426 /*
5427 * Disable interrupts so we don't get preempted while the shadow VMCS is the
5428 * current VMCS, as we may try saving guest lazy MSRs.
5429 *
5430 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
5431 * calling the import VMCS code which is currently performing the guest MSR reads
5432 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
5433 * and the rest of the VMX leave session machinery.
5434 */
5435 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
5436
5437 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5438 if (RT_SUCCESS(rc))
5439 {
5440 /*
5441 * Copy all guest read/write VMCS fields.
5442 *
5443 * We don't check for VMWRITE failures here for performance reasons and
5444 * because they are not expected to fail, barring irrecoverable conditions
5445 * like hardware errors.
5446 */
5447 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
5448 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5449 {
5450 uint64_t u64Val;
5451 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsFields[i];
5452 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5453 VMXWriteVmcs64(uVmcsField, u64Val);
5454 }
5455
5456 /*
5457 * If the host CPU supports writing all VMCS fields, copy the guest read-only
5458 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
5459 */
5460 if (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL)
5461 {
5462 uint32_t const cShadowVmcsRoFields = pVM->hmr0.s.vmx.cShadowVmcsRoFields;
5463 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
5464 {
5465 uint64_t u64Val;
5466 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsRoFields[i];
5467 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5468 VMXWriteVmcs64(uVmcsField, u64Val);
5469 }
5470 }
5471
5472 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5473 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5474 }
5475
5476 ASMSetFlags(fEFlags);
5477 return rc;
5478}
5479
5480
5481/**
5482 * Copies the shadow VMCS to the nested-guest VMCS.
5483 *
5484 * @returns VBox status code.
5485 * @param pVCpu The cross context virtual CPU structure.
5486 * @param pVmcsInfo The VMCS info. object.
5487 *
5488 * @remarks Called with interrupts disabled.
5489 */
5490static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5491{
5492 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5493 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5494 PVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5495
5496 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5497 if (RT_SUCCESS(rc))
5498 {
5499 /*
5500 * Copy guest read/write fields from the shadow VMCS.
5501 * Guest read-only fields cannot be modified, so no need to copy them.
5502 *
5503 * We don't check for VMREAD failures here for performance reasons and
5504 * because they are not expected to fail, barring irrecoverable conditions
5505 * like hardware errors.
5506 */
5507 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
5508 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5509 {
5510 uint64_t u64Val;
5511 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsFields[i];
5512 VMXReadVmcs64(uVmcsField, &u64Val);
5513 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
5514 }
5515
5516 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5517 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5518 }
5519 return rc;
5520}
5521
5522
5523/**
5524 * Enables VMCS shadowing for the given VMCS info. object.
5525 *
5526 * @param pVmcsInfo The VMCS info. object.
5527 *
5528 * @remarks No-long-jump zone!!!
5529 */
5530static void hmR0VmxEnableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5531{
5532 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5533 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
5534 {
5535 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
5536 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
5537 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5538 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
5539 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5540 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
5541 Log4Func(("Enabled\n"));
5542 }
5543}
5544
5545
5546/**
5547 * Disables VMCS shadowing for the given VMCS info. object.
5548 *
5549 * @param pVmcsInfo The VMCS info. object.
5550 *
5551 * @remarks No-long-jump zone!!!
5552 */
5553static void hmR0VmxDisableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5554{
5555 /*
5556 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
5557 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
5558 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
5559 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
5560 *
5561 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
5562 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5563 */
5564 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5565 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
5566 {
5567 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
5568 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5569 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
5570 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5571 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
5572 Log4Func(("Disabled\n"));
5573 }
5574}
5575#endif
5576
5577
5578/**
5579 * Exports the guest hardware-virtualization state.
5580 *
5581 * @returns VBox status code.
5582 * @param pVCpu The cross context virtual CPU structure.
5583 * @param pVmxTransient The VMX-transient structure.
5584 *
5585 * @remarks No-long-jump zone!!!
5586 */
5587static int hmR0VmxExportGuestHwvirtState(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5588{
5589 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
5590 {
5591#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5592 /*
5593 * Check if the VMX feature is exposed to the guest and if the host CPU supports
5594 * VMCS shadowing.
5595 */
5596 if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
5597 {
5598 /*
5599 * If the nested hypervisor has loaded a current VMCS and is in VMX root mode,
5600 * copy the nested hypervisor's current VMCS into the shadow VMCS and enable
5601 * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
5602 *
5603 * We check for VMX root mode here in case the guest executes VMXOFF without
5604 * clearing the current VMCS pointer and our VMXOFF instruction emulation does
5605 * not clear the current VMCS pointer.
5606 */
5607 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5608 if ( CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
5609 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
5610 && CPUMIsGuestVmxCurrentVmcsValid(&pVCpu->cpum.GstCtx))
5611 {
5612 /* Paranoia. */
5613 Assert(!pVmxTransient->fIsNestedGuest);
5614
5615 /*
5616 * For performance reasons, also check if the nested hypervisor's current VMCS
5617 * was newly loaded or modified before copying it to the shadow VMCS.
5618 */
5619 if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
5620 {
5621 int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
5622 AssertRCReturn(rc, rc);
5623 pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
5624 }
5625 hmR0VmxEnableVmcsShadowing(pVmcsInfo);
5626 }
5627 else
5628 hmR0VmxDisableVmcsShadowing(pVmcsInfo);
5629 }
5630#else
5631 NOREF(pVmxTransient);
5632#endif
5633 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
5634 }
5635 return VINF_SUCCESS;
5636}
5637
5638
5639/**
5640 * Exports the guest CR0 control register into the guest-state area in the VMCS.
5641 *
5642 * The guest FPU state is always pre-loaded hence we don't need to bother about
5643 * sharing FPU related CR0 bits between the guest and host.
5644 *
5645 * @returns VBox status code.
5646 * @param pVCpu The cross context virtual CPU structure.
5647 * @param pVmxTransient The VMX-transient structure.
5648 *
5649 * @remarks No-long-jump zone!!!
5650 */
5651static int hmR0VmxExportGuestCR0(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5652{
5653 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR0)
5654 {
5655 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5656 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5657
5658 uint64_t fSetCr0 = g_HmMsrs.u.vmx.u64Cr0Fixed0;
5659 uint64_t const fZapCr0 = g_HmMsrs.u.vmx.u64Cr0Fixed1;
5660 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
5661 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5662 else
5663 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
5664
5665 if (!pVmxTransient->fIsNestedGuest)
5666 {
5667 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5668 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5669 uint64_t const u64ShadowCr0 = u64GuestCr0;
5670 Assert(!RT_HI_U32(u64GuestCr0));
5671
5672 /*
5673 * Setup VT-x's view of the guest CR0.
5674 */
5675 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5676 if (pVM->hmr0.s.fNestedPaging)
5677 {
5678 if (CPUMIsGuestPagingEnabled(pVCpu))
5679 {
5680 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
5681 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
5682 | VMX_PROC_CTLS_CR3_STORE_EXIT);
5683 }
5684 else
5685 {
5686 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
5687 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
5688 | VMX_PROC_CTLS_CR3_STORE_EXIT;
5689 }
5690
5691 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
5692 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
5693 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
5694 }
5695 else
5696 {
5697 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
5698 u64GuestCr0 |= X86_CR0_WP;
5699 }
5700
5701 /*
5702 * Guest FPU bits.
5703 *
5704 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
5705 * using CR0.TS.
5706 *
5707 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
5708 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
5709 */
5710 u64GuestCr0 |= X86_CR0_NE;
5711
5712 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
5713 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
5714
5715 /*
5716 * Update exception intercepts.
5717 */
5718 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
5719 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
5720 {
5721 Assert(PDMVmmDevHeapIsEnabled(pVM));
5722 Assert(pVM->hm.s.vmx.pRealModeTSS);
5723 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
5724 }
5725 else
5726 {
5727 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
5728 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
5729 if (fInterceptMF)
5730 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
5731 }
5732
5733 /* Additional intercepts for debugging, define these yourself explicitly. */
5734#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
5735 uXcptBitmap |= 0
5736 | RT_BIT(X86_XCPT_BP)
5737 | RT_BIT(X86_XCPT_DE)
5738 | RT_BIT(X86_XCPT_NM)
5739 | RT_BIT(X86_XCPT_TS)
5740 | RT_BIT(X86_XCPT_UD)
5741 | RT_BIT(X86_XCPT_NP)
5742 | RT_BIT(X86_XCPT_SS)
5743 | RT_BIT(X86_XCPT_GP)
5744 | RT_BIT(X86_XCPT_PF)
5745 | RT_BIT(X86_XCPT_MF)
5746 ;
5747#elif defined(HMVMX_ALWAYS_TRAP_PF)
5748 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
5749#endif
5750 if (pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv)
5751 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
5752 Assert(pVM->hmr0.s.fNestedPaging || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
5753
5754 /* Apply the hardware specified CR0 fixed bits and enable caching. */
5755 u64GuestCr0 |= fSetCr0;
5756 u64GuestCr0 &= fZapCr0;
5757 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5758
5759 /* Commit the CR0 and related fields to the guest VMCS. */
5760 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5761 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5762 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5763 {
5764 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5765 AssertRC(rc);
5766 }
5767 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
5768 {
5769 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
5770 AssertRC(rc);
5771 }
5772
5773 /* Update our caches. */
5774 pVmcsInfo->u32ProcCtls = uProcCtls;
5775 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
5776
5777 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5778 }
5779 else
5780 {
5781 /*
5782 * With nested-guests, we may have extended the guest/host mask here since we
5783 * merged in the outer guest's mask. Thus, the merged mask can include more bits
5784 * (to read from the nested-guest CR0 read-shadow) than the nested hypervisor
5785 * originally supplied. We must copy those bits from the nested-guest CR0 into
5786 * the nested-guest CR0 read-shadow.
5787 */
5788 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5789 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5790 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(&pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
5791 Assert(!RT_HI_U32(u64GuestCr0));
5792 Assert(u64GuestCr0 & X86_CR0_NE);
5793
5794 /* Apply the hardware specified CR0 fixed bits and enable caching. */
5795 u64GuestCr0 |= fSetCr0;
5796 u64GuestCr0 &= fZapCr0;
5797 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5798
5799 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
5800 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5801 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5802
5803 Log4Func(("cr0=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5804 }
5805
5806 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR0);
5807 }
5808
5809 return VINF_SUCCESS;
5810}
5811
5812
5813/**
5814 * Exports the guest control registers (CR3, CR4) into the guest-state area
5815 * in the VMCS.
5816 *
5817 * @returns VBox strict status code.
5818 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
5819 * without unrestricted guest access and the VMMDev is not presently
5820 * mapped (e.g. EFI32).
5821 *
5822 * @param pVCpu The cross context virtual CPU structure.
5823 * @param pVmxTransient The VMX-transient structure.
5824 *
5825 * @remarks No-long-jump zone!!!
5826 */
5827static VBOXSTRICTRC hmR0VmxExportGuestCR3AndCR4(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5828{
5829 int rc = VINF_SUCCESS;
5830 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5831
5832 /*
5833 * Guest CR2.
5834 * It's always loaded in the assembler code. Nothing to do here.
5835 */
5836
5837 /*
5838 * Guest CR3.
5839 */
5840 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR3)
5841 {
5842 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5843
5844 if (pVM->hmr0.s.fNestedPaging)
5845 {
5846 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5847 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
5848
5849 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
5850 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
5851 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
5852 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
5853
5854 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
5855 pVmcsInfo->HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
5856 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
5857
5858 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
5859 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
5860 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
5861 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
5862 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
5863 || (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
5864 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
5865
5866 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
5867 AssertRC(rc);
5868
5869 uint64_t u64GuestCr3;
5870 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5871 if ( pVM->hmr0.s.vmx.fUnrestrictedGuest
5872 || CPUMIsGuestPagingEnabledEx(pCtx))
5873 {
5874 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
5875 if (CPUMIsGuestInPAEModeEx(pCtx))
5876 {
5877 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5878 AssertRC(rc);
5879 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
5880 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
5881 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
5882 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
5883 }
5884
5885 /*
5886 * The guest's view of its CR3 is unblemished with nested paging when the
5887 * guest is using paging or we have unrestricted guest execution to handle
5888 * the guest when it's not using paging.
5889 */
5890 u64GuestCr3 = pCtx->cr3;
5891 }
5892 else
5893 {
5894 /*
5895 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
5896 * thinks it accesses physical memory directly, we use our identity-mapped
5897 * page table to map guest-linear to guest-physical addresses. EPT takes care
5898 * of translating it to host-physical addresses.
5899 */
5900 RTGCPHYS GCPhys;
5901 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
5902
5903 /* We obtain it here every time as the guest could have relocated this PCI region. */
5904 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
5905 if (RT_SUCCESS(rc))
5906 { /* likely */ }
5907 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
5908 {
5909 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
5910 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
5911 }
5912 else
5913 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
5914
5915 u64GuestCr3 = GCPhys;
5916 }
5917
5918 Log4Func(("guest_cr3=%#RX64 (GstN)\n", u64GuestCr3));
5919 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, u64GuestCr3);
5920 AssertRC(rc);
5921 }
5922 else
5923 {
5924 Assert(!pVmxTransient->fIsNestedGuest);
5925 /* Non-nested paging case, just use the hypervisor's CR3. */
5926 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
5927
5928 Log4Func(("guest_cr3=%#RX64 (HstN)\n", HCPhysGuestCr3));
5929 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
5930 AssertRC(rc);
5931 }
5932
5933 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR3);
5934 }
5935
5936 /*
5937 * Guest CR4.
5938 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
5939 */
5940 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR4)
5941 {
5942 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5943 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5944
5945 uint64_t const fSetCr4 = g_HmMsrs.u.vmx.u64Cr4Fixed0;
5946 uint64_t const fZapCr4 = g_HmMsrs.u.vmx.u64Cr4Fixed1;
5947
5948 /*
5949 * With nested-guests, we may have extended the guest/host mask here (since we
5950 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
5951 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
5952 * the nested hypervisor originally supplied. Thus, we should, in essence, copy
5953 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
5954 */
5955 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5956 uint64_t u64GuestCr4 = pCtx->cr4;
5957 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
5958 ? pCtx->cr4
5959 : CPUMGetGuestVmxMaskedCr4(pCtx, pVmcsInfo->u64Cr4Mask);
5960 Assert(!RT_HI_U32(u64GuestCr4));
5961
5962 /*
5963 * Setup VT-x's view of the guest CR4.
5964 *
5965 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
5966 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
5967 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
5968 *
5969 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
5970 */
5971 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
5972 {
5973 Assert(pVM->hm.s.vmx.pRealModeTSS);
5974 Assert(PDMVmmDevHeapIsEnabled(pVM));
5975 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
5976 }
5977
5978 if (pVM->hmr0.s.fNestedPaging)
5979 {
5980 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
5981 && !pVM->hmr0.s.vmx.fUnrestrictedGuest)
5982 {
5983 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
5984 u64GuestCr4 |= X86_CR4_PSE;
5985 /* Our identity mapping is a 32-bit page directory. */
5986 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5987 }
5988 /* else use guest CR4.*/
5989 }
5990 else
5991 {
5992 Assert(!pVmxTransient->fIsNestedGuest);
5993
5994 /*
5995 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
5996 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
5997 */
5998 switch (pVCpu->hm.s.enmShadowMode)
5999 {
6000 case PGMMODE_REAL: /* Real-mode. */
6001 case PGMMODE_PROTECTED: /* Protected mode without paging. */
6002 case PGMMODE_32_BIT: /* 32-bit paging. */
6003 {
6004 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
6005 break;
6006 }
6007
6008 case PGMMODE_PAE: /* PAE paging. */
6009 case PGMMODE_PAE_NX: /* PAE paging with NX. */
6010 {
6011 u64GuestCr4 |= X86_CR4_PAE;
6012 break;
6013 }
6014
6015 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
6016 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
6017 {
6018#ifdef VBOX_WITH_64_BITS_GUESTS
6019 /* For our assumption in hmR0VmxShouldSwapEferMsr. */
6020 Assert(u64GuestCr4 & X86_CR4_PAE);
6021 break;
6022#endif
6023 }
6024 default:
6025 AssertFailed();
6026 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
6027 }
6028 }
6029
6030 /* Apply the hardware specified CR4 fixed bits (mainly CR4.VMXE). */
6031 u64GuestCr4 |= fSetCr4;
6032 u64GuestCr4 &= fZapCr4;
6033
6034 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
6035 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
6036 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
6037
6038 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
6039 bool const fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
6040 if (fLoadSaveGuestXcr0 != pVCpu->hmr0.s.fLoadSaveGuestXcr0)
6041 {
6042 pVCpu->hmr0.s.fLoadSaveGuestXcr0 = fLoadSaveGuestXcr0;
6043 hmR0VmxUpdateStartVmFunction(pVCpu);
6044 }
6045
6046 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR4);
6047
6048 Log4Func(("cr4=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
6049 }
6050 return rc;
6051}
6052
6053
6054/**
6055 * Exports the guest debug registers into the guest-state area in the VMCS.
6056 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
6057 *
6058 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
6059 *
6060 * @returns VBox status code.
6061 * @param pVCpu The cross context virtual CPU structure.
6062 * @param pVmxTransient The VMX-transient structure.
6063 *
6064 * @remarks No-long-jump zone!!!
6065 */
6066static int hmR0VmxExportSharedDebugState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6067{
6068 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
6069
6070 /** @todo NSTVMX: Figure out what we want to do with nested-guest instruction
6071 * stepping. */
6072 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6073 if (pVmxTransient->fIsNestedGuest)
6074 {
6075 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, CPUMGetGuestDR7(pVCpu));
6076 AssertRC(rc);
6077
6078 /* Always intercept Mov DRx accesses for the nested-guest for now. */
6079 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
6080 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
6081 AssertRC(rc);
6082 return VINF_SUCCESS;
6083 }
6084
6085#ifdef VBOX_STRICT
6086 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
6087 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
6088 {
6089 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
6090 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
6091 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
6092 }
6093#endif
6094
6095 bool fSteppingDB = false;
6096 bool fInterceptMovDRx = false;
6097 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
6098 if (pVCpu->hm.s.fSingleInstruction)
6099 {
6100 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
6101 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
6102 {
6103 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
6104 Assert(fSteppingDB == false);
6105 }
6106 else
6107 {
6108 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
6109 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
6110 pVCpu->hmr0.s.fClearTrapFlag = true;
6111 fSteppingDB = true;
6112 }
6113 }
6114
6115 uint64_t u64GuestDr7;
6116 if ( fSteppingDB
6117 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
6118 {
6119 /*
6120 * Use the combined guest and host DRx values found in the hypervisor register set
6121 * because the hypervisor debugger has breakpoints active or someone is single stepping
6122 * on the host side without a monitor trap flag.
6123 *
6124 * Note! DBGF expects a clean DR6 state before executing guest code.
6125 */
6126 if (!CPUMIsHyperDebugStateActive(pVCpu))
6127 {
6128 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
6129 Assert(CPUMIsHyperDebugStateActive(pVCpu));
6130 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
6131 }
6132
6133 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
6134 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
6135 pVCpu->hmr0.s.fUsingHyperDR7 = true;
6136 fInterceptMovDRx = true;
6137 }
6138 else
6139 {
6140 /*
6141 * If the guest has enabled debug registers, we need to load them prior to
6142 * executing guest code so they'll trigger at the right time.
6143 */
6144 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
6145 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
6146 {
6147 if (!CPUMIsGuestDebugStateActive(pVCpu))
6148 {
6149 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
6150 Assert(CPUMIsGuestDebugStateActive(pVCpu));
6151 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
6152 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
6153 }
6154 Assert(!fInterceptMovDRx);
6155 }
6156 else if (!CPUMIsGuestDebugStateActive(pVCpu))
6157 {
6158 /*
6159 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
6160 * must intercept #DB in order to maintain a correct DR6 guest value, and
6161 * because we need to intercept it to prevent nested #DBs from hanging the
6162 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
6163 */
6164 fInterceptMovDRx = true;
6165 }
6166
6167 /* Update DR7 with the actual guest value. */
6168 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
6169 pVCpu->hmr0.s.fUsingHyperDR7 = false;
6170 }
6171
6172 if (fInterceptMovDRx)
6173 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
6174 else
6175 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
6176
6177 /*
6178 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
6179 * monitor-trap flag and update our cache.
6180 */
6181 if (uProcCtls != pVmcsInfo->u32ProcCtls)
6182 {
6183 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
6184 AssertRC(rc);
6185 pVmcsInfo->u32ProcCtls = uProcCtls;
6186 }
6187
6188 /*
6189 * Update guest DR7.
6190 */
6191 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, u64GuestDr7);
6192 AssertRC(rc);
6193
6194 /*
6195 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
6196 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
6197 *
6198 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
6199 */
6200 if (fSteppingDB)
6201 {
6202 Assert(pVCpu->hm.s.fSingleInstruction);
6203 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
6204
6205 uint32_t fIntrState = 0;
6206 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
6207 AssertRC(rc);
6208
6209 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
6210 {
6211 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
6212 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
6213 AssertRC(rc);
6214 }
6215 }
6216
6217 return VINF_SUCCESS;
6218}
6219
6220
6221#ifdef VBOX_STRICT
6222/**
6223 * Strict function to validate segment registers.
6224 *
6225 * @param pVCpu The cross context virtual CPU structure.
6226 * @param pVmcsInfo The VMCS info. object.
6227 *
6228 * @remarks Will import guest CR0 on strict builds during validation of
6229 * segments.
6230 */
6231static void hmR0VmxValidateSegmentRegs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
6232{
6233 /*
6234 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
6235 *
6236 * The reason we check for attribute value 0 in this function and not just the unusable bit is
6237 * because hmR0VmxExportGuestSegReg() only updates the VMCS' copy of the value with the
6238 * unusable bit and doesn't change the guest-context value.
6239 */
6240 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6241 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6242 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
6243 if ( !pVM->hmr0.s.vmx.fUnrestrictedGuest
6244 && ( !CPUMIsGuestInRealModeEx(pCtx)
6245 && !CPUMIsGuestInV86ModeEx(pCtx)))
6246 {
6247 /* Protected mode checks */
6248 /* CS */
6249 Assert(pCtx->cs.Attr.n.u1Present);
6250 Assert(!(pCtx->cs.Attr.u & 0xf00));
6251 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
6252 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
6253 || !(pCtx->cs.Attr.n.u1Granularity));
6254 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
6255 || (pCtx->cs.Attr.n.u1Granularity));
6256 /* CS cannot be loaded with NULL in protected mode. */
6257 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
6258 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
6259 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
6260 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
6261 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
6262 else
6263 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
6264 /* SS */
6265 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
6266 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
6267 if ( !(pCtx->cr0 & X86_CR0_PE)
6268 || pCtx->cs.Attr.n.u4Type == 3)
6269 {
6270 Assert(!pCtx->ss.Attr.n.u2Dpl);
6271 }
6272 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
6273 {
6274 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
6275 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
6276 Assert(pCtx->ss.Attr.n.u1Present);
6277 Assert(!(pCtx->ss.Attr.u & 0xf00));
6278 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
6279 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
6280 || !(pCtx->ss.Attr.n.u1Granularity));
6281 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
6282 || (pCtx->ss.Attr.n.u1Granularity));
6283 }
6284 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSegReg(). */
6285 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
6286 {
6287 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6288 Assert(pCtx->ds.Attr.n.u1Present);
6289 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
6290 Assert(!(pCtx->ds.Attr.u & 0xf00));
6291 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
6292 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
6293 || !(pCtx->ds.Attr.n.u1Granularity));
6294 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
6295 || (pCtx->ds.Attr.n.u1Granularity));
6296 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6297 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
6298 }
6299 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
6300 {
6301 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6302 Assert(pCtx->es.Attr.n.u1Present);
6303 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
6304 Assert(!(pCtx->es.Attr.u & 0xf00));
6305 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
6306 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
6307 || !(pCtx->es.Attr.n.u1Granularity));
6308 Assert( !(pCtx->es.u32Limit & 0xfff00000)
6309 || (pCtx->es.Attr.n.u1Granularity));
6310 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6311 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
6312 }
6313 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
6314 {
6315 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6316 Assert(pCtx->fs.Attr.n.u1Present);
6317 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
6318 Assert(!(pCtx->fs.Attr.u & 0xf00));
6319 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
6320 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
6321 || !(pCtx->fs.Attr.n.u1Granularity));
6322 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
6323 || (pCtx->fs.Attr.n.u1Granularity));
6324 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6325 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
6326 }
6327 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
6328 {
6329 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6330 Assert(pCtx->gs.Attr.n.u1Present);
6331 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
6332 Assert(!(pCtx->gs.Attr.u & 0xf00));
6333 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
6334 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
6335 || !(pCtx->gs.Attr.n.u1Granularity));
6336 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
6337 || (pCtx->gs.Attr.n.u1Granularity));
6338 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6339 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
6340 }
6341 /* 64-bit capable CPUs. */
6342 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6343 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
6344 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
6345 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
6346 }
6347 else if ( CPUMIsGuestInV86ModeEx(pCtx)
6348 || ( CPUMIsGuestInRealModeEx(pCtx)
6349 && !pVM->hmr0.s.vmx.fUnrestrictedGuest))
6350 {
6351 /* Real and v86 mode checks. */
6352 /* hmR0VmxExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
6353 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
6354 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
6355 {
6356 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
6357 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
6358 }
6359 else
6360 {
6361 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
6362 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
6363 }
6364
6365 /* CS */
6366 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
6367 Assert(pCtx->cs.u32Limit == 0xffff);
6368 Assert(u32CSAttr == 0xf3);
6369 /* SS */
6370 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
6371 Assert(pCtx->ss.u32Limit == 0xffff);
6372 Assert(u32SSAttr == 0xf3);
6373 /* DS */
6374 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
6375 Assert(pCtx->ds.u32Limit == 0xffff);
6376 Assert(u32DSAttr == 0xf3);
6377 /* ES */
6378 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
6379 Assert(pCtx->es.u32Limit == 0xffff);
6380 Assert(u32ESAttr == 0xf3);
6381 /* FS */
6382 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
6383 Assert(pCtx->fs.u32Limit == 0xffff);
6384 Assert(u32FSAttr == 0xf3);
6385 /* GS */
6386 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
6387 Assert(pCtx->gs.u32Limit == 0xffff);
6388 Assert(u32GSAttr == 0xf3);
6389 /* 64-bit capable CPUs. */
6390 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6391 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
6392 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
6393 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
6394 }
6395}
6396#endif /* VBOX_STRICT */
6397
6398
6399/**
6400 * Exports a guest segment register into the guest-state area in the VMCS.
6401 *
6402 * @returns VBox status code.
6403 * @param pVCpu The cross context virtual CPU structure.
6404 * @param pVmcsInfo The VMCS info. object.
6405 * @param iSegReg The segment register number (X86_SREG_XXX).
6406 * @param pSelReg Pointer to the segment selector.
6407 *
6408 * @remarks No-long-jump zone!!!
6409 */
6410static int hmR0VmxExportGuestSegReg(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, uint32_t iSegReg, PCCPUMSELREG pSelReg)
6411{
6412 Assert(iSegReg < X86_SREG_COUNT);
6413
6414 uint32_t u32Access = pSelReg->Attr.u;
6415 if (!pVmcsInfo->pShared->RealMode.fRealOnV86Active)
6416 {
6417 /*
6418 * The way to differentiate between whether this is really a null selector or was just
6419 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
6420 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
6421 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
6422 * NULL selectors loaded in protected-mode have their attribute as 0.
6423 */
6424 if (u32Access)
6425 { }
6426 else
6427 u32Access = X86DESCATTR_UNUSABLE;
6428 }
6429 else
6430 {
6431 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
6432 u32Access = 0xf3;
6433 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6434 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
6435 RT_NOREF_PV(pVCpu);
6436 }
6437
6438 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
6439 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
6440 ("Access bit not set for usable segment. %.2s sel=%#x attr %#x\n", "ESCSSSDSFSGS" + iSegReg * 2, pSelReg, pSelReg->Attr.u));
6441
6442 /*
6443 * Commit it to the VMCS.
6444 */
6445 Assert((uint32_t)VMX_VMCS16_GUEST_SEG_SEL(iSegReg) == g_aVmcsSegSel[iSegReg]);
6446 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg) == g_aVmcsSegLimit[iSegReg]);
6447 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg) == g_aVmcsSegAttr[iSegReg]);
6448 Assert((uint32_t)VMX_VMCS_GUEST_SEG_BASE(iSegReg) == g_aVmcsSegBase[iSegReg]);
6449 int rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_SEG_SEL(iSegReg), pSelReg->Sel); AssertRC(rc);
6450 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg), pSelReg->u32Limit); AssertRC(rc);
6451 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SEG_BASE(iSegReg), pSelReg->u64Base); AssertRC(rc);
6452 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg), u32Access); AssertRC(rc);
6453 return VINF_SUCCESS;
6454}
6455
6456
6457/**
6458 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
6459 * area in the VMCS.
6460 *
6461 * @returns VBox status code.
6462 * @param pVCpu The cross context virtual CPU structure.
6463 * @param pVmxTransient The VMX-transient structure.
6464 *
6465 * @remarks Will import guest CR0 on strict builds during validation of
6466 * segments.
6467 * @remarks No-long-jump zone!!!
6468 */
6469static int hmR0VmxExportGuestSegRegsXdtr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6470{
6471 int rc = VERR_INTERNAL_ERROR_5;
6472 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6473 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6474 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6475 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
6476
6477 /*
6478 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
6479 */
6480 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
6481 {
6482 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CS)
6483 {
6484 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
6485 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6486 pVmcsInfoShared->RealMode.AttrCS.u = pCtx->cs.Attr.u;
6487 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
6488 AssertRC(rc);
6489 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CS);
6490 }
6491
6492 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SS)
6493 {
6494 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
6495 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6496 pVmcsInfoShared->RealMode.AttrSS.u = pCtx->ss.Attr.u;
6497 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
6498 AssertRC(rc);
6499 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SS);
6500 }
6501
6502 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_DS)
6503 {
6504 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
6505 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6506 pVmcsInfoShared->RealMode.AttrDS.u = pCtx->ds.Attr.u;
6507 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
6508 AssertRC(rc);
6509 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_DS);
6510 }
6511
6512 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_ES)
6513 {
6514 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
6515 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6516 pVmcsInfoShared->RealMode.AttrES.u = pCtx->es.Attr.u;
6517 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
6518 AssertRC(rc);
6519 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_ES);
6520 }
6521
6522 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_FS)
6523 {
6524 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
6525 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6526 pVmcsInfoShared->RealMode.AttrFS.u = pCtx->fs.Attr.u;
6527 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
6528 AssertRC(rc);
6529 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_FS);
6530 }
6531
6532 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GS)
6533 {
6534 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
6535 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6536 pVmcsInfoShared->RealMode.AttrGS.u = pCtx->gs.Attr.u;
6537 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
6538 AssertRC(rc);
6539 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GS);
6540 }
6541
6542#ifdef VBOX_STRICT
6543 hmR0VmxValidateSegmentRegs(pVCpu, pVmcsInfo);
6544#endif
6545 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
6546 pCtx->cs.Attr.u));
6547 }
6548
6549 /*
6550 * Guest TR.
6551 */
6552 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_TR)
6553 {
6554 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
6555
6556 /*
6557 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
6558 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
6559 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
6560 */
6561 uint16_t u16Sel;
6562 uint32_t u32Limit;
6563 uint64_t u64Base;
6564 uint32_t u32AccessRights;
6565 if (!pVmcsInfoShared->RealMode.fRealOnV86Active)
6566 {
6567 u16Sel = pCtx->tr.Sel;
6568 u32Limit = pCtx->tr.u32Limit;
6569 u64Base = pCtx->tr.u64Base;
6570 u32AccessRights = pCtx->tr.Attr.u;
6571 }
6572 else
6573 {
6574 Assert(!pVmxTransient->fIsNestedGuest);
6575 Assert(pVM->hm.s.vmx.pRealModeTSS);
6576 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
6577
6578 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
6579 RTGCPHYS GCPhys;
6580 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
6581 AssertRCReturn(rc, rc);
6582
6583 X86DESCATTR DescAttr;
6584 DescAttr.u = 0;
6585 DescAttr.n.u1Present = 1;
6586 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
6587
6588 u16Sel = 0;
6589 u32Limit = HM_VTX_TSS_SIZE;
6590 u64Base = GCPhys;
6591 u32AccessRights = DescAttr.u;
6592 }
6593
6594 /* Validate. */
6595 Assert(!(u16Sel & RT_BIT(2)));
6596 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
6597 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
6598 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
6599 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
6600 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
6601 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
6602 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
6603 Assert( (u32Limit & 0xfff) == 0xfff
6604 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
6605 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
6606 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
6607
6608 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
6609 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
6610 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
6611 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
6612
6613 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_TR);
6614 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
6615 }
6616
6617 /*
6618 * Guest GDTR.
6619 */
6620 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GDTR)
6621 {
6622 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
6623
6624 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
6625 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
6626
6627 /* Validate. */
6628 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6629
6630 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
6631 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
6632 }
6633
6634 /*
6635 * Guest LDTR.
6636 */
6637 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_LDTR)
6638 {
6639 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
6640
6641 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
6642 uint32_t u32Access;
6643 if ( !pVmxTransient->fIsNestedGuest
6644 && !pCtx->ldtr.Attr.u)
6645 u32Access = X86DESCATTR_UNUSABLE;
6646 else
6647 u32Access = pCtx->ldtr.Attr.u;
6648
6649 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
6650 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
6651 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
6652 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
6653
6654 /* Validate. */
6655 if (!(u32Access & X86DESCATTR_UNUSABLE))
6656 {
6657 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
6658 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
6659 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
6660 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
6661 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
6662 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
6663 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
6664 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
6665 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
6666 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
6667 }
6668
6669 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
6670 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
6671 }
6672
6673 /*
6674 * Guest IDTR.
6675 */
6676 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_IDTR)
6677 {
6678 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
6679
6680 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
6681 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
6682
6683 /* Validate. */
6684 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6685
6686 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
6687 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
6688 }
6689
6690 return VINF_SUCCESS;
6691}
6692
6693
6694/**
6695 * Exports certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
6696 * areas.
6697 *
6698 * These MSRs will automatically be loaded to the host CPU on every successful
6699 * VM-entry and stored from the host CPU on every successful VM-exit.
6700 *
6701 * We creates/updates MSR slots for the host MSRs in the VM-exit MSR-load area. The
6702 * actual host MSR values are not- updated here for performance reasons. See
6703 * hmR0VmxExportHostMsrs().
6704 *
6705 * We also exports the guest sysenter MSRs into the guest-state area in the VMCS.
6706 *
6707 * @returns VBox status code.
6708 * @param pVCpu The cross context virtual CPU structure.
6709 * @param pVmxTransient The VMX-transient structure.
6710 *
6711 * @remarks No-long-jump zone!!!
6712 */
6713static int hmR0VmxExportGuestMsrs(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6714{
6715 AssertPtr(pVCpu);
6716 AssertPtr(pVmxTransient);
6717
6718 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6719 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6720
6721 /*
6722 * MSRs that we use the auto-load/store MSR area in the VMCS.
6723 * For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(),
6724 * nothing to do here. The host MSR values are updated when it's safe in
6725 * hmR0VmxLazySaveHostMsrs().
6726 *
6727 * For nested-guests, the guests MSRs from the VM-entry MSR-load area are already
6728 * loaded (into the guest-CPU context) by the VMLAUNCH/VMRESUME instruction
6729 * emulation. The merged MSR permission bitmap will ensure that we get VM-exits
6730 * for any MSR that are not part of the lazy MSRs so we do not need to place
6731 * those MSRs into the auto-load/store MSR area. Nothing to do here.
6732 */
6733 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
6734 {
6735 /* No auto-load/store MSRs currently. */
6736 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_GUEST_AUTO_MSRS);
6737 }
6738
6739 /*
6740 * Guest Sysenter MSRs.
6741 */
6742 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_MSR_MASK)
6743 {
6744 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
6745
6746 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
6747 {
6748 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
6749 AssertRC(rc);
6750 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_CS_MSR);
6751 }
6752
6753 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
6754 {
6755 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
6756 AssertRC(rc);
6757 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
6758 }
6759
6760 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
6761 {
6762 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
6763 AssertRC(rc);
6764 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
6765 }
6766 }
6767
6768 /*
6769 * Guest/host EFER MSR.
6770 */
6771 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_EFER_MSR)
6772 {
6773 /* Whether we are using the VMCS to swap the EFER MSR must have been
6774 determined earlier while exporting VM-entry/VM-exit controls. */
6775 Assert(!(ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS));
6776 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6777
6778 if (hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
6779 {
6780 /*
6781 * EFER.LME is written by software, while EFER.LMA is set by the CPU to (CR0.PG & EFER.LME).
6782 * This means a guest can set EFER.LME=1 while CR0.PG=0 and EFER.LMA can remain 0.
6783 * VT-x requires that "IA-32e mode guest" VM-entry control must be identical to EFER.LMA
6784 * and to CR0.PG. Without unrestricted execution, CR0.PG (used for VT-x, not the shadow)
6785 * must always be 1. This forces us to effectively clear both EFER.LMA and EFER.LME until
6786 * the guest has also set CR0.PG=1. Otherwise, we would run into an invalid-guest state
6787 * during VM-entry.
6788 */
6789 uint64_t uGuestEferMsr = pCtx->msrEFER;
6790 if (!pVM->hmr0.s.vmx.fUnrestrictedGuest)
6791 {
6792 if (!(pCtx->msrEFER & MSR_K6_EFER_LMA))
6793 uGuestEferMsr &= ~MSR_K6_EFER_LME;
6794 else
6795 Assert((pCtx->msrEFER & (MSR_K6_EFER_LMA | MSR_K6_EFER_LME)) == (MSR_K6_EFER_LMA | MSR_K6_EFER_LME));
6796 }
6797
6798 /*
6799 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
6800 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
6801 */
6802 if (pVM->hm.s.vmx.fSupportsVmcsEfer)
6803 {
6804 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, uGuestEferMsr);
6805 AssertRC(rc);
6806 }
6807 else
6808 {
6809 /*
6810 * We shall use the auto-load/store MSR area only for loading the EFER MSR but we must
6811 * continue to intercept guest read and write accesses to it, see @bugref{7386#c16}.
6812 */
6813 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER, uGuestEferMsr,
6814 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6815 AssertRCReturn(rc, rc);
6816 }
6817
6818 Log4Func(("efer=%#RX64 shadow=%#RX64\n", uGuestEferMsr, pCtx->msrEFER));
6819 }
6820 else if (!pVM->hm.s.vmx.fSupportsVmcsEfer)
6821 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER);
6822
6823 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
6824 }
6825
6826 /*
6827 * Other MSRs.
6828 */
6829 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_OTHER_MSRS)
6830 {
6831 /* Speculation Control (R/W). */
6832 HMVMX_CPUMCTX_ASSERT(pVCpu, HM_CHANGED_GUEST_OTHER_MSRS);
6833 if (pVM->cpum.ro.GuestFeatures.fIbrs)
6834 {
6835 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_IA32_SPEC_CTRL, CPUMGetGuestSpecCtrl(pVCpu),
6836 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6837 AssertRCReturn(rc, rc);
6838 }
6839
6840 /* Last Branch Record. */
6841 if (pVM->hm.s.vmx.fLbr)
6842 {
6843 PVMXVMCSINFOSHARED const pVmcsInfoShared = pVmxTransient->pVmcsInfo->pShared;
6844 uint32_t const idFromIpMsrStart = pVM->hm.s.vmx.idLbrFromIpMsrFirst;
6845 uint32_t const idToIpMsrStart = pVM->hm.s.vmx.idLbrToIpMsrFirst;
6846 uint32_t const cLbrStack = pVM->hm.s.vmx.idLbrFromIpMsrLast - pVM->hm.s.vmx.idLbrFromIpMsrFirst + 1;
6847 Assert(cLbrStack <= 32);
6848 for (uint32_t i = 0; i < cLbrStack; i++)
6849 {
6850 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, idFromIpMsrStart + i,
6851 pVmcsInfoShared->au64LbrFromIpMsr[i],
6852 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6853 AssertRCReturn(rc, rc);
6854
6855 /* Some CPUs don't have a Branch-To-IP MSR (P4 and related Xeons). */
6856 if (idToIpMsrStart != 0)
6857 {
6858 rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, idToIpMsrStart + i,
6859 pVmcsInfoShared->au64LbrToIpMsr[i],
6860 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6861 AssertRCReturn(rc, rc);
6862 }
6863 }
6864
6865 /* Add LBR top-of-stack MSR (which contains the index to the most recent record). */
6866 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, pVM->hm.s.vmx.idLbrTosMsr,
6867 pVmcsInfoShared->u64LbrTosMsr, false /* fSetReadWrite */,
6868 false /* fUpdateHostMsr */);
6869 AssertRCReturn(rc, rc);
6870 }
6871
6872 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
6873 }
6874
6875 return VINF_SUCCESS;
6876}
6877
6878
6879/**
6880 * Wrapper for running the guest code in VT-x.
6881 *
6882 * @returns VBox status code, no informational status codes.
6883 * @param pVCpu The cross context virtual CPU structure.
6884 * @param pVmxTransient The VMX-transient structure.
6885 *
6886 * @remarks No-long-jump zone!!!
6887 */
6888DECLINLINE(int) hmR0VmxRunGuest(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6889{
6890 /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
6891 pVCpu->cpum.GstCtx.fExtrn |= HMVMX_CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_HM;
6892
6893 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6894 bool const fResumeVM = RT_BOOL(pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_LAUNCHED);
6895#ifdef VBOX_WITH_STATISTICS
6896 if (fResumeVM)
6897 STAM_COUNTER_INC(&pVCpu->hm.s.StatVmxVmResume);
6898 else
6899 STAM_COUNTER_INC(&pVCpu->hm.s.StatVmxVmLaunch);
6900#endif
6901 int rc = pVCpu->hmr0.s.vmx.pfnStartVm(pVmcsInfo, pVCpu, fResumeVM);
6902 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
6903 return rc;
6904}
6905
6906
6907/**
6908 * Reports world-switch error and dumps some useful debug info.
6909 *
6910 * @param pVCpu The cross context virtual CPU structure.
6911 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
6912 * @param pVmxTransient The VMX-transient structure (only
6913 * exitReason updated).
6914 */
6915static void hmR0VmxReportWorldSwitchError(PVMCPUCC pVCpu, int rcVMRun, PVMXTRANSIENT pVmxTransient)
6916{
6917 Assert(pVCpu);
6918 Assert(pVmxTransient);
6919 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
6920
6921 Log4Func(("VM-entry failure: %Rrc\n", rcVMRun));
6922 switch (rcVMRun)
6923 {
6924 case VERR_VMX_INVALID_VMXON_PTR:
6925 AssertFailed();
6926 break;
6927 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
6928 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
6929 {
6930 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
6931 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
6932 AssertRC(rc);
6933 hmR0VmxReadExitQualVmcs(pVmxTransient);
6934
6935 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hmr0.s.idEnteredCpu;
6936 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
6937 Cannot do it here as we may have been long preempted. */
6938
6939#ifdef VBOX_STRICT
6940 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6941 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
6942 pVmxTransient->uExitReason));
6943 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQual));
6944 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
6945 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
6946 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
6947 else
6948 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
6949 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
6950 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
6951
6952 static struct
6953 {
6954 /** Name of the field to log. */
6955 const char *pszName;
6956 /** The VMCS field. */
6957 uint32_t uVmcsField;
6958 /** Whether host support of this field needs to be checked. */
6959 bool fCheckSupport;
6960 } const s_aVmcsFields[] =
6961 {
6962 { "VMX_VMCS32_CTRL_PIN_EXEC", VMX_VMCS32_CTRL_PIN_EXEC, false },
6963 { "VMX_VMCS32_CTRL_PROC_EXEC", VMX_VMCS32_CTRL_PROC_EXEC, false },
6964 { "VMX_VMCS32_CTRL_PROC_EXEC2", VMX_VMCS32_CTRL_PROC_EXEC2, true },
6965 { "VMX_VMCS32_CTRL_ENTRY", VMX_VMCS32_CTRL_ENTRY, false },
6966 { "VMX_VMCS32_CTRL_EXIT", VMX_VMCS32_CTRL_EXIT, false },
6967 { "VMX_VMCS32_CTRL_CR3_TARGET_COUNT", VMX_VMCS32_CTRL_CR3_TARGET_COUNT, false },
6968 { "VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO", VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, false },
6969 { "VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE", VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, false },
6970 { "VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH", VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, false },
6971 { "VMX_VMCS32_CTRL_TPR_THRESHOLD", VMX_VMCS32_CTRL_TPR_THRESHOLD, false },
6972 { "VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, false },
6973 { "VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, false },
6974 { "VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, false },
6975 { "VMX_VMCS32_CTRL_EXCEPTION_BITMAP", VMX_VMCS32_CTRL_EXCEPTION_BITMAP, false },
6976 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, false },
6977 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, false },
6978 { "VMX_VMCS_CTRL_CR0_MASK", VMX_VMCS_CTRL_CR0_MASK, false },
6979 { "VMX_VMCS_CTRL_CR0_READ_SHADOW", VMX_VMCS_CTRL_CR0_READ_SHADOW, false },
6980 { "VMX_VMCS_CTRL_CR4_MASK", VMX_VMCS_CTRL_CR4_MASK, false },
6981 { "VMX_VMCS_CTRL_CR4_READ_SHADOW", VMX_VMCS_CTRL_CR4_READ_SHADOW, false },
6982 { "VMX_VMCS64_CTRL_EPTP_FULL", VMX_VMCS64_CTRL_EPTP_FULL, true },
6983 { "VMX_VMCS_GUEST_RIP", VMX_VMCS_GUEST_RIP, false },
6984 { "VMX_VMCS_GUEST_RSP", VMX_VMCS_GUEST_RSP, false },
6985 { "VMX_VMCS_GUEST_RFLAGS", VMX_VMCS_GUEST_RFLAGS, false },
6986 { "VMX_VMCS16_VPID", VMX_VMCS16_VPID, true, },
6987 { "VMX_VMCS_HOST_CR0", VMX_VMCS_HOST_CR0, false },
6988 { "VMX_VMCS_HOST_CR3", VMX_VMCS_HOST_CR3, false },
6989 { "VMX_VMCS_HOST_CR4", VMX_VMCS_HOST_CR4, false },
6990 /* The order of selector fields below are fixed! */
6991 { "VMX_VMCS16_HOST_ES_SEL", VMX_VMCS16_HOST_ES_SEL, false },
6992 { "VMX_VMCS16_HOST_CS_SEL", VMX_VMCS16_HOST_CS_SEL, false },
6993 { "VMX_VMCS16_HOST_SS_SEL", VMX_VMCS16_HOST_SS_SEL, false },
6994 { "VMX_VMCS16_HOST_DS_SEL", VMX_VMCS16_HOST_DS_SEL, false },
6995 { "VMX_VMCS16_HOST_FS_SEL", VMX_VMCS16_HOST_FS_SEL, false },
6996 { "VMX_VMCS16_HOST_GS_SEL", VMX_VMCS16_HOST_GS_SEL, false },
6997 { "VMX_VMCS16_HOST_TR_SEL", VMX_VMCS16_HOST_TR_SEL, false },
6998 /* End of ordered selector fields. */
6999 { "VMX_VMCS_HOST_TR_BASE", VMX_VMCS_HOST_TR_BASE, false },
7000 { "VMX_VMCS_HOST_GDTR_BASE", VMX_VMCS_HOST_GDTR_BASE, false },
7001 { "VMX_VMCS_HOST_IDTR_BASE", VMX_VMCS_HOST_IDTR_BASE, false },
7002 { "VMX_VMCS32_HOST_SYSENTER_CS", VMX_VMCS32_HOST_SYSENTER_CS, false },
7003 { "VMX_VMCS_HOST_SYSENTER_EIP", VMX_VMCS_HOST_SYSENTER_EIP, false },
7004 { "VMX_VMCS_HOST_SYSENTER_ESP", VMX_VMCS_HOST_SYSENTER_ESP, false },
7005 { "VMX_VMCS_HOST_RSP", VMX_VMCS_HOST_RSP, false },
7006 { "VMX_VMCS_HOST_RIP", VMX_VMCS_HOST_RIP, false }
7007 };
7008
7009 RTGDTR HostGdtr;
7010 ASMGetGDTR(&HostGdtr);
7011
7012 uint32_t const cVmcsFields = RT_ELEMENTS(s_aVmcsFields);
7013 for (uint32_t i = 0; i < cVmcsFields; i++)
7014 {
7015 uint32_t const uVmcsField = s_aVmcsFields[i].uVmcsField;
7016
7017 bool fSupported;
7018 if (!s_aVmcsFields[i].fCheckSupport)
7019 fSupported = true;
7020 else
7021 {
7022 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7023 switch (uVmcsField)
7024 {
7025 case VMX_VMCS64_CTRL_EPTP_FULL: fSupported = pVM->hmr0.s.fNestedPaging; break;
7026 case VMX_VMCS16_VPID: fSupported = pVM->hmr0.s.vmx.fVpid; break;
7027 case VMX_VMCS32_CTRL_PROC_EXEC2:
7028 fSupported = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
7029 break;
7030 default:
7031 AssertMsgFailedReturnVoid(("Failed to provide VMCS field support for %#RX32\n", uVmcsField));
7032 }
7033 }
7034
7035 if (fSupported)
7036 {
7037 uint8_t const uWidth = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH);
7038 switch (uWidth)
7039 {
7040 case VMX_VMCSFIELD_WIDTH_16BIT:
7041 {
7042 uint16_t u16Val;
7043 rc = VMXReadVmcs16(uVmcsField, &u16Val);
7044 AssertRC(rc);
7045 Log4(("%-40s = %#RX16\n", s_aVmcsFields[i].pszName, u16Val));
7046
7047 if ( uVmcsField >= VMX_VMCS16_HOST_ES_SEL
7048 && uVmcsField <= VMX_VMCS16_HOST_TR_SEL)
7049 {
7050 if (u16Val < HostGdtr.cbGdt)
7051 {
7052 /* Order of selectors in s_apszSel is fixed and matches the order in s_aVmcsFields. */
7053 static const char * const s_apszSel[] = { "Host ES", "Host CS", "Host SS", "Host DS",
7054 "Host FS", "Host GS", "Host TR" };
7055 uint8_t const idxSel = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_INDEX);
7056 Assert(idxSel < RT_ELEMENTS(s_apszSel));
7057 PCX86DESCHC pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u16Val & X86_SEL_MASK));
7058 hmR0DumpDescriptor(pDesc, u16Val, s_apszSel[idxSel]);
7059 }
7060 else
7061 Log4((" Selector value exceeds GDT limit!\n"));
7062 }
7063 break;
7064 }
7065
7066 case VMX_VMCSFIELD_WIDTH_32BIT:
7067 {
7068 uint32_t u32Val;
7069 rc = VMXReadVmcs32(uVmcsField, &u32Val);
7070 AssertRC(rc);
7071 Log4(("%-40s = %#RX32\n", s_aVmcsFields[i].pszName, u32Val));
7072 break;
7073 }
7074
7075 case VMX_VMCSFIELD_WIDTH_64BIT:
7076 case VMX_VMCSFIELD_WIDTH_NATURAL:
7077 {
7078 uint64_t u64Val;
7079 rc = VMXReadVmcs64(uVmcsField, &u64Val);
7080 AssertRC(rc);
7081 Log4(("%-40s = %#RX64\n", s_aVmcsFields[i].pszName, u64Val));
7082 break;
7083 }
7084 }
7085 }
7086 }
7087
7088 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
7089 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
7090 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
7091 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
7092 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
7093 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
7094#endif /* VBOX_STRICT */
7095 break;
7096 }
7097
7098 default:
7099 /* Impossible */
7100 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
7101 break;
7102 }
7103}
7104
7105
7106/**
7107 * Sets up the usage of TSC-offsetting and updates the VMCS.
7108 *
7109 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
7110 * VMX-preemption timer.
7111 *
7112 * @returns VBox status code.
7113 * @param pVCpu The cross context virtual CPU structure.
7114 * @param pVmxTransient The VMX-transient structure.
7115 *
7116 * @remarks No-long-jump zone!!!
7117 */
7118static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
7119{
7120 bool fOffsettedTsc;
7121 bool fParavirtTsc;
7122 uint64_t uTscOffset;
7123 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7124 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7125
7126 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
7127 {
7128 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &uTscOffset, &fOffsettedTsc, &fParavirtTsc);
7129
7130 /* Make sure the returned values have sane upper and lower boundaries. */
7131 uint64_t u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
7132 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second */
7133 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
7134 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
7135
7136 /** @todo r=ramshankar: We need to find a way to integrate nested-guest
7137 * preemption timers here. We probably need to clamp the preemption timer,
7138 * after converting the timer value to the host. */
7139 uint32_t const cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
7140 int rc = VMXWriteVmcs32(VMX_VMCS32_PREEMPT_TIMER_VALUE, cPreemptionTickCount);
7141 AssertRC(rc);
7142 }
7143 else
7144 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
7145
7146 if (fParavirtTsc)
7147 {
7148 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
7149 information before every VM-entry, hence disable it for performance sake. */
7150#if 0
7151 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
7152 AssertRC(rc);
7153#endif
7154 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
7155 }
7156
7157 if ( fOffsettedTsc
7158 && RT_LIKELY(!pVCpu->hmr0.s.fDebugWantRdTscExit))
7159 {
7160 if (pVmxTransient->fIsNestedGuest)
7161 uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
7162 hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
7163 hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
7164 }
7165 else
7166 {
7167 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
7168 hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
7169 }
7170}
7171
7172
7173/**
7174 * Gets the IEM exception flags for the specified vector and IDT vectoring /
7175 * VM-exit interruption info type.
7176 *
7177 * @returns The IEM exception flags.
7178 * @param uVector The event vector.
7179 * @param uVmxEventType The VMX event type.
7180 *
7181 * @remarks This function currently only constructs flags required for
7182 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
7183 * and CR2 aspects of an exception are not included).
7184 */
7185static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
7186{
7187 uint32_t fIemXcptFlags;
7188 switch (uVmxEventType)
7189 {
7190 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
7191 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
7192 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
7193 break;
7194
7195 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
7196 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
7197 break;
7198
7199 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
7200 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
7201 break;
7202
7203 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
7204 {
7205 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
7206 if (uVector == X86_XCPT_BP)
7207 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
7208 else if (uVector == X86_XCPT_OF)
7209 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
7210 else
7211 {
7212 fIemXcptFlags = 0;
7213 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
7214 }
7215 break;
7216 }
7217
7218 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
7219 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
7220 break;
7221
7222 default:
7223 fIemXcptFlags = 0;
7224 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
7225 break;
7226 }
7227 return fIemXcptFlags;
7228}
7229
7230
7231/**
7232 * Sets an event as a pending event to be injected into the guest.
7233 *
7234 * @param pVCpu The cross context virtual CPU structure.
7235 * @param u32IntInfo The VM-entry interruption-information field.
7236 * @param cbInstr The VM-entry instruction length in bytes (for
7237 * software interrupts, exceptions and privileged
7238 * software exceptions).
7239 * @param u32ErrCode The VM-entry exception error code.
7240 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
7241 * page-fault.
7242 */
7243DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPUCC pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
7244 RTGCUINTPTR GCPtrFaultAddress)
7245{
7246 Assert(!pVCpu->hm.s.Event.fPending);
7247 pVCpu->hm.s.Event.fPending = true;
7248 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
7249 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
7250 pVCpu->hm.s.Event.cbInstr = cbInstr;
7251 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
7252}
7253
7254
7255/**
7256 * Sets an external interrupt as pending-for-injection into the VM.
7257 *
7258 * @param pVCpu The cross context virtual CPU structure.
7259 * @param u8Interrupt The external interrupt vector.
7260 */
7261DECLINLINE(void) hmR0VmxSetPendingExtInt(PVMCPUCC pVCpu, uint8_t u8Interrupt)
7262{
7263 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
7264 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
7265 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7266 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7267 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7268}
7269
7270
7271/**
7272 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
7273 *
7274 * @param pVCpu The cross context virtual CPU structure.
7275 */
7276DECLINLINE(void) hmR0VmxSetPendingXcptNmi(PVMCPUCC pVCpu)
7277{
7278 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
7279 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
7280 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7281 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7282 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7283}
7284
7285
7286/**
7287 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
7288 *
7289 * @param pVCpu The cross context virtual CPU structure.
7290 */
7291DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPUCC pVCpu)
7292{
7293 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
7294 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7295 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7296 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7297 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7298}
7299
7300
7301/**
7302 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
7303 *
7304 * @param pVCpu The cross context virtual CPU structure.
7305 */
7306DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPUCC pVCpu)
7307{
7308 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
7309 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7310 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7311 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7312 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7313}
7314
7315
7316/**
7317 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
7318 *
7319 * @param pVCpu The cross context virtual CPU structure.
7320 */
7321DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPUCC pVCpu)
7322{
7323 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
7324 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7325 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7326 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7327 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7328}
7329
7330
7331#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7332/**
7333 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
7334 *
7335 * @param pVCpu The cross context virtual CPU structure.
7336 * @param u32ErrCode The error code for the general-protection exception.
7337 */
7338DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPUCC pVCpu, uint32_t u32ErrCode)
7339{
7340 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
7341 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7342 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7343 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7344 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
7345}
7346
7347
7348/**
7349 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
7350 *
7351 * @param pVCpu The cross context virtual CPU structure.
7352 * @param u32ErrCode The error code for the stack exception.
7353 */
7354DECLINLINE(void) hmR0VmxSetPendingXcptSS(PVMCPUCC pVCpu, uint32_t u32ErrCode)
7355{
7356 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
7357 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7358 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7359 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7360 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
7361}
7362#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
7363
7364
7365/**
7366 * Fixes up attributes for the specified segment register.
7367 *
7368 * @param pVCpu The cross context virtual CPU structure.
7369 * @param pSelReg The segment register that needs fixing.
7370 * @param pszRegName The register name (for logging and assertions).
7371 */
7372static void hmR0VmxFixUnusableSegRegAttr(PVMCPUCC pVCpu, PCPUMSELREG pSelReg, const char *pszRegName)
7373{
7374 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
7375
7376 /*
7377 * If VT-x marks the segment as unusable, most other bits remain undefined:
7378 * - For CS the L, D and G bits have meaning.
7379 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
7380 * - For the remaining data segments no bits are defined.
7381 *
7382 * The present bit and the unusable bit has been observed to be set at the
7383 * same time (the selector was supposed to be invalid as we started executing
7384 * a V8086 interrupt in ring-0).
7385 *
7386 * What should be important for the rest of the VBox code, is that the P bit is
7387 * cleared. Some of the other VBox code recognizes the unusable bit, but
7388 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
7389 * safe side here, we'll strip off P and other bits we don't care about. If
7390 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
7391 *
7392 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
7393 */
7394#ifdef VBOX_STRICT
7395 uint32_t const uAttr = pSelReg->Attr.u;
7396#endif
7397
7398 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
7399 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
7400 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
7401
7402#ifdef VBOX_STRICT
7403 VMMRZCallRing3Disable(pVCpu);
7404 Log4Func(("Unusable %s: sel=%#x attr=%#x -> %#x\n", pszRegName, pSelReg->Sel, uAttr, pSelReg->Attr.u));
7405# ifdef DEBUG_bird
7406 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
7407 ("%s: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
7408 pszRegName, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
7409# endif
7410 VMMRZCallRing3Enable(pVCpu);
7411 NOREF(uAttr);
7412#endif
7413 RT_NOREF2(pVCpu, pszRegName);
7414}
7415
7416
7417/**
7418 * Imports a guest segment register from the current VMCS into the guest-CPU
7419 * context.
7420 *
7421 * @param pVCpu The cross context virtual CPU structure.
7422 * @param iSegReg The segment register number (X86_SREG_XXX).
7423 *
7424 * @remarks Called with interrupts and/or preemption disabled.
7425 */
7426static void hmR0VmxImportGuestSegReg(PVMCPUCC pVCpu, uint32_t iSegReg)
7427{
7428 Assert(iSegReg < X86_SREG_COUNT);
7429 Assert((uint32_t)VMX_VMCS16_GUEST_SEG_SEL(iSegReg) == g_aVmcsSegSel[iSegReg]);
7430 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg) == g_aVmcsSegLimit[iSegReg]);
7431 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg) == g_aVmcsSegAttr[iSegReg]);
7432 Assert((uint32_t)VMX_VMCS_GUEST_SEG_BASE(iSegReg) == g_aVmcsSegBase[iSegReg]);
7433
7434 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
7435
7436 uint16_t u16Sel;
7437 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_SEG_SEL(iSegReg), &u16Sel); AssertRC(rc);
7438 pSelReg->Sel = u16Sel;
7439 pSelReg->ValidSel = u16Sel;
7440
7441 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg), &pSelReg->u32Limit); AssertRC(rc);
7442 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SEG_BASE(iSegReg), &pSelReg->u64Base); AssertRC(rc);
7443
7444 uint32_t u32Attr;
7445 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg), &u32Attr); AssertRC(rc);
7446 pSelReg->Attr.u = u32Attr;
7447 if (u32Attr & X86DESCATTR_UNUSABLE)
7448 hmR0VmxFixUnusableSegRegAttr(pVCpu, pSelReg, "ES\0CS\0SS\0DS\0FS\0GS" + iSegReg * 3);
7449
7450 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
7451}
7452
7453
7454/**
7455 * Imports the guest LDTR from the current VMCS into the guest-CPU context.
7456 *
7457 * @param pVCpu The cross context virtual CPU structure.
7458 *
7459 * @remarks Called with interrupts and/or preemption disabled.
7460 */
7461static void hmR0VmxImportGuestLdtr(PVMCPUCC pVCpu)
7462{
7463 uint16_t u16Sel;
7464 uint64_t u64Base;
7465 uint32_t u32Limit, u32Attr;
7466 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
7467 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
7468 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7469 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
7470
7471 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
7472 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
7473 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
7474 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
7475 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
7476 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
7477 if (u32Attr & X86DESCATTR_UNUSABLE)
7478 hmR0VmxFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, "LDTR");
7479}
7480
7481
7482/**
7483 * Imports the guest TR from the current VMCS into the guest-CPU context.
7484 *
7485 * @param pVCpu The cross context virtual CPU structure.
7486 *
7487 * @remarks Called with interrupts and/or preemption disabled.
7488 */
7489static void hmR0VmxImportGuestTr(PVMCPUCC pVCpu)
7490{
7491 uint16_t u16Sel;
7492 uint64_t u64Base;
7493 uint32_t u32Limit, u32Attr;
7494 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
7495 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
7496 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7497 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
7498
7499 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
7500 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
7501 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
7502 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
7503 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
7504 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
7505 /* TR is the only selector that can never be unusable. */
7506 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
7507}
7508
7509
7510/**
7511 * Imports the guest RIP from the VMCS back into the guest-CPU context.
7512 *
7513 * @param pVCpu The cross context virtual CPU structure.
7514 *
7515 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7516 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7517 * instead!!!
7518 */
7519static void hmR0VmxImportGuestRip(PVMCPUCC pVCpu)
7520{
7521 uint64_t u64Val;
7522 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7523 if (pCtx->fExtrn & CPUMCTX_EXTRN_RIP)
7524 {
7525 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
7526 AssertRC(rc);
7527
7528 pCtx->rip = u64Val;
7529 EMR0HistoryUpdatePC(pVCpu, pCtx->rip, false);
7530 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RIP;
7531 }
7532}
7533
7534
7535/**
7536 * Imports the guest RFLAGS from the VMCS back into the guest-CPU context.
7537 *
7538 * @param pVCpu The cross context virtual CPU structure.
7539 * @param pVmcsInfo The VMCS info. object.
7540 *
7541 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7542 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7543 * instead!!!
7544 */
7545static void hmR0VmxImportGuestRFlags(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7546{
7547 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7548 if (pCtx->fExtrn & CPUMCTX_EXTRN_RFLAGS)
7549 {
7550 uint64_t u64Val;
7551 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
7552 AssertRC(rc);
7553
7554 pCtx->rflags.u64 = u64Val;
7555 PCVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7556 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
7557 {
7558 pCtx->eflags.Bits.u1VM = 0;
7559 pCtx->eflags.Bits.u2IOPL = pVmcsInfoShared->RealMode.Eflags.Bits.u2IOPL;
7560 }
7561 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
7562 }
7563}
7564
7565
7566/**
7567 * Imports the guest interruptibility-state from the VMCS back into the guest-CPU
7568 * context.
7569 *
7570 * @param pVCpu The cross context virtual CPU structure.
7571 * @param pVmcsInfo The VMCS info. object.
7572 *
7573 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
7574 * do not log!
7575 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7576 * instead!!!
7577 */
7578static void hmR0VmxImportGuestIntrState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7579{
7580 uint32_t u32Val;
7581 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
7582 if (!u32Val)
7583 {
7584 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7585 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7586 CPUMSetGuestNmiBlocking(pVCpu, false);
7587 }
7588 else
7589 {
7590 /*
7591 * We must import RIP here to set our EM interrupt-inhibited state.
7592 * We also import RFLAGS as our code that evaluates pending interrupts
7593 * before VM-entry requires it.
7594 */
7595 hmR0VmxImportGuestRip(pVCpu);
7596 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7597
7598 if (u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
7599 EMSetInhibitInterruptsPC(pVCpu, pVCpu->cpum.GstCtx.rip);
7600 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7601 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7602
7603 bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
7604 CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
7605 }
7606}
7607
7608
7609/**
7610 * Worker for VMXR0ImportStateOnDemand.
7611 *
7612 * @returns VBox status code.
7613 * @param pVCpu The cross context virtual CPU structure.
7614 * @param pVmcsInfo The VMCS info. object.
7615 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7616 */
7617static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
7618{
7619 int rc = VINF_SUCCESS;
7620 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7621 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7622 uint32_t u32Val;
7623
7624 /*
7625 * Note! This is hack to workaround a mysterious BSOD observed with release builds
7626 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
7627 * neither are other host platforms.
7628 *
7629 * Committing this temporarily as it prevents BSOD.
7630 *
7631 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
7632 */
7633#ifdef RT_OS_WINDOWS
7634 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
7635 return VERR_HM_IPE_1;
7636#endif
7637
7638 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatImportGuestState, x);
7639
7640 /*
7641 * We disable interrupts to make the updating of the state and in particular
7642 * the fExtrn modification atomic wrt to preemption hooks.
7643 */
7644 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
7645
7646 fWhat &= pCtx->fExtrn;
7647 if (fWhat)
7648 {
7649 do
7650 {
7651 if (fWhat & CPUMCTX_EXTRN_RIP)
7652 hmR0VmxImportGuestRip(pVCpu);
7653
7654 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
7655 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7656
7657 if (fWhat & CPUMCTX_EXTRN_HM_VMX_INT_STATE)
7658 hmR0VmxImportGuestIntrState(pVCpu, pVmcsInfo);
7659
7660 if (fWhat & CPUMCTX_EXTRN_RSP)
7661 {
7662 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RSP, &pCtx->rsp);
7663 AssertRC(rc);
7664 }
7665
7666 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
7667 {
7668 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7669 bool const fRealOnV86Active = pVmcsInfoShared->RealMode.fRealOnV86Active;
7670 if (fWhat & CPUMCTX_EXTRN_CS)
7671 {
7672 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_CS);
7673 hmR0VmxImportGuestRip(pVCpu);
7674 if (fRealOnV86Active)
7675 pCtx->cs.Attr.u = pVmcsInfoShared->RealMode.AttrCS.u;
7676 EMR0HistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
7677 }
7678 if (fWhat & CPUMCTX_EXTRN_SS)
7679 {
7680 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_SS);
7681 if (fRealOnV86Active)
7682 pCtx->ss.Attr.u = pVmcsInfoShared->RealMode.AttrSS.u;
7683 }
7684 if (fWhat & CPUMCTX_EXTRN_DS)
7685 {
7686 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_DS);
7687 if (fRealOnV86Active)
7688 pCtx->ds.Attr.u = pVmcsInfoShared->RealMode.AttrDS.u;
7689 }
7690 if (fWhat & CPUMCTX_EXTRN_ES)
7691 {
7692 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_ES);
7693 if (fRealOnV86Active)
7694 pCtx->es.Attr.u = pVmcsInfoShared->RealMode.AttrES.u;
7695 }
7696 if (fWhat & CPUMCTX_EXTRN_FS)
7697 {
7698 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_FS);
7699 if (fRealOnV86Active)
7700 pCtx->fs.Attr.u = pVmcsInfoShared->RealMode.AttrFS.u;
7701 }
7702 if (fWhat & CPUMCTX_EXTRN_GS)
7703 {
7704 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_GS);
7705 if (fRealOnV86Active)
7706 pCtx->gs.Attr.u = pVmcsInfoShared->RealMode.AttrGS.u;
7707 }
7708 }
7709
7710 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
7711 {
7712 if (fWhat & CPUMCTX_EXTRN_LDTR)
7713 hmR0VmxImportGuestLdtr(pVCpu);
7714
7715 if (fWhat & CPUMCTX_EXTRN_GDTR)
7716 {
7717 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &pCtx->gdtr.pGdt); AssertRC(rc);
7718 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
7719 pCtx->gdtr.cbGdt = u32Val;
7720 }
7721
7722 /* Guest IDTR. */
7723 if (fWhat & CPUMCTX_EXTRN_IDTR)
7724 {
7725 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &pCtx->idtr.pIdt); AssertRC(rc);
7726 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
7727 pCtx->idtr.cbIdt = u32Val;
7728 }
7729
7730 /* Guest TR. */
7731 if (fWhat & CPUMCTX_EXTRN_TR)
7732 {
7733 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
7734 don't need to import that one. */
7735 if (!pVmcsInfo->pShared->RealMode.fRealOnV86Active)
7736 hmR0VmxImportGuestTr(pVCpu);
7737 }
7738 }
7739
7740 if (fWhat & CPUMCTX_EXTRN_DR7)
7741 {
7742 if (!pVCpu->hmr0.s.fUsingHyperDR7)
7743 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_DR7, &pCtx->dr[7]); AssertRC(rc);
7744 }
7745
7746 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
7747 {
7748 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, &pCtx->SysEnter.eip); AssertRC(rc);
7749 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, &pCtx->SysEnter.esp); AssertRC(rc);
7750 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
7751 pCtx->SysEnter.cs = u32Val;
7752 }
7753
7754 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
7755 {
7756 if ( pVM->hmr0.s.fAllow64BitGuests
7757 && (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7758 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
7759 }
7760
7761 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
7762 {
7763 if ( pVM->hmr0.s.fAllow64BitGuests
7764 && (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7765 {
7766 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
7767 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
7768 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
7769 }
7770 }
7771
7772 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
7773 {
7774 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7775 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
7776 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
7777 Assert(pMsrs);
7778 Assert(cMsrs <= VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc));
7779 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
7780 for (uint32_t i = 0; i < cMsrs; i++)
7781 {
7782 uint32_t const idMsr = pMsrs[i].u32Msr;
7783 switch (idMsr)
7784 {
7785 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
7786 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
7787 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
7788 default:
7789 {
7790 uint32_t idxLbrMsr;
7791 if (pVM->hm.s.vmx.fLbr)
7792 {
7793 if (hmR0VmxIsLbrBranchFromMsr(pVM, idMsr, &idxLbrMsr))
7794 {
7795 Assert(idxLbrMsr < RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr));
7796 pVmcsInfoShared->au64LbrFromIpMsr[idxLbrMsr] = pMsrs[i].u64Value;
7797 break;
7798 }
7799 if (hmR0VmxIsLbrBranchToMsr(pVM, idMsr, &idxLbrMsr))
7800 {
7801 Assert(idxLbrMsr < RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr));
7802 pVmcsInfoShared->au64LbrToIpMsr[idxLbrMsr] = pMsrs[i].u64Value;
7803 break;
7804 }
7805 if (idMsr == pVM->hm.s.vmx.idLbrTosMsr)
7806 {
7807 pVmcsInfoShared->u64LbrTosMsr = pMsrs[i].u64Value;
7808 break;
7809 }
7810 /* Fallthru (no break) */
7811 }
7812 pCtx->fExtrn = 0;
7813 pVCpu->hm.s.u32HMError = pMsrs->u32Msr;
7814 ASMSetFlags(fEFlags);
7815 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
7816 return VERR_HM_UNEXPECTED_LD_ST_MSR;
7817 }
7818 }
7819 }
7820 }
7821
7822 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
7823 {
7824 if (fWhat & CPUMCTX_EXTRN_CR0)
7825 {
7826 uint64_t u64Cr0;
7827 uint64_t u64Shadow;
7828 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Cr0); AssertRC(rc);
7829 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Shadow); AssertRC(rc);
7830#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
7831 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7832 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7833#else
7834 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
7835 {
7836 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7837 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7838 }
7839 else
7840 {
7841 /*
7842 * We've merged the guest and nested-guest's CR0 guest/host mask while executing
7843 * the nested-guest using hardware-assisted VMX. Accordingly we need to
7844 * re-construct CR0. See @bugref{9180#c95} for details.
7845 */
7846 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
7847 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
7848 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7849 | (pVmcsNstGst->u64GuestCr0.u & pVmcsNstGst->u64Cr0Mask.u)
7850 | (u64Shadow & (pVmcsInfoGst->u64Cr0Mask & ~pVmcsNstGst->u64Cr0Mask.u));
7851 }
7852#endif
7853 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
7854 CPUMSetGuestCR0(pVCpu, u64Cr0);
7855 VMMRZCallRing3Enable(pVCpu);
7856 }
7857
7858 if (fWhat & CPUMCTX_EXTRN_CR4)
7859 {
7860 uint64_t u64Cr4;
7861 uint64_t u64Shadow;
7862 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64Cr4); AssertRC(rc);
7863 rc |= VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Shadow); AssertRC(rc);
7864#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
7865 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7866 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7867#else
7868 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
7869 {
7870 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7871 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7872 }
7873 else
7874 {
7875 /*
7876 * We've merged the guest and nested-guest's CR4 guest/host mask while executing
7877 * the nested-guest using hardware-assisted VMX. Accordingly we need to
7878 * re-construct CR4. See @bugref{9180#c95} for details.
7879 */
7880 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
7881 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
7882 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7883 | (pVmcsNstGst->u64GuestCr4.u & pVmcsNstGst->u64Cr4Mask.u)
7884 | (u64Shadow & (pVmcsInfoGst->u64Cr4Mask & ~pVmcsNstGst->u64Cr4Mask.u));
7885 }
7886#endif
7887 pCtx->cr4 = u64Cr4;
7888 }
7889
7890 if (fWhat & CPUMCTX_EXTRN_CR3)
7891 {
7892 /* CR0.PG bit changes are always intercepted, so it's up to date. */
7893 if ( pVM->hmr0.s.vmx.fUnrestrictedGuest
7894 || ( pVM->hmr0.s.fNestedPaging
7895 && CPUMIsGuestPagingEnabledEx(pCtx)))
7896 {
7897 uint64_t u64Cr3;
7898 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR3, &u64Cr3); AssertRC(rc);
7899 if (pCtx->cr3 != u64Cr3)
7900 {
7901 pCtx->cr3 = u64Cr3;
7902 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7903 }
7904
7905 /* If the guest is in PAE mode, sync back the PDPE's into the guest state.
7906 Note: CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date. */
7907 if (CPUMIsGuestInPAEModeEx(pCtx))
7908 {
7909 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
7910 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
7911 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
7912 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
7913 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
7914 }
7915 }
7916 }
7917 }
7918
7919#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7920 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
7921 {
7922 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7923 && !CPUMIsGuestInVmxNonRootMode(pCtx))
7924 {
7925 Assert(CPUMIsGuestInVmxRootMode(pCtx));
7926 rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
7927 if (RT_SUCCESS(rc))
7928 { /* likely */ }
7929 else
7930 break;
7931 }
7932 }
7933#endif
7934 } while (0);
7935
7936 if (RT_SUCCESS(rc))
7937 {
7938 /* Update fExtrn. */
7939 pCtx->fExtrn &= ~fWhat;
7940
7941 /* If everything has been imported, clear the HM keeper bit. */
7942 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
7943 {
7944 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
7945 Assert(!pCtx->fExtrn);
7946 }
7947 }
7948 }
7949 else
7950 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
7951
7952 /*
7953 * Restore interrupts.
7954 */
7955 ASMSetFlags(fEFlags);
7956
7957 STAM_PROFILE_ADV_STOP(& pVCpu->hm.s.StatImportGuestState, x);
7958
7959 if (RT_SUCCESS(rc))
7960 { /* likely */ }
7961 else
7962 return rc;
7963
7964 /*
7965 * Honor any pending CR3 updates.
7966 *
7967 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> VMXR0CallRing3Callback()
7968 * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
7969 * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
7970 *
7971 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
7972 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
7973 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
7974 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
7975 *
7976 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
7977 */
7978 if (VMMRZCallRing3IsEnabled(pVCpu))
7979 {
7980 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
7981 {
7982 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
7983 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
7984 }
7985
7986 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
7987 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
7988
7989 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
7990 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
7991 }
7992
7993 return VINF_SUCCESS;
7994}
7995
7996
7997/**
7998 * Saves the guest state from the VMCS into the guest-CPU context.
7999 *
8000 * @returns VBox status code.
8001 * @param pVCpu The cross context virtual CPU structure.
8002 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
8003 */
8004VMMR0DECL(int) VMXR0ImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat)
8005{
8006 AssertPtr(pVCpu);
8007 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8008 return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
8009}
8010
8011
8012/**
8013 * Check per-VM and per-VCPU force flag actions that require us to go back to
8014 * ring-3 for one reason or another.
8015 *
8016 * @returns Strict VBox status code (i.e. informational status codes too)
8017 * @retval VINF_SUCCESS if we don't have any actions that require going back to
8018 * ring-3.
8019 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
8020 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
8021 * interrupts)
8022 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
8023 * all EMTs to be in ring-3.
8024 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
8025 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
8026 * to the EM loop.
8027 *
8028 * @param pVCpu The cross context virtual CPU structure.
8029 * @param pVmxTransient The VMX-transient structure.
8030 * @param fStepping Whether we are single-stepping the guest using the
8031 * hypervisor debugger.
8032 *
8033 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
8034 * is no longer in VMX non-root mode.
8035 */
8036static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, bool fStepping)
8037{
8038 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8039
8040 /*
8041 * Update pending interrupts into the APIC's IRR.
8042 */
8043 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
8044 APICUpdatePendingInterrupts(pVCpu);
8045
8046 /*
8047 * Anything pending? Should be more likely than not if we're doing a good job.
8048 */
8049 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8050 if ( !fStepping
8051 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
8052 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
8053 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
8054 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
8055 return VINF_SUCCESS;
8056
8057 /* Pending PGM C3 sync. */
8058 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
8059 {
8060 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8061 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
8062 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
8063 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
8064 if (rcStrict != VINF_SUCCESS)
8065 {
8066 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
8067 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
8068 return rcStrict;
8069 }
8070 }
8071
8072 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
8073 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
8074 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
8075 {
8076 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
8077 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
8078 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
8079 return rc;
8080 }
8081
8082 /* Pending VM request packets, such as hardware interrupts. */
8083 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
8084 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
8085 {
8086 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchVmReq);
8087 Log4Func(("Pending VM request forcing us back to ring-3\n"));
8088 return VINF_EM_PENDING_REQUEST;
8089 }
8090
8091 /* Pending PGM pool flushes. */
8092 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
8093 {
8094 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPgmPoolFlush);
8095 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
8096 return VINF_PGM_POOL_FLUSH_PENDING;
8097 }
8098
8099 /* Pending DMA requests. */
8100 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
8101 {
8102 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchDma);
8103 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
8104 return VINF_EM_RAW_TO_R3;
8105 }
8106
8107#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8108 /*
8109 * Pending nested-guest events.
8110 *
8111 * Please note the priority of these events are specified and important.
8112 * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
8113 * See Intel spec. 6.9 "Priority Among Simultaneous Exceptions And Interrupts".
8114 */
8115 if (pVmxTransient->fIsNestedGuest)
8116 {
8117 /* Pending nested-guest APIC-write. */
8118 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
8119 {
8120 Log4Func(("Pending nested-guest APIC-write\n"));
8121 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
8122 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8123 return rcStrict;
8124 }
8125
8126 /* Pending nested-guest monitor-trap flag (MTF). */
8127 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF))
8128 {
8129 Log4Func(("Pending nested-guest MTF\n"));
8130 VBOXSTRICTRC rcStrict = IEMExecVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* uExitQual */);
8131 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8132 return rcStrict;
8133 }
8134
8135 /* Pending nested-guest VMX-preemption timer expired. */
8136 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))
8137 {
8138 Log4Func(("Pending nested-guest MTF\n"));
8139 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitPreemptTimer(pVCpu);
8140 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8141 return rcStrict;
8142 }
8143 }
8144#else
8145 NOREF(pVmxTransient);
8146#endif
8147
8148 return VINF_SUCCESS;
8149}
8150
8151
8152/**
8153 * Converts any TRPM trap into a pending HM event. This is typically used when
8154 * entering from ring-3 (not longjmp returns).
8155 *
8156 * @param pVCpu The cross context virtual CPU structure.
8157 */
8158static void hmR0VmxTrpmTrapToPendingEvent(PVMCPUCC pVCpu)
8159{
8160 Assert(TRPMHasTrap(pVCpu));
8161 Assert(!pVCpu->hm.s.Event.fPending);
8162
8163 uint8_t uVector;
8164 TRPMEVENT enmTrpmEvent;
8165 uint32_t uErrCode;
8166 RTGCUINTPTR GCPtrFaultAddress;
8167 uint8_t cbInstr;
8168 bool fIcebp;
8169
8170 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr, &fIcebp);
8171 AssertRC(rc);
8172
8173 uint32_t u32IntInfo;
8174 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
8175 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent, fIcebp);
8176
8177 rc = TRPMResetTrap(pVCpu);
8178 AssertRC(rc);
8179 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
8180 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
8181
8182 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
8183}
8184
8185
8186/**
8187 * Converts the pending HM event into a TRPM trap.
8188 *
8189 * @param pVCpu The cross context virtual CPU structure.
8190 */
8191static void hmR0VmxPendingEventToTrpmTrap(PVMCPUCC pVCpu)
8192{
8193 Assert(pVCpu->hm.s.Event.fPending);
8194
8195 /* If a trap was already pending, we did something wrong! */
8196 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
8197
8198 uint32_t const u32IntInfo = pVCpu->hm.s.Event.u64IntInfo;
8199 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
8200 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
8201
8202 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
8203
8204 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
8205 AssertRC(rc);
8206
8207 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8208 TRPMSetErrorCode(pVCpu, pVCpu->hm.s.Event.u32ErrCode);
8209
8210 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
8211 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
8212 else
8213 {
8214 uint8_t const uVectorType = VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo);
8215 switch (uVectorType)
8216 {
8217 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
8218 TRPMSetTrapDueToIcebp(pVCpu);
8219 RT_FALL_THRU();
8220 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
8221 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
8222 {
8223 AssertMsg( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
8224 || ( uVector == X86_XCPT_BP /* INT3 */
8225 || uVector == X86_XCPT_OF /* INTO */
8226 || uVector == X86_XCPT_DB /* INT1 (ICEBP) */),
8227 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
8228 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
8229 break;
8230 }
8231 }
8232 }
8233
8234 /* We're now done converting the pending event. */
8235 pVCpu->hm.s.Event.fPending = false;
8236}
8237
8238
8239/**
8240 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
8241 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
8242 *
8243 * @param pVmcsInfo The VMCS info. object.
8244 */
8245static void hmR0VmxSetIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8246{
8247 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
8248 {
8249 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
8250 {
8251 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
8252 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8253 AssertRC(rc);
8254 }
8255 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
8256}
8257
8258
8259/**
8260 * Clears the interrupt-window exiting control in the VMCS.
8261 *
8262 * @param pVmcsInfo The VMCS info. object.
8263 */
8264DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8265{
8266 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
8267 {
8268 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
8269 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8270 AssertRC(rc);
8271 }
8272}
8273
8274
8275/**
8276 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
8277 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
8278 *
8279 * @param pVmcsInfo The VMCS info. object.
8280 */
8281static void hmR0VmxSetNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8282{
8283 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
8284 {
8285 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
8286 {
8287 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
8288 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8289 AssertRC(rc);
8290 Log4Func(("Setup NMI-window exiting\n"));
8291 }
8292 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
8293}
8294
8295
8296/**
8297 * Clears the NMI-window exiting control in the VMCS.
8298 *
8299 * @param pVmcsInfo The VMCS info. object.
8300 */
8301DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8302{
8303 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
8304 {
8305 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
8306 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8307 AssertRC(rc);
8308 }
8309}
8310
8311
8312/**
8313 * Does the necessary state syncing before returning to ring-3 for any reason
8314 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
8315 *
8316 * @returns VBox status code.
8317 * @param pVCpu The cross context virtual CPU structure.
8318 * @param fImportState Whether to import the guest state from the VMCS back
8319 * to the guest-CPU context.
8320 *
8321 * @remarks No-long-jmp zone!!!
8322 */
8323static int hmR0VmxLeave(PVMCPUCC pVCpu, bool fImportState)
8324{
8325 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8326 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8327
8328 RTCPUID const idCpu = RTMpCpuId();
8329 Log4Func(("HostCpuId=%u\n", idCpu));
8330
8331 /*
8332 * !!! IMPORTANT !!!
8333 * If you modify code here, check whether VMXR0CallRing3Callback() needs to be updated too.
8334 */
8335
8336 /* Save the guest state if necessary. */
8337 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8338 if (fImportState)
8339 {
8340 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8341 AssertRCReturn(rc, rc);
8342 }
8343
8344 /* Restore host FPU state if necessary. We will resync on next R0 reentry. */
8345 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8346 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
8347
8348 /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
8349#ifdef VBOX_STRICT
8350 if (CPUMIsHyperDebugStateActive(pVCpu))
8351 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
8352#endif
8353 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8354 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
8355 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
8356
8357 /* Restore host-state bits that VT-x only restores partially. */
8358 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
8359 {
8360 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hmr0.s.vmx.fRestoreHostFlags, idCpu));
8361 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
8362 }
8363 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
8364
8365 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8366 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8367 {
8368 /* We shouldn't restore the host MSRs without saving the guest MSRs first. */
8369 if (!fImportState)
8370 {
8371 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS);
8372 AssertRCReturn(rc, rc);
8373 }
8374 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8375 Assert(!pVCpu->hmr0.s.vmx.fLazyMsrs);
8376 }
8377 else
8378 pVCpu->hmr0.s.vmx.fLazyMsrs = 0;
8379
8380 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8381 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
8382
8383 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
8384 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatImportGuestState);
8385 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExportGuestState);
8386 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatPreExit);
8387 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitHandling);
8388 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
8389 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
8390 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
8391 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitVmentry);
8392 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8393
8394 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8395
8396 /** @todo This partially defeats the purpose of having preemption hooks.
8397 * The problem is, deregistering the hooks should be moved to a place that
8398 * lasts until the EMT is about to be destroyed not everytime while leaving HM
8399 * context.
8400 */
8401 int rc = hmR0VmxClearVmcs(pVmcsInfo);
8402 AssertRCReturn(rc, rc);
8403
8404#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8405 /*
8406 * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
8407 * clear a shadow VMCS before allowing that VMCS to become active on another
8408 * logical processor. We may or may not be importing guest state which clears
8409 * it, so cover for it here.
8410 *
8411 * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
8412 */
8413 if ( pVmcsInfo->pvShadowVmcs
8414 && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
8415 {
8416 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
8417 AssertRCReturn(rc, rc);
8418 }
8419
8420 /*
8421 * Flag that we need to re-export the host state if we switch to this VMCS before
8422 * executing guest or nested-guest code.
8423 */
8424 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
8425#endif
8426
8427 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
8428 NOREF(idCpu);
8429 return VINF_SUCCESS;
8430}
8431
8432
8433/**
8434 * Leaves the VT-x session.
8435 *
8436 * @returns VBox status code.
8437 * @param pVCpu The cross context virtual CPU structure.
8438 *
8439 * @remarks No-long-jmp zone!!!
8440 */
8441static int hmR0VmxLeaveSession(PVMCPUCC pVCpu)
8442{
8443 HM_DISABLE_PREEMPT(pVCpu);
8444 HMVMX_ASSERT_CPU_SAFE(pVCpu);
8445 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8446 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8447
8448 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
8449 and done this from the VMXR0ThreadCtxCallback(). */
8450 if (!pVCpu->hmr0.s.fLeaveDone)
8451 {
8452 int rc2 = hmR0VmxLeave(pVCpu, true /* fImportState */);
8453 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
8454 pVCpu->hmr0.s.fLeaveDone = true;
8455 }
8456 Assert(!pVCpu->cpum.GstCtx.fExtrn);
8457
8458 /*
8459 * !!! IMPORTANT !!!
8460 * If you modify code here, make sure to check whether VMXR0CallRing3Callback() needs to be updated too.
8461 */
8462
8463 /* Deregister hook now that we've left HM context before re-enabling preemption. */
8464 /** @todo Deregistering here means we need to VMCLEAR always
8465 * (longjmp/exit-to-r3) in VT-x which is not efficient, eliminate need
8466 * for calling VMMR0ThreadCtxHookDisable here! */
8467 VMMR0ThreadCtxHookDisable(pVCpu);
8468
8469 /* Leave HM context. This takes care of local init (term) and deregistering the longjmp-to-ring-3 callback. */
8470 int rc = HMR0LeaveCpu(pVCpu);
8471 HM_RESTORE_PREEMPT();
8472 return rc;
8473}
8474
8475
8476/**
8477 * Does the necessary state syncing before doing a longjmp to ring-3.
8478 *
8479 * @returns VBox status code.
8480 * @param pVCpu The cross context virtual CPU structure.
8481 *
8482 * @remarks No-long-jmp zone!!!
8483 */
8484DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPUCC pVCpu)
8485{
8486 return hmR0VmxLeaveSession(pVCpu);
8487}
8488
8489
8490/**
8491 * Take necessary actions before going back to ring-3.
8492 *
8493 * An action requires us to go back to ring-3. This function does the necessary
8494 * steps before we can safely return to ring-3. This is not the same as longjmps
8495 * to ring-3, this is voluntary and prepares the guest so it may continue
8496 * executing outside HM (recompiler/IEM).
8497 *
8498 * @returns VBox status code.
8499 * @param pVCpu The cross context virtual CPU structure.
8500 * @param rcExit The reason for exiting to ring-3. Can be
8501 * VINF_VMM_UNKNOWN_RING3_CALL.
8502 */
8503static int hmR0VmxExitToRing3(PVMCPUCC pVCpu, VBOXSTRICTRC rcExit)
8504{
8505 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8506
8507 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8508 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
8509 {
8510 VMXGetCurrentVmcs(&pVCpu->hm.s.vmx.LastError.HCPhysCurrentVmcs);
8511 pVCpu->hm.s.vmx.LastError.u32VmcsRev = *(uint32_t *)pVmcsInfo->pvVmcs;
8512 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hmr0.s.idEnteredCpu;
8513 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
8514 }
8515
8516 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
8517 VMMRZCallRing3Disable(pVCpu);
8518 Log4Func(("rcExit=%d\n", VBOXSTRICTRC_VAL(rcExit)));
8519
8520 /*
8521 * Convert any pending HM events back to TRPM due to premature exits to ring-3.
8522 * We need to do this only on returns to ring-3 and not for longjmps to ring3.
8523 *
8524 * This is because execution may continue from ring-3 and we would need to inject
8525 * the event from there (hence place it back in TRPM).
8526 */
8527 if (pVCpu->hm.s.Event.fPending)
8528 {
8529 hmR0VmxPendingEventToTrpmTrap(pVCpu);
8530 Assert(!pVCpu->hm.s.Event.fPending);
8531
8532 /* Clear the events from the VMCS. */
8533 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
8534 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, 0); AssertRC(rc);
8535 }
8536#ifdef VBOX_STRICT
8537 /*
8538 * We check for rcExit here since for errors like VERR_VMX_UNABLE_TO_START_VM (which are
8539 * fatal), we don't care about verifying duplicate injection of events. Errors like
8540 * VERR_EM_INTERPRET are converted to their VINF_* counterparts -prior- to calling this
8541 * function so those should and will be checked below.
8542 */
8543 else if (RT_SUCCESS(rcExit))
8544 {
8545 /*
8546 * Ensure we don't accidentally clear a pending HM event without clearing the VMCS.
8547 * This can be pretty hard to debug otherwise, interrupts might get injected twice
8548 * occasionally, see @bugref{9180#c42}.
8549 *
8550 * However, if the VM-entry failed, any VM entry-interruption info. field would
8551 * be left unmodified as the event would not have been injected to the guest. In
8552 * such cases, don't assert, we're not going to continue guest execution anyway.
8553 */
8554 uint32_t uExitReason;
8555 uint32_t uEntryIntInfo;
8556 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8557 rc |= VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &uEntryIntInfo);
8558 AssertRC(rc);
8559 AssertMsg(VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason) || !VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo),
8560 ("uExitReason=%#RX32 uEntryIntInfo=%#RX32 rcExit=%d\n", uExitReason, uEntryIntInfo, VBOXSTRICTRC_VAL(rcExit)));
8561 }
8562#endif
8563
8564 /*
8565 * Clear the interrupt-window and NMI-window VMCS controls as we could have got
8566 * a VM-exit with higher priority than interrupt-window or NMI-window VM-exits
8567 * (e.g. TPR below threshold).
8568 */
8569 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8570 {
8571 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
8572 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
8573 }
8574
8575 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
8576 and if we're injecting an event we should have a TRPM trap pending. */
8577 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8578#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a triple fault in progress. */
8579 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8580#endif
8581
8582 /* Save guest state and restore host state bits. */
8583 int rc = hmR0VmxLeaveSession(pVCpu);
8584 AssertRCReturn(rc, rc);
8585 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8586
8587 /* Thread-context hooks are unregistered at this point!!! */
8588 /* Ring-3 callback notifications are unregistered at this point!!! */
8589
8590 /* Sync recompiler state. */
8591 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
8592 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
8593 | CPUM_CHANGED_LDTR
8594 | CPUM_CHANGED_GDTR
8595 | CPUM_CHANGED_IDTR
8596 | CPUM_CHANGED_TR
8597 | CPUM_CHANGED_HIDDEN_SEL_REGS);
8598 if ( pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging
8599 && CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx))
8600 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
8601
8602 Assert(!pVCpu->hmr0.s.fClearTrapFlag);
8603
8604 /* Update the exit-to-ring 3 reason. */
8605 pVCpu->hm.s.rcLastExitToR3 = VBOXSTRICTRC_VAL(rcExit);
8606
8607 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
8608 if ( rcExit != VINF_EM_RAW_INTERRUPT
8609 || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8610 {
8611 Assert(!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL));
8612 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
8613 }
8614
8615 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
8616 VMMRZCallRing3Enable(pVCpu);
8617 return rc;
8618}
8619
8620
8621/**
8622 * VMMRZCallRing3() callback wrapper which saves the guest state before we
8623 * longjump to ring-3 and possibly get preempted.
8624 *
8625 * @returns VBox status code.
8626 * @param pVCpu The cross context virtual CPU structure.
8627 * @param enmOperation The operation causing the ring-3 longjump.
8628 */
8629VMMR0DECL(int) VMXR0CallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation)
8630{
8631 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
8632 {
8633 /*
8634 * !!! IMPORTANT !!!
8635 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
8636 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
8637 */
8638 VMMRZCallRing3RemoveNotification(pVCpu);
8639 VMMRZCallRing3Disable(pVCpu);
8640 HM_DISABLE_PREEMPT(pVCpu);
8641
8642 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8643 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8644 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8645 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8646
8647 /* Restore host-state bits that VT-x only restores partially. */
8648 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
8649 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
8650 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
8651
8652 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8653 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8654 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8655
8656 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8657 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
8658 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8659
8660 /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
8661 cleared as part of importing the guest state above. */
8662 hmR0VmxClearVmcs(pVmcsInfo);
8663
8664 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
8665 VMMR0ThreadCtxHookDisable(pVCpu);
8666
8667 /* Leave HM context. This takes care of local init (term). */
8668 HMR0LeaveCpu(pVCpu);
8669 HM_RESTORE_PREEMPT();
8670 return VINF_SUCCESS;
8671 }
8672
8673 Assert(pVCpu);
8674 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8675 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8676
8677 VMMRZCallRing3Disable(pVCpu);
8678 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8679
8680 Log4Func(("-> hmR0VmxLongJmpToRing3 enmOperation=%d\n", enmOperation));
8681
8682 int rc = hmR0VmxLongJmpToRing3(pVCpu);
8683 AssertRCReturn(rc, rc);
8684
8685 VMMRZCallRing3Enable(pVCpu);
8686 return VINF_SUCCESS;
8687}
8688
8689
8690/**
8691 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8692 * stack.
8693 *
8694 * @returns Strict VBox status code (i.e. informational status codes too).
8695 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8696 * @param pVCpu The cross context virtual CPU structure.
8697 * @param uValue The value to push to the guest stack.
8698 */
8699static VBOXSTRICTRC hmR0VmxRealModeGuestStackPush(PVMCPUCC pVCpu, uint16_t uValue)
8700{
8701 /*
8702 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8703 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8704 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8705 */
8706 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8707 if (pCtx->sp == 1)
8708 return VINF_EM_RESET;
8709 pCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8710 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pCtx->ss.u64Base + pCtx->sp, &uValue, sizeof(uint16_t));
8711 AssertRC(rc);
8712 return rc;
8713}
8714
8715
8716/**
8717 * Injects an event into the guest upon VM-entry by updating the relevant fields
8718 * in the VM-entry area in the VMCS.
8719 *
8720 * @returns Strict VBox status code (i.e. informational status codes too).
8721 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8722 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8723 *
8724 * @param pVCpu The cross context virtual CPU structure.
8725 * @param pVmxTransient The VMX-transient structure.
8726 * @param pEvent The event being injected.
8727 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
8728 * will be updated if necessary. This cannot not be NULL.
8729 * @param fStepping Whether we're single-stepping guest execution and should
8730 * return VINF_EM_DBG_STEPPED if the event is injected
8731 * directly (registers modified by us, not by hardware on
8732 * VM-entry).
8733 */
8734static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PCHMEVENT pEvent, bool fStepping,
8735 uint32_t *pfIntrState)
8736{
8737 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8738 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
8739 Assert(pfIntrState);
8740
8741 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8742 uint32_t u32IntInfo = pEvent->u64IntInfo;
8743 uint32_t const u32ErrCode = pEvent->u32ErrCode;
8744 uint32_t const cbInstr = pEvent->cbInstr;
8745 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
8746 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
8747 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
8748
8749#ifdef VBOX_STRICT
8750 /*
8751 * Validate the error-code-valid bit for hardware exceptions.
8752 * No error codes for exceptions in real-mode.
8753 *
8754 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8755 */
8756 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8757 && !CPUMIsGuestInRealModeEx(pCtx))
8758 {
8759 switch (uVector)
8760 {
8761 case X86_XCPT_PF:
8762 case X86_XCPT_DF:
8763 case X86_XCPT_TS:
8764 case X86_XCPT_NP:
8765 case X86_XCPT_SS:
8766 case X86_XCPT_GP:
8767 case X86_XCPT_AC:
8768 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
8769 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8770 RT_FALL_THRU();
8771 default:
8772 break;
8773 }
8774 }
8775
8776 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8777 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
8778 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8779#endif
8780
8781 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8782 || uIntType == VMX_EXIT_INT_INFO_TYPE_NMI
8783 || uIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT
8784 || uIntType == VMX_EXIT_INT_INFO_TYPE_SW_XCPT)
8785 {
8786 Assert(uVector <= X86_XCPT_LAST);
8787 Assert(uIntType != VMX_EXIT_INT_INFO_TYPE_NMI || uVector == X86_XCPT_NMI);
8788 Assert(uIntType != VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT || uVector == X86_XCPT_DB);
8789 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedXcptsR0[uVector]);
8790 }
8791 else
8792 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
8793
8794 /*
8795 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
8796 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
8797 * interrupt handler in the (real-mode) guest.
8798 *
8799 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
8800 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8801 */
8802 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
8803 {
8804 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest)
8805 {
8806 /*
8807 * For CPUs with unrestricted guest execution enabled and with the guest
8808 * in real-mode, we must not set the deliver-error-code bit.
8809 *
8810 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8811 */
8812 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
8813 }
8814 else
8815 {
8816 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8817 Assert(PDMVmmDevHeapIsEnabled(pVM));
8818 Assert(pVM->hm.s.vmx.pRealModeTSS);
8819 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
8820
8821 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
8822 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8823 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
8824 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
8825 AssertRCReturn(rc2, rc2);
8826
8827 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8828 size_t const cbIdtEntry = sizeof(X86IDTR16);
8829 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
8830 {
8831 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8832 if (uVector == X86_XCPT_DF)
8833 return VINF_EM_RESET;
8834
8835 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
8836 No error codes for exceptions in real-mode. */
8837 if (uVector == X86_XCPT_GP)
8838 {
8839 uint32_t const uXcptDfInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
8840 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8841 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8842 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8843 HMEVENT EventXcptDf;
8844 RT_ZERO(EventXcptDf);
8845 EventXcptDf.u64IntInfo = uXcptDfInfo;
8846 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptDf, fStepping, pfIntrState);
8847 }
8848
8849 /*
8850 * If we're injecting an event with no valid IDT entry, inject a #GP.
8851 * No error codes for exceptions in real-mode.
8852 *
8853 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8854 */
8855 uint32_t const uXcptGpInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
8856 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8857 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8858 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8859 HMEVENT EventXcptGp;
8860 RT_ZERO(EventXcptGp);
8861 EventXcptGp.u64IntInfo = uXcptGpInfo;
8862 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptGp, fStepping, pfIntrState);
8863 }
8864
8865 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8866 uint16_t uGuestIp = pCtx->ip;
8867 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
8868 {
8869 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8870 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8871 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8872 }
8873 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
8874 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8875
8876 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8877 X86IDTR16 IdtEntry;
8878 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
8879 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8880 AssertRCReturn(rc2, rc2);
8881
8882 /* Construct the stack frame for the interrupt/exception handler. */
8883 VBOXSTRICTRC rcStrict;
8884 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->eflags.u32);
8885 if (rcStrict == VINF_SUCCESS)
8886 {
8887 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
8888 if (rcStrict == VINF_SUCCESS)
8889 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
8890 }
8891
8892 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8893 if (rcStrict == VINF_SUCCESS)
8894 {
8895 pCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8896 pCtx->rip = IdtEntry.offSel;
8897 pCtx->cs.Sel = IdtEntry.uSel;
8898 pCtx->cs.ValidSel = IdtEntry.uSel;
8899 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8900 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
8901 && uVector == X86_XCPT_PF)
8902 pCtx->cr2 = GCPtrFault;
8903
8904 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
8905 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8906 | HM_CHANGED_GUEST_RSP);
8907
8908 /*
8909 * If we delivered a hardware exception (other than an NMI) and if there was
8910 * block-by-STI in effect, we should clear it.
8911 */
8912 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8913 {
8914 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
8915 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
8916 Log4Func(("Clearing inhibition due to STI\n"));
8917 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
8918 }
8919
8920 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8921 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
8922
8923 /*
8924 * The event has been truly dispatched to the guest. Mark it as no longer pending so
8925 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
8926 */
8927 pVCpu->hm.s.Event.fPending = false;
8928
8929 /*
8930 * If we eventually support nested-guest execution without unrestricted guest execution,
8931 * we should set fInterceptEvents here.
8932 */
8933 Assert(!pVmxTransient->fIsNestedGuest);
8934
8935 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
8936 if (fStepping)
8937 rcStrict = VINF_EM_DBG_STEPPED;
8938 }
8939 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8940 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8941 return rcStrict;
8942 }
8943 }
8944
8945 /*
8946 * Validate.
8947 */
8948 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8949 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
8950
8951 /*
8952 * Inject the event into the VMCS.
8953 */
8954 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8955 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8956 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8957 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8958 AssertRC(rc);
8959
8960 /*
8961 * Update guest CR2 if this is a page-fault.
8962 */
8963 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
8964 pCtx->cr2 = GCPtrFault;
8965
8966 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
8967 return VINF_SUCCESS;
8968}
8969
8970
8971/**
8972 * Evaluates the event to be delivered to the guest and sets it as the pending
8973 * event.
8974 *
8975 * Toggling of interrupt force-flags here is safe since we update TRPM on premature
8976 * exits to ring-3 before executing guest code, see hmR0VmxExitToRing3(). We must
8977 * NOT restore these force-flags.
8978 *
8979 * @returns Strict VBox status code (i.e. informational status codes too).
8980 * @param pVCpu The cross context virtual CPU structure.
8981 * @param pVmxTransient The VMX-transient structure.
8982 * @param pfIntrState Where to store the VT-x guest-interruptibility state.
8983 */
8984static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
8985{
8986 Assert(pfIntrState);
8987 Assert(!TRPMHasTrap(pVCpu));
8988
8989 /*
8990 * Compute/update guest-interruptibility state related FFs.
8991 * The FFs will be used below while evaluating events to be injected.
8992 */
8993 *pfIntrState = hmR0VmxGetGuestIntrStateAndUpdateFFs(pVCpu);
8994
8995 /*
8996 * Evaluate if a new event needs to be injected.
8997 * An event that's already pending has already performed all necessary checks.
8998 */
8999 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
9000 bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
9001 if ( !pVCpu->hm.s.Event.fPending
9002 && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
9003 {
9004 /** @todo SMI. SMIs take priority over NMIs. */
9005
9006 /*
9007 * NMIs.
9008 * NMIs take priority over external interrupts.
9009 */
9010 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9011 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
9012 {
9013 /*
9014 * For a guest, the FF always indicates the guest's ability to receive an NMI.
9015 *
9016 * For a nested-guest, the FF always indicates the outer guest's ability to
9017 * receive an NMI while the guest-interruptibility state bit depends on whether
9018 * the nested-hypervisor is using virtual-NMIs.
9019 */
9020 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
9021 {
9022#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9023 if ( fIsNestedGuest
9024 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_NMI_EXIT))
9025 return IEMExecVmxVmexitXcptNmi(pVCpu);
9026#endif
9027 hmR0VmxSetPendingXcptNmi(pVCpu);
9028 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
9029 Log4Func(("NMI pending injection\n"));
9030
9031 /* We've injected the NMI, bail. */
9032 return VINF_SUCCESS;
9033 }
9034 else if (!fIsNestedGuest)
9035 hmR0VmxSetNmiWindowExitVmcs(pVmcsInfo);
9036 }
9037
9038 /*
9039 * External interrupts (PIC/APIC).
9040 * Once PDMGetInterrupt() returns a valid interrupt we -must- deliver it.
9041 * We cannot re-request the interrupt from the controller again.
9042 */
9043 if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
9044 && !pVCpu->hm.s.fSingleInstruction)
9045 {
9046 Assert(!DBGFIsStepping(pVCpu));
9047 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
9048 AssertRC(rc);
9049
9050 /*
9051 * We must not check EFLAGS directly when executing a nested-guest, use
9052 * CPUMIsGuestPhysIntrEnabled() instead as EFLAGS.IF does not control the blocking of
9053 * external interrupts when "External interrupt exiting" is set. This fixes a nasty
9054 * SMP hang while executing nested-guest VCPUs on spinlocks which aren't rescued by
9055 * other VM-exits (like a preemption timer), see @bugref{9562#c18}.
9056 *
9057 * See Intel spec. 25.4.1 "Event Blocking".
9058 */
9059 if (CPUMIsGuestPhysIntrEnabled(pVCpu))
9060 {
9061#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9062 if ( fIsNestedGuest
9063 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
9064 {
9065 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
9066 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
9067 return rcStrict;
9068 }
9069#endif
9070 uint8_t u8Interrupt;
9071 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
9072 if (RT_SUCCESS(rc))
9073 {
9074#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9075 if ( fIsNestedGuest
9076 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
9077 {
9078 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
9079 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
9080 return rcStrict;
9081 }
9082#endif
9083 hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
9084 Log4Func(("External interrupt (%#x) pending injection\n", u8Interrupt));
9085 }
9086 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
9087 {
9088 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
9089
9090 if ( !fIsNestedGuest
9091 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
9092 hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
9093 /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
9094
9095 /*
9096 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
9097 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
9098 * need to re-set this force-flag here.
9099 */
9100 }
9101 else
9102 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
9103
9104 /* We've injected the interrupt or taken necessary action, bail. */
9105 return VINF_SUCCESS;
9106 }
9107 if (!fIsNestedGuest)
9108 hmR0VmxSetIntWindowExitVmcs(pVmcsInfo);
9109 }
9110 }
9111 else if (!fIsNestedGuest)
9112 {
9113 /*
9114 * An event is being injected or we are in an interrupt shadow. Check if another event is
9115 * pending. If so, instruct VT-x to cause a VM-exit as soon as the guest is ready to accept
9116 * the pending event.
9117 */
9118 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
9119 hmR0VmxSetNmiWindowExitVmcs(pVmcsInfo);
9120 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
9121 && !pVCpu->hm.s.fSingleInstruction)
9122 hmR0VmxSetIntWindowExitVmcs(pVmcsInfo);
9123 }
9124 /* else: for nested-guests, NMI/interrupt-window exiting will be picked up when merging VMCS controls. */
9125
9126 return VINF_SUCCESS;
9127}
9128
9129
9130/**
9131 * Injects any pending events into the guest if the guest is in a state to
9132 * receive them.
9133 *
9134 * @returns Strict VBox status code (i.e. informational status codes too).
9135 * @param pVCpu The cross context virtual CPU structure.
9136 * @param pVmxTransient The VMX-transient structure.
9137 * @param fIntrState The VT-x guest-interruptibility state.
9138 * @param fStepping Whether we are single-stepping the guest using the
9139 * hypervisor debugger and should return
9140 * VINF_EM_DBG_STEPPED if the event was dispatched
9141 * directly.
9142 */
9143static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t fIntrState, bool fStepping)
9144{
9145 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9146 Assert(VMMRZCallRing3IsEnabled(pVCpu));
9147
9148#ifdef VBOX_STRICT
9149 /*
9150 * Verify guest-interruptibility state.
9151 *
9152 * We put this in a scoped block so we do not accidentally use fBlockSti or fBlockMovSS,
9153 * since injecting an event may modify the interruptibility state and we must thus always
9154 * use fIntrState.
9155 */
9156 {
9157 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
9158 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
9159 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
9160 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
9161 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
9162 Assert(!TRPMHasTrap(pVCpu));
9163 NOREF(fBlockMovSS); NOREF(fBlockSti);
9164 }
9165#endif
9166
9167 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
9168 if (pVCpu->hm.s.Event.fPending)
9169 {
9170 /*
9171 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
9172 * pending even while injecting an event and in this case, we want a VM-exit as soon as
9173 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
9174 *
9175 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
9176 */
9177 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
9178#ifdef VBOX_STRICT
9179 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
9180 {
9181 Assert(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_IF);
9182 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
9183 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
9184 }
9185 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
9186 {
9187 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI));
9188 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
9189 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
9190 }
9191#endif
9192 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
9193 uIntType));
9194
9195 /*
9196 * Inject the event and get any changes to the guest-interruptibility state.
9197 *
9198 * The guest-interruptibility state may need to be updated if we inject the event
9199 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
9200 */
9201 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &pVCpu->hm.s.Event, fStepping, &fIntrState);
9202 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
9203
9204 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
9205 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
9206 else
9207 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
9208 }
9209
9210 /*
9211 * Deliver any pending debug exceptions if the guest is single-stepping using EFLAGS.TF and
9212 * is an interrupt shadow (block-by-STI or block-by-MOV SS).
9213 */
9214 if ( (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
9215 && !pVmxTransient->fIsNestedGuest)
9216 {
9217 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
9218
9219 if (!pVCpu->hm.s.fSingleInstruction)
9220 {
9221 /*
9222 * Set or clear the BS bit depending on whether the trap flag is active or not. We need
9223 * to do both since we clear the BS bit from the VMCS while exiting to ring-3.
9224 */
9225 Assert(!DBGFIsStepping(pVCpu));
9226 uint8_t const fTrapFlag = !!(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_TF);
9227 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, fTrapFlag << VMX_BF_VMCS_PENDING_DBG_XCPT_BS_SHIFT);
9228 AssertRC(rc);
9229 }
9230 else
9231 {
9232 /*
9233 * We must not deliver a debug exception when single-stepping over STI/Mov-SS in the
9234 * hypervisor debugger using EFLAGS.TF but rather clear interrupt inhibition. However,
9235 * we take care of this case in hmR0VmxExportSharedDebugState and also the case if
9236 * we use MTF, so just make sure it's called before executing guest-code.
9237 */
9238 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR_MASK);
9239 }
9240 }
9241 /* else: for nested-guest currently handling while merging controls. */
9242
9243 /*
9244 * Finally, update the guest-interruptibility state.
9245 *
9246 * This is required for the real-on-v86 software interrupt injection, for
9247 * pending debug exceptions as well as updates to the guest state from ring-3 (IEM).
9248 */
9249 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
9250 AssertRC(rc);
9251
9252 /*
9253 * There's no need to clear the VM-entry interruption-information field here if we're not
9254 * injecting anything. VT-x clears the valid bit on every VM-exit.
9255 *
9256 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
9257 */
9258
9259 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
9260 return rcStrict;
9261}
9262
9263
9264/**
9265 * Enters the VT-x session.
9266 *
9267 * @returns VBox status code.
9268 * @param pVCpu The cross context virtual CPU structure.
9269 */
9270VMMR0DECL(int) VMXR0Enter(PVMCPUCC pVCpu)
9271{
9272 AssertPtr(pVCpu);
9273 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported);
9274 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9275
9276 LogFlowFunc(("pVCpu=%p\n", pVCpu));
9277 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9278 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
9279
9280#ifdef VBOX_STRICT
9281 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
9282 RTCCUINTREG uHostCr4 = ASMGetCR4();
9283 if (!(uHostCr4 & X86_CR4_VMXE))
9284 {
9285 LogRelFunc(("X86_CR4_VMXE bit in CR4 is not set!\n"));
9286 return VERR_VMX_X86_CR4_VMXE_CLEARED;
9287 }
9288#endif
9289
9290 /*
9291 * Load the appropriate VMCS as the current and active one.
9292 */
9293 PVMXVMCSINFO pVmcsInfo;
9294 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx);
9295 if (!fInNestedGuestMode)
9296 pVmcsInfo = &pVCpu->hmr0.s.vmx.VmcsInfo;
9297 else
9298 pVmcsInfo = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
9299 int rc = hmR0VmxLoadVmcs(pVmcsInfo);
9300 if (RT_SUCCESS(rc))
9301 {
9302 pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs = fInNestedGuestMode;
9303 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcsCopyForRing3 = fInNestedGuestMode;
9304 pVCpu->hmr0.s.fLeaveDone = false;
9305 Log4Func(("Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
9306
9307 /*
9308 * Do the EMT scheduled L1D flush here if needed.
9309 */
9310 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
9311 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
9312 else if (pVCpu->CTX_SUFF(pVM)->hm.s.fMdsClearOnSched)
9313 hmR0MdsClear();
9314 }
9315 return rc;
9316}
9317
9318
9319/**
9320 * The thread-context callback (only on platforms which support it).
9321 *
9322 * @param enmEvent The thread-context event.
9323 * @param pVCpu The cross context virtual CPU structure.
9324 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
9325 * @thread EMT(pVCpu)
9326 */
9327VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit)
9328{
9329 AssertPtr(pVCpu);
9330 RT_NOREF1(fGlobalInit);
9331
9332 switch (enmEvent)
9333 {
9334 case RTTHREADCTXEVENT_OUT:
9335 {
9336 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9337 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
9338 VMCPU_ASSERT_EMT(pVCpu);
9339
9340 /* No longjmps (logger flushes, locks) in this fragile context. */
9341 VMMRZCallRing3Disable(pVCpu);
9342 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
9343
9344 /* Restore host-state (FPU, debug etc.) */
9345 if (!pVCpu->hmr0.s.fLeaveDone)
9346 {
9347 /*
9348 * Do -not- import the guest-state here as we might already be in the middle of importing
9349 * it, esp. bad if we're holding the PGM lock, see comment in hmR0VmxImportGuestState().
9350 */
9351 hmR0VmxLeave(pVCpu, false /* fImportState */);
9352 pVCpu->hmr0.s.fLeaveDone = true;
9353 }
9354
9355 /* Leave HM context, takes care of local init (term). */
9356 int rc = HMR0LeaveCpu(pVCpu);
9357 AssertRC(rc);
9358
9359 /* Restore longjmp state. */
9360 VMMRZCallRing3Enable(pVCpu);
9361 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
9362 break;
9363 }
9364
9365 case RTTHREADCTXEVENT_IN:
9366 {
9367 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9368 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
9369 VMCPU_ASSERT_EMT(pVCpu);
9370
9371 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
9372 VMMRZCallRing3Disable(pVCpu);
9373 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
9374
9375 /* Initialize the bare minimum state required for HM. This takes care of
9376 initializing VT-x if necessary (onlined CPUs, local init etc.) */
9377 int rc = hmR0EnterCpu(pVCpu);
9378 AssertRC(rc);
9379 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9380 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
9381
9382 /* Load the active VMCS as the current one. */
9383 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
9384 rc = hmR0VmxLoadVmcs(pVmcsInfo);
9385 AssertRC(rc);
9386 Log4Func(("Resumed: Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
9387 pVCpu->hmr0.s.fLeaveDone = false;
9388
9389 /* Do the EMT scheduled L1D flush if needed. */
9390 if (pVCpu->CTX_SUFF(pVM)->hm.s.fL1dFlushOnSched)
9391 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
9392
9393 /* Restore longjmp state. */
9394 VMMRZCallRing3Enable(pVCpu);
9395 break;
9396 }
9397
9398 default:
9399 break;
9400 }
9401}
9402
9403
9404/**
9405 * Exports the host state into the VMCS host-state area.
9406 * Sets up the VM-exit MSR-load area.
9407 *
9408 * The CPU state will be loaded from these fields on every successful VM-exit.
9409 *
9410 * @returns VBox status code.
9411 * @param pVCpu The cross context virtual CPU structure.
9412 *
9413 * @remarks No-long-jump zone!!!
9414 */
9415static int hmR0VmxExportHostState(PVMCPUCC pVCpu)
9416{
9417 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9418
9419 int rc = VINF_SUCCESS;
9420 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
9421 {
9422 uint64_t uHostCr4 = hmR0VmxExportHostControlRegs();
9423
9424 rc = hmR0VmxExportHostSegmentRegs(pVCpu, uHostCr4);
9425 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9426
9427 hmR0VmxExportHostMsrs(pVCpu);
9428
9429 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_HOST_CONTEXT;
9430 }
9431 return rc;
9432}
9433
9434
9435/**
9436 * Saves the host state in the VMCS host-state.
9437 *
9438 * @returns VBox status code.
9439 * @param pVCpu The cross context virtual CPU structure.
9440 *
9441 * @remarks No-long-jump zone!!!
9442 */
9443VMMR0DECL(int) VMXR0ExportHostState(PVMCPUCC pVCpu)
9444{
9445 AssertPtr(pVCpu);
9446 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9447
9448 /*
9449 * Export the host state here while entering HM context.
9450 * When thread-context hooks are used, we might get preempted and have to re-save the host
9451 * state but most of the time we won't be, so do it here before we disable interrupts.
9452 */
9453 return hmR0VmxExportHostState(pVCpu);
9454}
9455
9456
9457/**
9458 * Exports the guest state into the VMCS guest-state area.
9459 *
9460 * The will typically be done before VM-entry when the guest-CPU state and the
9461 * VMCS state may potentially be out of sync.
9462 *
9463 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
9464 * VM-entry controls.
9465 * Sets up the appropriate VMX non-root function to execute guest code based on
9466 * the guest CPU mode.
9467 *
9468 * @returns VBox strict status code.
9469 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9470 * without unrestricted guest execution and the VMMDev is not presently
9471 * mapped (e.g. EFI32).
9472 *
9473 * @param pVCpu The cross context virtual CPU structure.
9474 * @param pVmxTransient The VMX-transient structure.
9475 *
9476 * @remarks No-long-jump zone!!!
9477 */
9478static VBOXSTRICTRC hmR0VmxExportGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9479{
9480 AssertPtr(pVCpu);
9481 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9482 LogFlowFunc(("pVCpu=%p\n", pVCpu));
9483
9484 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExportGuestState, x);
9485
9486 /*
9487 * Determine real-on-v86 mode.
9488 * Used when the guest is in real-mode and unrestricted guest execution is not used.
9489 */
9490 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmxTransient->pVmcsInfo->pShared;
9491 if ( pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest
9492 || !CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx))
9493 pVmcsInfoShared->RealMode.fRealOnV86Active = false;
9494 else
9495 {
9496 Assert(!pVmxTransient->fIsNestedGuest);
9497 pVmcsInfoShared->RealMode.fRealOnV86Active = true;
9498 }
9499
9500 /*
9501 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
9502 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
9503 */
9504 int rc = hmR0VmxExportGuestEntryExitCtls(pVCpu, pVmxTransient);
9505 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9506
9507 rc = hmR0VmxExportGuestCR0(pVCpu, pVmxTransient);
9508 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9509
9510 VBOXSTRICTRC rcStrict = hmR0VmxExportGuestCR3AndCR4(pVCpu, pVmxTransient);
9511 if (rcStrict == VINF_SUCCESS)
9512 { /* likely */ }
9513 else
9514 {
9515 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
9516 return rcStrict;
9517 }
9518
9519 rc = hmR0VmxExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
9520 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9521
9522 rc = hmR0VmxExportGuestMsrs(pVCpu, pVmxTransient);
9523 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9524
9525 hmR0VmxExportGuestApicTpr(pVCpu, pVmxTransient);
9526 hmR0VmxExportGuestXcptIntercepts(pVCpu, pVmxTransient);
9527 hmR0VmxExportGuestRip(pVCpu);
9528 hmR0VmxExportGuestRsp(pVCpu);
9529 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9530
9531 rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9532 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9533
9534 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
9535 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~( (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
9536 | HM_CHANGED_GUEST_CR2
9537 | (HM_CHANGED_GUEST_DR_MASK & ~HM_CHANGED_GUEST_DR7)
9538 | HM_CHANGED_GUEST_X87
9539 | HM_CHANGED_GUEST_SSE_AVX
9540 | HM_CHANGED_GUEST_OTHER_XSAVE
9541 | HM_CHANGED_GUEST_XCRx
9542 | HM_CHANGED_GUEST_KERNEL_GS_BASE /* Part of lazy or auto load-store MSRs. */
9543 | HM_CHANGED_GUEST_SYSCALL_MSRS /* Part of lazy or auto load-store MSRs. */
9544 | HM_CHANGED_GUEST_TSC_AUX
9545 | HM_CHANGED_GUEST_OTHER_MSRS
9546 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
9547
9548 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExportGuestState, x);
9549 return rc;
9550}
9551
9552
9553/**
9554 * Exports the state shared between the host and guest into the VMCS.
9555 *
9556 * @param pVCpu The cross context virtual CPU structure.
9557 * @param pVmxTransient The VMX-transient structure.
9558 *
9559 * @remarks No-long-jump zone!!!
9560 */
9561static void hmR0VmxExportSharedState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9562{
9563 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9564 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9565
9566 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_DR_MASK)
9567 {
9568 int rc = hmR0VmxExportSharedDebugState(pVCpu, pVmxTransient);
9569 AssertRC(rc);
9570 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_GUEST_DR_MASK;
9571
9572 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
9573 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_RFLAGS)
9574 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9575 }
9576
9577 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_GUEST_LAZY_MSRS)
9578 {
9579 hmR0VmxLazyLoadGuestMsrs(pVCpu);
9580 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_VMX_GUEST_LAZY_MSRS;
9581 }
9582
9583 AssertMsg(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE),
9584 ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
9585}
9586
9587
9588/**
9589 * Worker for loading the guest-state bits in the inner VT-x execution loop.
9590 *
9591 * @returns Strict VBox status code (i.e. informational status codes too).
9592 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9593 * without unrestricted guest execution and the VMMDev is not presently
9594 * mapped (e.g. EFI32).
9595 *
9596 * @param pVCpu The cross context virtual CPU structure.
9597 * @param pVmxTransient The VMX-transient structure.
9598 *
9599 * @remarks No-long-jump zone!!!
9600 */
9601static VBOXSTRICTRC hmR0VmxExportGuestStateOptimal(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9602{
9603 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9604 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9605 Assert(VMMR0IsLogFlushDisabled(pVCpu));
9606
9607#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
9608 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
9609#endif
9610
9611 /*
9612 * For many VM-exits only RIP/RSP/RFLAGS (and HWVIRT state when executing a nested-guest)
9613 * changes. First try to export only these without going through all other changed-flag checks.
9614 */
9615 VBOXSTRICTRC rcStrict;
9616 uint64_t const fCtxMask = HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE;
9617 uint64_t const fMinimalMask = HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT;
9618 uint64_t const fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9619
9620 /* If only RIP/RSP/RFLAGS/HWVIRT changed, export only those (quicker, happens more often).*/
9621 if ( (fCtxChanged & fMinimalMask)
9622 && !(fCtxChanged & (fCtxMask & ~fMinimalMask)))
9623 {
9624 hmR0VmxExportGuestRip(pVCpu);
9625 hmR0VmxExportGuestRsp(pVCpu);
9626 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9627 rcStrict = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9628 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportMinimal);
9629 }
9630 /* If anything else also changed, go through the full export routine and export as required. */
9631 else if (fCtxChanged & fCtxMask)
9632 {
9633 rcStrict = hmR0VmxExportGuestState(pVCpu, pVmxTransient);
9634 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9635 { /* likely */}
9636 else
9637 {
9638 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM, ("Failed to export guest state! rc=%Rrc\n",
9639 VBOXSTRICTRC_VAL(rcStrict)));
9640 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9641 return rcStrict;
9642 }
9643 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportFull);
9644 }
9645 /* Nothing changed, nothing to load here. */
9646 else
9647 rcStrict = VINF_SUCCESS;
9648
9649#ifdef VBOX_STRICT
9650 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
9651 uint64_t const fCtxChangedCur = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9652 AssertMsg(!(fCtxChangedCur & fCtxMask), ("fCtxChangedCur=%#RX64\n", fCtxChangedCur));
9653#endif
9654 return rcStrict;
9655}
9656
9657
9658/**
9659 * Tries to determine what part of the guest-state VT-x has deemed as invalid
9660 * and update error record fields accordingly.
9661 *
9662 * @returns VMX_IGS_* error codes.
9663 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
9664 * wrong with the guest state.
9665 *
9666 * @param pVCpu The cross context virtual CPU structure.
9667 * @param pVmcsInfo The VMCS info. object.
9668 *
9669 * @remarks This function assumes our cache of the VMCS controls
9670 * are valid, i.e. hmR0VmxCheckCachedVmcsCtls() succeeded.
9671 */
9672static uint32_t hmR0VmxCheckGuestState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
9673{
9674#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
9675#define HMVMX_CHECK_BREAK(expr, err) do { \
9676 if (!(expr)) { uError = (err); break; } \
9677 } while (0)
9678
9679 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9680 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9681 uint32_t uError = VMX_IGS_ERROR;
9682 uint32_t u32IntrState = 0;
9683 bool const fUnrestrictedGuest = pVM->hmr0.s.vmx.fUnrestrictedGuest;
9684 do
9685 {
9686 int rc;
9687
9688 /*
9689 * Guest-interruptibility state.
9690 *
9691 * Read this first so that any check that fails prior to those that actually
9692 * require the guest-interruptibility state would still reflect the correct
9693 * VMCS value and avoids causing further confusion.
9694 */
9695 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
9696 AssertRC(rc);
9697
9698 uint32_t u32Val;
9699 uint64_t u64Val;
9700
9701 /*
9702 * CR0.
9703 */
9704 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9705 uint64_t fSetCr0 = (g_HmMsrs.u.vmx.u64Cr0Fixed0 & g_HmMsrs.u.vmx.u64Cr0Fixed1);
9706 uint64_t const fZapCr0 = (g_HmMsrs.u.vmx.u64Cr0Fixed0 | g_HmMsrs.u.vmx.u64Cr0Fixed1);
9707 /* Exceptions for unrestricted guest execution for CR0 fixed bits (PE, PG).
9708 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
9709 if (fUnrestrictedGuest)
9710 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
9711
9712 uint64_t u64GuestCr0;
9713 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64GuestCr0);
9714 AssertRC(rc);
9715 HMVMX_CHECK_BREAK((u64GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
9716 HMVMX_CHECK_BREAK(!(u64GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
9717 if ( !fUnrestrictedGuest
9718 && (u64GuestCr0 & X86_CR0_PG)
9719 && !(u64GuestCr0 & X86_CR0_PE))
9720 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
9721
9722 /*
9723 * CR4.
9724 */
9725 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9726 uint64_t const fSetCr4 = (g_HmMsrs.u.vmx.u64Cr4Fixed0 & g_HmMsrs.u.vmx.u64Cr4Fixed1);
9727 uint64_t const fZapCr4 = (g_HmMsrs.u.vmx.u64Cr4Fixed0 | g_HmMsrs.u.vmx.u64Cr4Fixed1);
9728
9729 uint64_t u64GuestCr4;
9730 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64GuestCr4);
9731 AssertRC(rc);
9732 HMVMX_CHECK_BREAK((u64GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
9733 HMVMX_CHECK_BREAK(!(u64GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
9734
9735 /*
9736 * IA32_DEBUGCTL MSR.
9737 */
9738 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
9739 AssertRC(rc);
9740 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9741 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
9742 {
9743 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
9744 }
9745 uint64_t u64DebugCtlMsr = u64Val;
9746
9747#ifdef VBOX_STRICT
9748 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
9749 AssertRC(rc);
9750 Assert(u32Val == pVmcsInfo->u32EntryCtls);
9751#endif
9752 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
9753
9754 /*
9755 * RIP and RFLAGS.
9756 */
9757 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
9758 AssertRC(rc);
9759 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
9760 if ( !fLongModeGuest
9761 || !pCtx->cs.Attr.n.u1Long)
9762 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
9763 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
9764 * must be identical if the "IA-32e mode guest" VM-entry
9765 * control is 1 and CS.L is 1. No check applies if the
9766 * CPU supports 64 linear-address bits. */
9767
9768 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
9769 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
9770 AssertRC(rc);
9771 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
9772 VMX_IGS_RFLAGS_RESERVED);
9773 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
9774 uint32_t const u32Eflags = u64Val;
9775
9776 if ( fLongModeGuest
9777 || ( fUnrestrictedGuest
9778 && !(u64GuestCr0 & X86_CR0_PE)))
9779 {
9780 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
9781 }
9782
9783 uint32_t u32EntryInfo;
9784 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
9785 AssertRC(rc);
9786 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9787 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
9788
9789 /*
9790 * 64-bit checks.
9791 */
9792 if (fLongModeGuest)
9793 {
9794 HMVMX_CHECK_BREAK(u64GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
9795 HMVMX_CHECK_BREAK(u64GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
9796 }
9797
9798 if ( !fLongModeGuest
9799 && (u64GuestCr4 & X86_CR4_PCIDE))
9800 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
9801
9802 /** @todo CR3 field must be such that bits 63:52 and bits in the range
9803 * 51:32 beyond the processor's physical-address width are 0. */
9804
9805 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9806 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
9807 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
9808
9809 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
9810 AssertRC(rc);
9811 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
9812
9813 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
9814 AssertRC(rc);
9815 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
9816
9817 /*
9818 * PERF_GLOBAL MSR.
9819 */
9820 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
9821 {
9822 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
9823 AssertRC(rc);
9824 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
9825 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
9826 }
9827
9828 /*
9829 * PAT MSR.
9830 */
9831 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
9832 {
9833 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
9834 AssertRC(rc);
9835 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
9836 for (unsigned i = 0; i < 8; i++)
9837 {
9838 uint8_t u8Val = (u64Val & 0xff);
9839 if ( u8Val != 0 /* UC */
9840 && u8Val != 1 /* WC */
9841 && u8Val != 4 /* WT */
9842 && u8Val != 5 /* WP */
9843 && u8Val != 6 /* WB */
9844 && u8Val != 7 /* UC- */)
9845 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
9846 u64Val >>= 8;
9847 }
9848 }
9849
9850 /*
9851 * EFER MSR.
9852 */
9853 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
9854 {
9855 Assert(pVM->hm.s.vmx.fSupportsVmcsEfer);
9856 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
9857 AssertRC(rc);
9858 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
9859 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
9860 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
9861 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
9862 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
9863 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
9864 * iemVmxVmentryCheckGuestState(). */
9865 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9866 || !(u64GuestCr0 & X86_CR0_PG)
9867 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
9868 VMX_IGS_EFER_LMA_LME_MISMATCH);
9869 }
9870
9871 /*
9872 * Segment registers.
9873 */
9874 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9875 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
9876 if (!(u32Eflags & X86_EFL_VM))
9877 {
9878 /* CS */
9879 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
9880 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
9881 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
9882 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
9883 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9884 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
9885 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9886 /* CS cannot be loaded with NULL in protected mode. */
9887 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
9888 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
9889 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
9890 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
9891 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
9892 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
9893 else if (fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
9894 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
9895 else
9896 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
9897
9898 /* SS */
9899 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9900 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
9901 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
9902 if ( !(pCtx->cr0 & X86_CR0_PE)
9903 || pCtx->cs.Attr.n.u4Type == 3)
9904 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
9905
9906 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
9907 {
9908 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
9909 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
9910 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
9911 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
9912 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
9913 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9914 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
9915 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9916 }
9917
9918 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSReg(). */
9919 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
9920 {
9921 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
9922 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
9923 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9924 || pCtx->ds.Attr.n.u4Type > 11
9925 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9926 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
9927 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
9928 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
9929 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9930 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
9931 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9932 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9933 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
9934 }
9935 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
9936 {
9937 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
9938 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
9939 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9940 || pCtx->es.Attr.n.u4Type > 11
9941 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9942 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
9943 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
9944 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
9945 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9946 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
9947 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9948 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9949 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
9950 }
9951 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
9952 {
9953 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
9954 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
9955 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9956 || pCtx->fs.Attr.n.u4Type > 11
9957 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
9958 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
9959 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
9960 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
9961 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9962 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
9963 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9964 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9965 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
9966 }
9967 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
9968 {
9969 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
9970 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
9971 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9972 || pCtx->gs.Attr.n.u4Type > 11
9973 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
9974 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
9975 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
9976 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
9977 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9978 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
9979 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
9980 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9981 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
9982 }
9983 /* 64-bit capable CPUs. */
9984 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
9985 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
9986 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9987 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
9988 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
9989 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
9990 VMX_IGS_LONGMODE_SS_BASE_INVALID);
9991 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
9992 VMX_IGS_LONGMODE_DS_BASE_INVALID);
9993 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
9994 VMX_IGS_LONGMODE_ES_BASE_INVALID);
9995 }
9996 else
9997 {
9998 /* V86 mode checks. */
9999 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
10000 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
10001 {
10002 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
10003 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
10004 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
10005 }
10006 else
10007 {
10008 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
10009 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
10010 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
10011 }
10012
10013 /* CS */
10014 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
10015 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
10016 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
10017 /* SS */
10018 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
10019 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
10020 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
10021 /* DS */
10022 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
10023 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
10024 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
10025 /* ES */
10026 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
10027 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
10028 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
10029 /* FS */
10030 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
10031 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
10032 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
10033 /* GS */
10034 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
10035 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
10036 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
10037 /* 64-bit capable CPUs. */
10038 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10039 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10040 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10041 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10042 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10043 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
10044 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10045 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
10046 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10047 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
10048 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10049 }
10050
10051 /*
10052 * TR.
10053 */
10054 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
10055 /* 64-bit capable CPUs. */
10056 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
10057 if (fLongModeGuest)
10058 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
10059 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
10060 else
10061 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
10062 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
10063 VMX_IGS_TR_ATTR_TYPE_INVALID);
10064 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
10065 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
10066 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
10067 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
10068 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
10069 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
10070 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
10071 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
10072
10073 /*
10074 * GDTR and IDTR (64-bit capable checks).
10075 */
10076 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
10077 AssertRC(rc);
10078 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
10079
10080 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
10081 AssertRC(rc);
10082 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
10083
10084 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
10085 AssertRC(rc);
10086 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
10087
10088 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
10089 AssertRC(rc);
10090 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
10091
10092 /*
10093 * Guest Non-Register State.
10094 */
10095 /* Activity State. */
10096 uint32_t u32ActivityState;
10097 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
10098 AssertRC(rc);
10099 HMVMX_CHECK_BREAK( !u32ActivityState
10100 || (u32ActivityState & RT_BF_GET(g_HmMsrs.u.vmx.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
10101 VMX_IGS_ACTIVITY_STATE_INVALID);
10102 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
10103 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
10104
10105 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
10106 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10107 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
10108
10109 /** @todo Activity state and injecting interrupts. Left as a todo since we
10110 * currently don't use activity states but ACTIVE. */
10111
10112 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
10113 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
10114
10115 /* Guest interruptibility-state. */
10116 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
10117 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
10118 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10119 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
10120 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
10121 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
10122 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
10123 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
10124 {
10125 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10126 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10127 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
10128 }
10129 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
10130 {
10131 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10132 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
10133 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
10134 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
10135 }
10136 /** @todo Assumes the processor is not in SMM. */
10137 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
10138 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
10139 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
10140 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
10141 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
10142 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
10143 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
10144 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI), VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
10145
10146 /* Pending debug exceptions. */
10147 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
10148 AssertRC(rc);
10149 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
10150 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
10151 u32Val = u64Val; /* For pending debug exceptions checks below. */
10152
10153 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10154 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
10155 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
10156 {
10157 if ( (u32Eflags & X86_EFL_TF)
10158 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
10159 {
10160 /* Bit 14 is PendingDebug.BS. */
10161 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
10162 }
10163 if ( !(u32Eflags & X86_EFL_TF)
10164 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
10165 {
10166 /* Bit 14 is PendingDebug.BS. */
10167 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
10168 }
10169 }
10170
10171 /* VMCS link pointer. */
10172 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
10173 AssertRC(rc);
10174 if (u64Val != UINT64_C(0xffffffffffffffff))
10175 {
10176 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
10177 /** @todo Bits beyond the processor's physical-address width MBZ. */
10178 /** @todo SMM checks. */
10179 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
10180 Assert(pVmcsInfo->pvShadowVmcs);
10181 VMXVMCSREVID VmcsRevId;
10182 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
10183 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID),
10184 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
10185 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
10186 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
10187 }
10188
10189 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
10190 * not using nested paging? */
10191 if ( pVM->hmr0.s.fNestedPaging
10192 && !fLongModeGuest
10193 && CPUMIsGuestInPAEModeEx(pCtx))
10194 {
10195 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
10196 AssertRC(rc);
10197 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10198
10199 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
10200 AssertRC(rc);
10201 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10202
10203 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
10204 AssertRC(rc);
10205 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10206
10207 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
10208 AssertRC(rc);
10209 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10210 }
10211
10212 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
10213 if (uError == VMX_IGS_ERROR)
10214 uError = VMX_IGS_REASON_NOT_FOUND;
10215 } while (0);
10216
10217 pVCpu->hm.s.u32HMError = uError;
10218 pVCpu->hm.s.vmx.LastError.u32GuestIntrState = u32IntrState;
10219 return uError;
10220
10221#undef HMVMX_ERROR_BREAK
10222#undef HMVMX_CHECK_BREAK
10223}
10224
10225
10226/**
10227 * Map the APIC-access page for virtualizing APIC accesses.
10228 *
10229 * This can cause a longjumps to R3 due to the acquisition of the PGM lock. Hence,
10230 * this not done as part of exporting guest state, see @bugref{8721}.
10231 *
10232 * @returns VBox status code.
10233 * @param pVCpu The cross context virtual CPU structure.
10234 */
10235static int hmR0VmxMapHCApicAccessPage(PVMCPUCC pVCpu)
10236{
10237 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10238 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
10239
10240 Assert(PDMHasApic(pVM));
10241 Assert(u64MsrApicBase);
10242
10243 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
10244 Log4Func(("Mappping HC APIC-access page at %#RGp\n", GCPhysApicBase));
10245
10246 /* Unalias the existing mapping. */
10247 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
10248 AssertRCReturn(rc, rc);
10249
10250 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
10251 Assert(pVM->hmr0.s.vmx.HCPhysApicAccess != NIL_RTHCPHYS);
10252 rc = IOMR0MmioMapMmioHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hmr0.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
10253 AssertRCReturn(rc, rc);
10254
10255 /* Update the per-VCPU cache of the APIC base MSR. */
10256 pVCpu->hm.s.vmx.u64GstMsrApicBase = u64MsrApicBase;
10257 return VINF_SUCCESS;
10258}
10259
10260
10261/**
10262 * Worker function passed to RTMpOnSpecific() that is to be called on the target
10263 * CPU.
10264 *
10265 * @param idCpu The ID for the CPU the function is called on.
10266 * @param pvUser1 Null, not used.
10267 * @param pvUser2 Null, not used.
10268 */
10269static DECLCALLBACK(void) hmR0DispatchHostNmi(RTCPUID idCpu, void *pvUser1, void *pvUser2)
10270{
10271 RT_NOREF3(idCpu, pvUser1, pvUser2);
10272 VMXDispatchHostNmi();
10273}
10274
10275
10276/**
10277 * Dispatching an NMI on the host CPU that received it.
10278 *
10279 * @returns VBox status code.
10280 * @param pVCpu The cross context virtual CPU structure.
10281 * @param pVmcsInfo The VMCS info. object corresponding to the VMCS that was
10282 * executing when receiving the host NMI in VMX non-root
10283 * operation.
10284 */
10285static int hmR0VmxExitHostNmi(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
10286{
10287 RTCPUID const idCpu = pVmcsInfo->idHostCpuExec;
10288 Assert(idCpu != NIL_RTCPUID);
10289
10290 /*
10291 * We don't want to delay dispatching the NMI any more than we have to. However,
10292 * we have already chosen -not- to dispatch NMIs when interrupts were still disabled
10293 * after executing guest or nested-guest code for the following reasons:
10294 *
10295 * - We would need to perform VMREADs with interrupts disabled and is orders of
10296 * magnitude worse when we run as a nested hypervisor without VMCS shadowing
10297 * supported by the host hypervisor.
10298 *
10299 * - It affects the common VM-exit scenario and keeps interrupts disabled for a
10300 * longer period of time just for handling an edge case like host NMIs which do
10301 * not occur nearly as frequently as other VM-exits.
10302 *
10303 * Let's cover the most likely scenario first. Check if we are on the target CPU
10304 * and dispatch the NMI right away. This should be much faster than calling into
10305 * RTMpOnSpecific() machinery.
10306 */
10307 bool fDispatched = false;
10308 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
10309 if (idCpu == RTMpCpuId())
10310 {
10311 VMXDispatchHostNmi();
10312 fDispatched = true;
10313 }
10314 ASMSetFlags(fEFlags);
10315 if (fDispatched)
10316 {
10317 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
10318 return VINF_SUCCESS;
10319 }
10320
10321 /*
10322 * RTMpOnSpecific() waits until the worker function has run on the target CPU. So
10323 * there should be no race or recursion even if we are unlucky enough to be preempted
10324 * (to the target CPU) without dispatching the host NMI above.
10325 */
10326 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGCIpi);
10327 return RTMpOnSpecific(idCpu, &hmR0DispatchHostNmi, NULL /* pvUser1 */, NULL /* pvUser2 */);
10328}
10329
10330
10331#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10332/**
10333 * Merges the guest with the nested-guest MSR bitmap in preparation of executing the
10334 * nested-guest using hardware-assisted VMX.
10335 *
10336 * @param pVCpu The cross context virtual CPU structure.
10337 * @param pVmcsInfoNstGst The nested-guest VMCS info. object.
10338 * @param pVmcsInfoGst The guest VMCS info. object.
10339 */
10340static void hmR0VmxMergeMsrBitmapNested(PCVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
10341{
10342 uint32_t const cbMsrBitmap = X86_PAGE_4K_SIZE;
10343 uint64_t *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
10344 Assert(pu64MsrBitmap);
10345
10346 /*
10347 * We merge the guest MSR bitmap with the nested-guest MSR bitmap such that any
10348 * MSR that is intercepted by the guest is also intercepted while executing the
10349 * nested-guest using hardware-assisted VMX.
10350 *
10351 * Note! If the nested-guest is not using an MSR bitmap, every MSR must cause a
10352 * nested-guest VM-exit even if the outer guest is not intercepting some
10353 * MSRs. We cannot assume the caller has initialized the nested-guest
10354 * MSR bitmap in this case.
10355 *
10356 * The nested hypervisor may also switch whether it uses MSR bitmaps for
10357 * each of its VM-entry, hence initializing it once per-VM while setting
10358 * up the nested-guest VMCS is not sufficient.
10359 */
10360 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
10361 if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10362 {
10363 uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
10364 uint64_t const *pu64MsrBitmapGst = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
10365 Assert(pu64MsrBitmapNstGst);
10366 Assert(pu64MsrBitmapGst);
10367
10368 uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
10369 for (uint32_t i = 0; i < cFrags; i++)
10370 pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
10371 }
10372 else
10373 ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
10374}
10375
10376
10377/**
10378 * Merges the guest VMCS in to the nested-guest VMCS controls in preparation of
10379 * hardware-assisted VMX execution of the nested-guest.
10380 *
10381 * For a guest, we don't modify these controls once we set up the VMCS and hence
10382 * this function is never called.
10383 *
10384 * For nested-guests since the nested hypervisor provides these controls on every
10385 * nested-guest VM-entry and could potentially change them everytime we need to
10386 * merge them before every nested-guest VM-entry.
10387 *
10388 * @returns VBox status code.
10389 * @param pVCpu The cross context virtual CPU structure.
10390 */
10391static int hmR0VmxMergeVmcsNested(PVMCPUCC pVCpu)
10392{
10393 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10394 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
10395 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
10396 Assert(pVmcsNstGst);
10397
10398 /*
10399 * Merge the controls with the requirements of the guest VMCS.
10400 *
10401 * We do not need to validate the nested-guest VMX features specified in the nested-guest
10402 * VMCS with the features supported by the physical CPU as it's already done by the
10403 * VMLAUNCH/VMRESUME instruction emulation.
10404 *
10405 * This is because the VMX features exposed by CPUM (through CPUID/MSRs) to the guest are
10406 * derived from the VMX features supported by the physical CPU.
10407 */
10408
10409 /* Pin-based VM-execution controls. */
10410 uint32_t const u32PinCtls = pVmcsNstGst->u32PinCtls | pVmcsInfoGst->u32PinCtls;
10411
10412 /* Processor-based VM-execution controls. */
10413 uint32_t u32ProcCtls = (pVmcsNstGst->u32ProcCtls & ~VMX_PROC_CTLS_USE_IO_BITMAPS)
10414 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT
10415 | VMX_PROC_CTLS_NMI_WINDOW_EXIT
10416 | VMX_PROC_CTLS_USE_TPR_SHADOW
10417 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
10418
10419 /* Secondary processor-based VM-execution controls. */
10420 uint32_t const u32ProcCtls2 = (pVmcsNstGst->u32ProcCtls2 & ~VMX_PROC_CTLS2_VPID)
10421 | (pVmcsInfoGst->u32ProcCtls2 & ~( VMX_PROC_CTLS2_VIRT_APIC_ACCESS
10422 | VMX_PROC_CTLS2_INVPCID
10423 | VMX_PROC_CTLS2_VMCS_SHADOWING
10424 | VMX_PROC_CTLS2_RDTSCP
10425 | VMX_PROC_CTLS2_XSAVES_XRSTORS
10426 | VMX_PROC_CTLS2_APIC_REG_VIRT
10427 | VMX_PROC_CTLS2_VIRT_INT_DELIVERY
10428 | VMX_PROC_CTLS2_VMFUNC));
10429
10430 /*
10431 * VM-entry controls:
10432 * These controls contains state that depends on the nested-guest state (primarily
10433 * EFER MSR) and is thus not constant between VMLAUNCH/VMRESUME and the nested-guest
10434 * VM-exit. Although the nested hypervisor cannot change it, we need to in order to
10435 * properly continue executing the nested-guest if the EFER MSR changes but does not
10436 * cause a nested-guest VM-exits.
10437 *
10438 * VM-exit controls:
10439 * These controls specify the host state on return. We cannot use the controls from
10440 * the nested hypervisor state as is as it would contain the guest state rather than
10441 * the host state. Since the host state is subject to change (e.g. preemption, trips
10442 * to ring-3, longjmp and rescheduling to a different host CPU) they are not constant
10443 * through VMLAUNCH/VMRESUME and the nested-guest VM-exit.
10444 *
10445 * VM-entry MSR-load:
10446 * The guest MSRs from the VM-entry MSR-load area are already loaded into the guest-CPU
10447 * context by the VMLAUNCH/VMRESUME instruction emulation.
10448 *
10449 * VM-exit MSR-store:
10450 * The VM-exit emulation will take care of populating the MSRs from the guest-CPU context
10451 * back into the VM-exit MSR-store area.
10452 *
10453 * VM-exit MSR-load areas:
10454 * This must contain the real host MSRs with hardware-assisted VMX execution. Hence, we
10455 * can entirely ignore what the nested hypervisor wants to load here.
10456 */
10457
10458 /*
10459 * Exception bitmap.
10460 *
10461 * We could remove #UD from the guest bitmap and merge it with the nested-guest bitmap
10462 * here (and avoid doing anything while exporting nested-guest state), but to keep the
10463 * code more flexible if intercepting exceptions become more dynamic in the future we do
10464 * it as part of exporting the nested-guest state.
10465 */
10466 uint32_t const u32XcptBitmap = pVmcsNstGst->u32XcptBitmap | pVmcsInfoGst->u32XcptBitmap;
10467
10468 /*
10469 * CR0/CR4 guest/host mask.
10470 *
10471 * Modifications by the nested-guest to CR0/CR4 bits owned by the host and the guest must
10472 * cause VM-exits, so we need to merge them here.
10473 */
10474 uint64_t const u64Cr0Mask = pVmcsNstGst->u64Cr0Mask.u | pVmcsInfoGst->u64Cr0Mask;
10475 uint64_t const u64Cr4Mask = pVmcsNstGst->u64Cr4Mask.u | pVmcsInfoGst->u64Cr4Mask;
10476
10477 /*
10478 * Page-fault error-code mask and match.
10479 *
10480 * Although we require unrestricted guest execution (and thereby nested-paging) for
10481 * hardware-assisted VMX execution of nested-guests and thus the outer guest doesn't
10482 * normally intercept #PFs, it might intercept them for debugging purposes.
10483 *
10484 * If the outer guest is not intercepting #PFs, we can use the nested-guest #PF filters.
10485 * If the outer guest is intercepting #PFs, we must intercept all #PFs.
10486 */
10487 uint32_t u32XcptPFMask;
10488 uint32_t u32XcptPFMatch;
10489 if (!(pVmcsInfoGst->u32XcptBitmap & RT_BIT(X86_XCPT_PF)))
10490 {
10491 u32XcptPFMask = pVmcsNstGst->u32XcptPFMask;
10492 u32XcptPFMatch = pVmcsNstGst->u32XcptPFMatch;
10493 }
10494 else
10495 {
10496 u32XcptPFMask = 0;
10497 u32XcptPFMatch = 0;
10498 }
10499
10500 /*
10501 * Pause-Loop exiting.
10502 */
10503 /** @todo r=bird: given that both pVM->hm.s.vmx.cPleGapTicks and
10504 * pVM->hm.s.vmx.cPleWindowTicks defaults to zero, I cannot see how
10505 * this will work... */
10506 uint32_t const cPleGapTicks = RT_MIN(pVM->hm.s.vmx.cPleGapTicks, pVmcsNstGst->u32PleGap);
10507 uint32_t const cPleWindowTicks = RT_MIN(pVM->hm.s.vmx.cPleWindowTicks, pVmcsNstGst->u32PleWindow);
10508
10509 /*
10510 * Pending debug exceptions.
10511 * Currently just copy whatever the nested-guest provides us.
10512 */
10513 uint64_t const uPendingDbgXcpts = pVmcsNstGst->u64GuestPendingDbgXcpts.u;
10514
10515 /*
10516 * I/O Bitmap.
10517 *
10518 * We do not use the I/O bitmap that may be provided by the nested hypervisor as we always
10519 * intercept all I/O port accesses.
10520 */
10521 Assert(u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT);
10522 Assert(!(u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS));
10523
10524 /*
10525 * VMCS shadowing.
10526 *
10527 * We do not yet expose VMCS shadowing to the guest and thus VMCS shadowing should not be
10528 * enabled while executing the nested-guest.
10529 */
10530 Assert(!(u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING));
10531
10532 /*
10533 * APIC-access page.
10534 */
10535 RTHCPHYS HCPhysApicAccess;
10536 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10537 {
10538 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
10539 RTGCPHYS const GCPhysApicAccess = pVmcsNstGst->u64AddrApicAccess.u;
10540
10541 /** @todo NSTVMX: This is not really correct but currently is required to make
10542 * things work. We need to re-enable the page handler when we fallback to
10543 * IEM execution of the nested-guest! */
10544 PGMHandlerPhysicalPageTempOff(pVM, GCPhysApicAccess, GCPhysApicAccess);
10545
10546 void *pvPage;
10547 PGMPAGEMAPLOCK PgLockApicAccess;
10548 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysApicAccess, &pvPage, &PgLockApicAccess);
10549 if (RT_SUCCESS(rc))
10550 {
10551 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysApicAccess, &HCPhysApicAccess);
10552 AssertMsgRCReturn(rc, ("Failed to get host-physical address for APIC-access page at %#RGp\n", GCPhysApicAccess), rc);
10553
10554 /** @todo Handle proper releasing of page-mapping lock later. */
10555 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockApicAccess);
10556 }
10557 else
10558 return rc;
10559 }
10560 else
10561 HCPhysApicAccess = 0;
10562
10563 /*
10564 * Virtual-APIC page and TPR threshold.
10565 */
10566 RTHCPHYS HCPhysVirtApic;
10567 uint32_t u32TprThreshold;
10568 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10569 {
10570 Assert(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW);
10571 RTGCPHYS const GCPhysVirtApic = pVmcsNstGst->u64AddrVirtApic.u;
10572
10573 void *pvPage;
10574 PGMPAGEMAPLOCK PgLockVirtApic;
10575 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysVirtApic, &pvPage, &PgLockVirtApic);
10576 if (RT_SUCCESS(rc))
10577 {
10578 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysVirtApic, &HCPhysVirtApic);
10579 AssertMsgRCReturn(rc, ("Failed to get host-physical address for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10580
10581 /** @todo Handle proper releasing of page-mapping lock later. */
10582 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockVirtApic);
10583 }
10584 else
10585 return rc;
10586
10587 u32TprThreshold = pVmcsNstGst->u32TprThreshold;
10588 }
10589 else
10590 {
10591 HCPhysVirtApic = 0;
10592 u32TprThreshold = 0;
10593
10594 /*
10595 * We must make sure CR8 reads/write must cause VM-exits when TPR shadowing is not
10596 * used by the nested hypervisor. Preventing MMIO accesses to the physical APIC will
10597 * be taken care of by EPT/shadow paging.
10598 */
10599 if (pVM->hmr0.s.fAllow64BitGuests)
10600 u32ProcCtls |= VMX_PROC_CTLS_CR8_STORE_EXIT
10601 | VMX_PROC_CTLS_CR8_LOAD_EXIT;
10602 }
10603
10604 /*
10605 * Validate basic assumptions.
10606 */
10607 PVMXVMCSINFO pVmcsInfoNstGst = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
10608 Assert(pVM->hmr0.s.vmx.fUnrestrictedGuest);
10609 Assert(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
10610 Assert(hmGetVmxActiveVmcsInfo(pVCpu) == pVmcsInfoNstGst);
10611
10612 /*
10613 * Commit it to the nested-guest VMCS.
10614 */
10615 int rc = VINF_SUCCESS;
10616 if (pVmcsInfoNstGst->u32PinCtls != u32PinCtls)
10617 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, u32PinCtls);
10618 if (pVmcsInfoNstGst->u32ProcCtls != u32ProcCtls)
10619 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, u32ProcCtls);
10620 if (pVmcsInfoNstGst->u32ProcCtls2 != u32ProcCtls2)
10621 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, u32ProcCtls2);
10622 if (pVmcsInfoNstGst->u32XcptBitmap != u32XcptBitmap)
10623 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
10624 if (pVmcsInfoNstGst->u64Cr0Mask != u64Cr0Mask)
10625 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask);
10626 if (pVmcsInfoNstGst->u64Cr4Mask != u64Cr4Mask)
10627 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask);
10628 if (pVmcsInfoNstGst->u32XcptPFMask != u32XcptPFMask)
10629 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, u32XcptPFMask);
10630 if (pVmcsInfoNstGst->u32XcptPFMatch != u32XcptPFMatch)
10631 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, u32XcptPFMatch);
10632 if ( !(u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
10633 && (u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10634 {
10635 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT);
10636 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, cPleGapTicks);
10637 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, cPleWindowTicks);
10638 }
10639 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10640 {
10641 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
10642 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
10643 }
10644 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10645 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
10646 rc |= VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, uPendingDbgXcpts);
10647 AssertRC(rc);
10648
10649 /*
10650 * Update the nested-guest VMCS cache.
10651 */
10652 pVmcsInfoNstGst->u32PinCtls = u32PinCtls;
10653 pVmcsInfoNstGst->u32ProcCtls = u32ProcCtls;
10654 pVmcsInfoNstGst->u32ProcCtls2 = u32ProcCtls2;
10655 pVmcsInfoNstGst->u32XcptBitmap = u32XcptBitmap;
10656 pVmcsInfoNstGst->u64Cr0Mask = u64Cr0Mask;
10657 pVmcsInfoNstGst->u64Cr4Mask = u64Cr4Mask;
10658 pVmcsInfoNstGst->u32XcptPFMask = u32XcptPFMask;
10659 pVmcsInfoNstGst->u32XcptPFMatch = u32XcptPFMatch;
10660 pVmcsInfoNstGst->HCPhysVirtApic = HCPhysVirtApic;
10661
10662 /*
10663 * We need to flush the TLB if we are switching the APIC-access page address.
10664 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
10665 */
10666 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10667 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = true;
10668
10669 /*
10670 * MSR bitmap.
10671 *
10672 * The MSR bitmap address has already been initialized while setting up the nested-guest
10673 * VMCS, here we need to merge the MSR bitmaps.
10674 */
10675 if (u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10676 hmR0VmxMergeMsrBitmapNested(pVCpu, pVmcsInfoNstGst, pVmcsInfoGst);
10677
10678 return VINF_SUCCESS;
10679}
10680#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10681
10682
10683/**
10684 * Does the preparations before executing guest code in VT-x.
10685 *
10686 * This may cause longjmps to ring-3 and may even result in rescheduling to the
10687 * recompiler/IEM. We must be cautious what we do here regarding committing
10688 * guest-state information into the VMCS assuming we assuredly execute the
10689 * guest in VT-x mode.
10690 *
10691 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
10692 * the common-state (TRPM/forceflags), we must undo those changes so that the
10693 * recompiler/IEM can (and should) use them when it resumes guest execution.
10694 * Otherwise such operations must be done when we can no longer exit to ring-3.
10695 *
10696 * @returns Strict VBox status code (i.e. informational status codes too).
10697 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
10698 * have been disabled.
10699 * @retval VINF_VMX_VMEXIT if a nested-guest VM-exit occurs (e.g., while evaluating
10700 * pending events).
10701 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
10702 * double-fault into the guest.
10703 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
10704 * dispatched directly.
10705 * @retval VINF_* scheduling changes, we have to go back to ring-3.
10706 *
10707 * @param pVCpu The cross context virtual CPU structure.
10708 * @param pVmxTransient The VMX-transient structure.
10709 * @param fStepping Whether we are single-stepping the guest in the
10710 * hypervisor debugger. Makes us ignore some of the reasons
10711 * for returning to ring-3, and return VINF_EM_DBG_STEPPED
10712 * if event dispatching took place.
10713 */
10714static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, bool fStepping)
10715{
10716 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10717
10718 Log4Func(("fIsNested=%RTbool fStepping=%RTbool\n", pVmxTransient->fIsNestedGuest, fStepping));
10719
10720#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
10721 if (pVmxTransient->fIsNestedGuest)
10722 {
10723 RT_NOREF2(pVCpu, fStepping);
10724 Log2Func(("Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
10725 return VINF_EM_RESCHEDULE_REM;
10726 }
10727#endif
10728
10729 /*
10730 * Check and process force flag actions, some of which might require us to go back to ring-3.
10731 */
10732 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVCpu, pVmxTransient, fStepping);
10733 if (rcStrict == VINF_SUCCESS)
10734 {
10735 /* FFs don't get set all the time. */
10736#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10737 if ( pVmxTransient->fIsNestedGuest
10738 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10739 {
10740 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10741 return VINF_VMX_VMEXIT;
10742 }
10743#endif
10744 }
10745 else
10746 return rcStrict;
10747
10748 /*
10749 * Virtualize memory-mapped accesses to the physical APIC (may take locks).
10750 */
10751 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10752 if ( !pVCpu->hm.s.vmx.u64GstMsrApicBase
10753 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10754 && PDMHasApic(pVM))
10755 {
10756 int rc = hmR0VmxMapHCApicAccessPage(pVCpu);
10757 AssertRCReturn(rc, rc);
10758 }
10759
10760#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10761 /*
10762 * Merge guest VMCS controls with the nested-guest VMCS controls.
10763 *
10764 * Even if we have not executed the guest prior to this (e.g. when resuming from a
10765 * saved state), we should be okay with merging controls as we initialize the
10766 * guest VMCS controls as part of VM setup phase.
10767 */
10768 if ( pVmxTransient->fIsNestedGuest
10769 && !pVCpu->hm.s.vmx.fMergedNstGstCtls)
10770 {
10771 int rc = hmR0VmxMergeVmcsNested(pVCpu);
10772 AssertRCReturn(rc, rc);
10773 pVCpu->hm.s.vmx.fMergedNstGstCtls = true;
10774 }
10775#endif
10776
10777 /*
10778 * Evaluate events to be injected into the guest.
10779 *
10780 * Events in TRPM can be injected without inspecting the guest state.
10781 * If any new events (interrupts/NMI) are pending currently, we try to set up the
10782 * guest to cause a VM-exit the next time they are ready to receive the event.
10783 *
10784 * With nested-guests, evaluating pending events may cause VM-exits. Also, verify
10785 * that the event in TRPM that we will inject using hardware-assisted VMX is -not-
10786 * subject to interecption. Otherwise, we should have checked and injected them
10787 * manually elsewhere (IEM).
10788 */
10789 if (TRPMHasTrap(pVCpu))
10790 {
10791 Assert(!pVmxTransient->fIsNestedGuest || !CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx));
10792 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
10793 }
10794
10795 uint32_t fIntrState;
10796 rcStrict = hmR0VmxEvaluatePendingEvent(pVCpu, pVmxTransient, &fIntrState);
10797
10798#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10799 /*
10800 * While evaluating pending events if something failed (unlikely) or if we were
10801 * preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
10802 */
10803 if (rcStrict != VINF_SUCCESS)
10804 return rcStrict;
10805 if ( pVmxTransient->fIsNestedGuest
10806 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10807 {
10808 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10809 return VINF_VMX_VMEXIT;
10810 }
10811#else
10812 Assert(rcStrict == VINF_SUCCESS);
10813#endif
10814
10815 /*
10816 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
10817 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
10818 * also result in triple-faulting the VM.
10819 *
10820 * With nested-guests, the above does not apply since unrestricted guest execution is a
10821 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
10822 */
10823 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
10824 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10825 { /* likely */ }
10826 else
10827 {
10828 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
10829 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
10830 return rcStrict;
10831 }
10832
10833 /*
10834 * A longjump might result in importing CR3 even for VM-exits that don't necessarily
10835 * import CR3 themselves. We will need to update them here, as even as late as the above
10836 * hmR0VmxInjectPendingEvent() call may lazily import guest-CPU state on demand causing
10837 * the below force flags to be set.
10838 */
10839 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
10840 {
10841 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
10842 int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
10843 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
10844 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
10845 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10846 }
10847 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
10848 {
10849 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
10850 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10851 }
10852
10853#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10854 /* Paranoia. */
10855 Assert(!pVmxTransient->fIsNestedGuest || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10856#endif
10857
10858 /*
10859 * No longjmps to ring-3 from this point on!!!
10860 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
10861 * This also disables flushing of the R0-logger instance (if any).
10862 */
10863 VMMRZCallRing3Disable(pVCpu);
10864
10865 /*
10866 * Export the guest state bits.
10867 *
10868 * We cannot perform longjmps while loading the guest state because we do not preserve the
10869 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
10870 * CPU migration.
10871 *
10872 * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
10873 * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
10874 */
10875 rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
10876 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10877 { /* likely */ }
10878 else
10879 {
10880 VMMRZCallRing3Enable(pVCpu);
10881 return rcStrict;
10882 }
10883
10884 /*
10885 * We disable interrupts so that we don't miss any interrupts that would flag preemption
10886 * (IPI/timers etc.) when thread-context hooks aren't used and we've been running with
10887 * preemption disabled for a while. Since this is purely to aid the
10888 * RTThreadPreemptIsPending() code, it doesn't matter that it may temporarily reenable and
10889 * disable interrupt on NT.
10890 *
10891 * We need to check for force-flags that could've possible been altered since we last
10892 * checked them (e.g. by PDMGetInterrupt() leaving the PDM critical section,
10893 * see @bugref{6398}).
10894 *
10895 * We also check a couple of other force-flags as a last opportunity to get the EMT back
10896 * to ring-3 before executing guest code.
10897 */
10898 pVmxTransient->fEFlags = ASMIntDisableFlags();
10899
10900 if ( ( !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
10901 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
10902 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
10903 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
10904 {
10905 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
10906 {
10907#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10908 /*
10909 * If we are executing a nested-guest make sure that we should intercept subsequent
10910 * events. The one we are injecting might be part of VM-entry. This is mainly to keep
10911 * the VM-exit instruction emulation happy.
10912 */
10913 if (pVmxTransient->fIsNestedGuest)
10914 CPUMSetGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx, true);
10915#endif
10916
10917 /*
10918 * We've injected any pending events. This is really the point of no return (to ring-3).
10919 *
10920 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
10921 * returns from this function, so do -not- enable them here.
10922 */
10923 pVCpu->hm.s.Event.fPending = false;
10924 return VINF_SUCCESS;
10925 }
10926
10927 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPendingHostIrq);
10928 rcStrict = VINF_EM_RAW_INTERRUPT;
10929 }
10930 else
10931 {
10932 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
10933 rcStrict = VINF_EM_RAW_TO_R3;
10934 }
10935
10936 ASMSetFlags(pVmxTransient->fEFlags);
10937 VMMRZCallRing3Enable(pVCpu);
10938
10939 return rcStrict;
10940}
10941
10942
10943/**
10944 * Final preparations before executing guest code using hardware-assisted VMX.
10945 *
10946 * We can no longer get preempted to a different host CPU and there are no returns
10947 * to ring-3. We ignore any errors that may happen from this point (e.g. VMWRITE
10948 * failures), this function is not intended to fail sans unrecoverable hardware
10949 * errors.
10950 *
10951 * @param pVCpu The cross context virtual CPU structure.
10952 * @param pVmxTransient The VMX-transient structure.
10953 *
10954 * @remarks Called with preemption disabled.
10955 * @remarks No-long-jump zone!!!
10956 */
10957static void hmR0VmxPreRunGuestCommitted(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10958{
10959 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10960 Assert(VMMR0IsLogFlushDisabled(pVCpu));
10961 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
10962 Assert(!pVCpu->hm.s.Event.fPending);
10963
10964 /*
10965 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
10966 */
10967 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10968 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
10969
10970 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10971 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10972 PHMPHYSCPU pHostCpu = hmR0GetCurrentCpu();
10973 RTCPUID const idCurrentCpu = pHostCpu->idCpu;
10974
10975 if (!CPUMIsGuestFPUStateActive(pVCpu))
10976 {
10977 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10978 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
10979 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_HOST_CONTEXT;
10980 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestFpuState, x);
10981 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadGuestFpu);
10982 }
10983
10984 /*
10985 * Re-export the host state bits as we may've been preempted (only happens when
10986 * thread-context hooks are used or when the VM start function changes) or if
10987 * the host CR0 is modified while loading the guest FPU state above.
10988 *
10989 * The 64-on-32 switcher saves the (64-bit) host state into the VMCS and if we
10990 * changed the switcher back to 32-bit, we *must* save the 32-bit host state here,
10991 * see @bugref{8432}.
10992 *
10993 * This may also happen when switching to/from a nested-guest VMCS without leaving
10994 * ring-0.
10995 */
10996 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
10997 {
10998 hmR0VmxExportHostState(pVCpu);
10999 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportHostState);
11000 }
11001 Assert(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT));
11002
11003 /*
11004 * Export the state shared between host and guest (FPU, debug, lazy MSRs).
11005 */
11006 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)
11007 hmR0VmxExportSharedState(pVCpu, pVmxTransient);
11008 AssertMsg(!pVCpu->hm.s.fCtxChanged, ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
11009
11010 /*
11011 * Store status of the shared guest/host debug state at the time of VM-entry.
11012 */
11013 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
11014 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
11015
11016 /*
11017 * Always cache the TPR-shadow if the virtual-APIC page exists, thereby skipping
11018 * more than one conditional check. The post-run side of our code shall determine
11019 * if it needs to sync. the virtual APIC TPR with the TPR-shadow.
11020 */
11021 if (pVmcsInfo->pbVirtApic)
11022 pVmxTransient->u8GuestTpr = pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR];
11023
11024 /*
11025 * Update the host MSRs values in the VM-exit MSR-load area.
11026 */
11027 if (!pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs)
11028 {
11029 if (pVmcsInfo->cExitMsrLoad > 0)
11030 hmR0VmxUpdateAutoLoadHostMsrs(pVCpu, pVmcsInfo);
11031 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = true;
11032 }
11033
11034 /*
11035 * Evaluate if we need to intercept guest RDTSC/P accesses. Set up the
11036 * VMX-preemption timer based on the next virtual sync clock deadline.
11037 */
11038 if ( !pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer
11039 || idCurrentCpu != pVCpu->hmr0.s.idLastCpu)
11040 {
11041 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pVmxTransient);
11042 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = true;
11043 }
11044
11045 /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
11046 bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
11047 if (!fIsRdtscIntercepted)
11048 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
11049 else
11050 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
11051
11052 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
11053 hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo); /* Invalidate the appropriate guest entries from the TLB. */
11054 Assert(idCurrentCpu == pVCpu->hmr0.s.idLastCpu);
11055 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Record the error reporting info. with the current host CPU. */
11056 pVmcsInfo->idHostCpuState = idCurrentCpu; /* Record the CPU for which the host-state has been exported. */
11057 pVmcsInfo->idHostCpuExec = idCurrentCpu; /* Record the CPU on which we shall execute. */
11058
11059 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
11060
11061 TMNotifyStartOfExecution(pVM, pVCpu); /* Notify TM to resume its clocks when TSC is tied to execution,
11062 as we're about to start executing the guest. */
11063
11064 /*
11065 * Load the guest TSC_AUX MSR when we are not intercepting RDTSCP.
11066 *
11067 * This is done this late as updating the TSC offsetting/preemption timer above
11068 * figures out if we can skip intercepting RDTSCP by calculating the number of
11069 * host CPU ticks till the next virtual sync deadline (for the dynamic case).
11070 */
11071 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
11072 && !fIsRdtscIntercepted)
11073 {
11074 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
11075
11076 /* NB: Because we call hmR0VmxAddAutoLoadStoreMsr with fUpdateHostMsr=true,
11077 it's safe even after hmR0VmxUpdateAutoLoadHostMsrs has already been done. */
11078 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX, CPUMGetGuestTscAux(pVCpu),
11079 true /* fSetReadWrite */, true /* fUpdateHostMsr */);
11080 AssertRC(rc);
11081 Assert(!pVmxTransient->fRemoveTscAuxMsr);
11082 pVmxTransient->fRemoveTscAuxMsr = true;
11083 }
11084
11085#ifdef VBOX_STRICT
11086 Assert(pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs);
11087 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
11088 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo);
11089 AssertRC(hmR0VmxCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest));
11090#endif
11091
11092#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
11093 /** @todo r=ramshankar: We can now probably use iemVmxVmentryCheckGuestState here.
11094 * Add a PVMXMSRS parameter to it, so that IEM can look at the host MSRs,
11095 * see @bugref{9180#c54}. */
11096 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
11097 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
11098 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
11099#endif
11100}
11101
11102
11103/**
11104 * First C routine invoked after running guest code using hardware-assisted VMX.
11105 *
11106 * @param pVCpu The cross context virtual CPU structure.
11107 * @param pVmxTransient The VMX-transient structure.
11108 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
11109 *
11110 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
11111 *
11112 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
11113 * unconditionally when it is safe to do so.
11114 */
11115static void hmR0VmxPostRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, int rcVMRun)
11116{
11117 uint64_t const uHostTsc = ASMReadTSC(); /** @todo We can do a lot better here, see @bugref{9180#c38}. */
11118
11119 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
11120 ASMAtomicIncU32(&pVCpu->hmr0.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
11121 pVCpu->hm.s.fCtxChanged = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
11122 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
11123 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
11124 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
11125
11126 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11127 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
11128 {
11129 uint64_t uGstTsc;
11130 if (!pVmxTransient->fIsNestedGuest)
11131 uGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
11132 else
11133 {
11134 uint64_t const uNstGstTsc = uHostTsc + pVmcsInfo->u64TscOffset;
11135 uGstTsc = CPUMRemoveNestedGuestTscOffset(pVCpu, uNstGstTsc);
11136 }
11137 TMCpuTickSetLastSeen(pVCpu, uGstTsc); /* Update TM with the guest TSC. */
11138 }
11139
11140 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatPreExit, x);
11141 TMNotifyEndOfExecution(pVCpu->CTX_SUFF(pVM), pVCpu); /* Notify TM that the guest is no longer running. */
11142 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
11143
11144 pVCpu->hmr0.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Some host state messed up by VMX needs restoring. */
11145 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
11146#ifdef VBOX_STRICT
11147 hmR0VmxCheckHostEferMsr(pVCpu, pVmcsInfo); /* Verify that the host EFER MSR wasn't modified. */
11148#endif
11149 Assert(!ASMIntAreEnabled());
11150 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
11151 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
11152
11153#ifdef HMVMX_ALWAYS_CLEAN_TRANSIENT
11154 /*
11155 * Clean all the VMCS fields in the transient structure before reading
11156 * anything from the VMCS.
11157 */
11158 pVmxTransient->uExitReason = 0;
11159 pVmxTransient->uExitIntErrorCode = 0;
11160 pVmxTransient->uExitQual = 0;
11161 pVmxTransient->uGuestLinearAddr = 0;
11162 pVmxTransient->uExitIntInfo = 0;
11163 pVmxTransient->cbExitInstr = 0;
11164 pVmxTransient->ExitInstrInfo.u = 0;
11165 pVmxTransient->uEntryIntInfo = 0;
11166 pVmxTransient->uEntryXcptErrorCode = 0;
11167 pVmxTransient->cbEntryInstr = 0;
11168 pVmxTransient->uIdtVectoringInfo = 0;
11169 pVmxTransient->uIdtVectoringErrorCode = 0;
11170#endif
11171
11172 /*
11173 * Save the basic VM-exit reason and check if the VM-entry failed.
11174 * See Intel spec. 24.9.1 "Basic VM-exit Information".
11175 */
11176 uint32_t uExitReason;
11177 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
11178 AssertRC(rc);
11179 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
11180 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
11181
11182 /*
11183 * Log the VM-exit before logging anything else as otherwise it might be a
11184 * tad confusing what happens before and after the world-switch.
11185 */
11186 HMVMX_LOG_EXIT(pVCpu, uExitReason);
11187
11188 /*
11189 * Remove the TSC_AUX MSR from the auto-load/store MSR area and reset any MSR
11190 * bitmap permissions, if it was added before VM-entry.
11191 */
11192 if (pVmxTransient->fRemoveTscAuxMsr)
11193 {
11194 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX);
11195 pVmxTransient->fRemoveTscAuxMsr = false;
11196 }
11197
11198 /*
11199 * Check if VMLAUNCH/VMRESUME succeeded.
11200 * If this failed, we cause a guru meditation and cease further execution.
11201 *
11202 * However, if we are executing a nested-guest we might fail if we use the
11203 * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
11204 */
11205 if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
11206 {
11207 /*
11208 * Update the VM-exit history array here even if the VM-entry failed due to:
11209 * - Invalid guest state.
11210 * - MSR loading.
11211 * - Machine-check event.
11212 *
11213 * In any of the above cases we will still have a "valid" VM-exit reason
11214 * despite @a fVMEntryFailed being false.
11215 *
11216 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
11217 *
11218 * Note! We don't have CS or RIP at this point. Will probably address that later
11219 * by amending the history entry added here.
11220 */
11221 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_VMX, pVmxTransient->uExitReason & EMEXIT_F_TYPE_MASK),
11222 UINT64_MAX, uHostTsc);
11223
11224 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
11225 {
11226 VMMRZCallRing3Enable(pVCpu);
11227
11228 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
11229 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
11230
11231#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
11232 hmR0VmxReadAllRoFieldsVmcs(pVmxTransient);
11233#endif
11234
11235 /*
11236 * Import the guest-interruptibility state always as we need it while evaluating
11237 * injecting events on re-entry.
11238 *
11239 * We don't import CR0 (when unrestricted guest execution is unavailable) despite
11240 * checking for real-mode while exporting the state because all bits that cause
11241 * mode changes wrt CR0 are intercepted.
11242 */
11243 uint64_t const fImportMask = CPUMCTX_EXTRN_HM_VMX_INT_STATE
11244#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
11245 | HMVMX_CPUMCTX_EXTRN_ALL
11246#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
11247 | CPUMCTX_EXTRN_RFLAGS
11248#endif
11249 ;
11250 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImportMask);
11251 AssertRC(rc);
11252
11253 /*
11254 * Sync the TPR shadow with our APIC state.
11255 */
11256 if ( !pVmxTransient->fIsNestedGuest
11257 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
11258 {
11259 Assert(pVmcsInfo->pbVirtApic);
11260 if (pVmxTransient->u8GuestTpr != pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR])
11261 {
11262 rc = APICSetTpr(pVCpu, pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR]);
11263 AssertRC(rc);
11264 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
11265 }
11266 }
11267
11268 Assert(VMMRZCallRing3IsEnabled(pVCpu));
11269 return;
11270 }
11271 }
11272#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11273 else if (pVmxTransient->fIsNestedGuest)
11274 AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
11275#endif
11276 else
11277 Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
11278
11279 VMMRZCallRing3Enable(pVCpu);
11280}
11281
11282
11283/**
11284 * Runs the guest code using hardware-assisted VMX the normal way.
11285 *
11286 * @returns VBox status code.
11287 * @param pVCpu The cross context virtual CPU structure.
11288 * @param pcLoops Pointer to the number of executed loops.
11289 */
11290static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVMCPUCC pVCpu, uint32_t *pcLoops)
11291{
11292 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
11293 Assert(pcLoops);
11294 Assert(*pcLoops <= cMaxResumeLoops);
11295 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
11296
11297#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11298 /*
11299 * Switch to the guest VMCS as we may have transitioned from executing the nested-guest
11300 * without leaving ring-0. Otherwise, if we came from ring-3 we would have loaded the
11301 * guest VMCS while entering the VMX ring-0 session.
11302 */
11303 if (pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
11304 {
11305 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, false /* fSwitchToNstGstVmcs */);
11306 if (RT_SUCCESS(rc))
11307 { /* likely */ }
11308 else
11309 {
11310 LogRelFunc(("Failed to switch to the guest VMCS. rc=%Rrc\n", rc));
11311 return rc;
11312 }
11313 }
11314#endif
11315
11316 VMXTRANSIENT VmxTransient;
11317 RT_ZERO(VmxTransient);
11318 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
11319
11320 /* Paranoia. */
11321 Assert(VmxTransient.pVmcsInfo == &pVCpu->hmr0.s.vmx.VmcsInfo);
11322
11323 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
11324 for (;;)
11325 {
11326 Assert(!HMR0SuspendPending());
11327 HMVMX_ASSERT_CPU_SAFE(pVCpu);
11328 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
11329
11330 /*
11331 * Preparatory work for running nested-guest code, this may force us to
11332 * return to ring-3.
11333 *
11334 * Warning! This bugger disables interrupts on VINF_SUCCESS!
11335 */
11336 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
11337 if (rcStrict != VINF_SUCCESS)
11338 break;
11339
11340 /* Interrupts are disabled at this point! */
11341 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
11342 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
11343 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
11344 /* Interrupts are re-enabled at this point! */
11345
11346 /*
11347 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
11348 */
11349 if (RT_SUCCESS(rcRun))
11350 { /* very likely */ }
11351 else
11352 {
11353 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
11354 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
11355 return rcRun;
11356 }
11357
11358 /*
11359 * Profile the VM-exit.
11360 */
11361 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
11362 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
11363 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
11364 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
11365 HMVMX_START_EXIT_DISPATCH_PROF();
11366
11367 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
11368
11369 /*
11370 * Handle the VM-exit.
11371 */
11372#ifdef HMVMX_USE_FUNCTION_TABLE
11373 rcStrict = g_aVMExitHandlers[VmxTransient.uExitReason].pfn(pVCpu, &VmxTransient);
11374#else
11375 rcStrict = hmR0VmxHandleExit(pVCpu, &VmxTransient);
11376#endif
11377 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
11378 if (rcStrict == VINF_SUCCESS)
11379 {
11380 if (++(*pcLoops) <= cMaxResumeLoops)
11381 continue;
11382 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
11383 rcStrict = VINF_EM_RAW_INTERRUPT;
11384 }
11385 break;
11386 }
11387
11388 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11389 return rcStrict;
11390}
11391
11392
11393#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11394/**
11395 * Runs the nested-guest code using hardware-assisted VMX.
11396 *
11397 * @returns VBox status code.
11398 * @param pVCpu The cross context virtual CPU structure.
11399 * @param pcLoops Pointer to the number of executed loops.
11400 *
11401 * @sa hmR0VmxRunGuestCodeNormal.
11402 */
11403static VBOXSTRICTRC hmR0VmxRunGuestCodeNested(PVMCPUCC pVCpu, uint32_t *pcLoops)
11404{
11405 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
11406 Assert(pcLoops);
11407 Assert(*pcLoops <= cMaxResumeLoops);
11408 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
11409
11410 /*
11411 * Switch to the nested-guest VMCS as we may have transitioned from executing the
11412 * guest without leaving ring-0. Otherwise, if we came from ring-3 we would have
11413 * loaded the nested-guest VMCS while entering the VMX ring-0 session.
11414 */
11415 if (!pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
11416 {
11417 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, true /* fSwitchToNstGstVmcs */);
11418 if (RT_SUCCESS(rc))
11419 { /* likely */ }
11420 else
11421 {
11422 LogRelFunc(("Failed to switch to the nested-guest VMCS. rc=%Rrc\n", rc));
11423 return rc;
11424 }
11425 }
11426
11427 VMXTRANSIENT VmxTransient;
11428 RT_ZERO(VmxTransient);
11429 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
11430 VmxTransient.fIsNestedGuest = true;
11431
11432 /* Paranoia. */
11433 Assert(VmxTransient.pVmcsInfo == &pVCpu->hmr0.s.vmx.VmcsInfoNstGst);
11434
11435 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
11436 for (;;)
11437 {
11438 Assert(!HMR0SuspendPending());
11439 HMVMX_ASSERT_CPU_SAFE(pVCpu);
11440 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
11441
11442 /*
11443 * Preparatory work for running guest code, this may force us to
11444 * return to ring-3.
11445 *
11446 * Warning! This bugger disables interrupts on VINF_SUCCESS!
11447 */
11448 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
11449 if (rcStrict != VINF_SUCCESS)
11450 break;
11451
11452 /* Interrupts are disabled at this point! */
11453 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
11454 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
11455 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
11456 /* Interrupts are re-enabled at this point! */
11457
11458 /*
11459 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
11460 */
11461 if (RT_SUCCESS(rcRun))
11462 { /* very likely */ }
11463 else
11464 {
11465 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
11466 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
11467 return rcRun;
11468 }
11469
11470 /*
11471 * Profile the VM-exit.
11472 */
11473 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
11474 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
11475 STAM_COUNTER_INC(&pVCpu->hm.s.StatNestedExitAll);
11476 STAM_COUNTER_INC(&pVCpu->hm.s.paStatNestedExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
11477 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
11478 HMVMX_START_EXIT_DISPATCH_PROF();
11479
11480 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
11481
11482 /*
11483 * Handle the VM-exit.
11484 */
11485 rcStrict = hmR0VmxHandleExitNested(pVCpu, &VmxTransient);
11486 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
11487 if (rcStrict == VINF_SUCCESS)
11488 {
11489 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
11490 {
11491 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
11492 rcStrict = VINF_VMX_VMEXIT;
11493 }
11494 else
11495 {
11496 if (++(*pcLoops) <= cMaxResumeLoops)
11497 continue;
11498 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
11499 rcStrict = VINF_EM_RAW_INTERRUPT;
11500 }
11501 }
11502 else
11503 Assert(rcStrict != VINF_VMX_VMEXIT);
11504 break;
11505 }
11506
11507 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11508 return rcStrict;
11509}
11510#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
11511
11512
11513/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
11514 * probes.
11515 *
11516 * The following few functions and associated structure contains the bloat
11517 * necessary for providing detailed debug events and dtrace probes as well as
11518 * reliable host side single stepping. This works on the principle of
11519 * "subclassing" the normal execution loop and workers. We replace the loop
11520 * method completely and override selected helpers to add necessary adjustments
11521 * to their core operation.
11522 *
11523 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
11524 * any performance for debug and analysis features.
11525 *
11526 * @{
11527 */
11528
11529/**
11530 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11531 * the debug run loop.
11532 */
11533typedef struct VMXRUNDBGSTATE
11534{
11535 /** The RIP we started executing at. This is for detecting that we stepped. */
11536 uint64_t uRipStart;
11537 /** The CS we started executing with. */
11538 uint16_t uCsStart;
11539
11540 /** Whether we've actually modified the 1st execution control field. */
11541 bool fModifiedProcCtls : 1;
11542 /** Whether we've actually modified the 2nd execution control field. */
11543 bool fModifiedProcCtls2 : 1;
11544 /** Whether we've actually modified the exception bitmap. */
11545 bool fModifiedXcptBitmap : 1;
11546
11547 /** We desire the modified the CR0 mask to be cleared. */
11548 bool fClearCr0Mask : 1;
11549 /** We desire the modified the CR4 mask to be cleared. */
11550 bool fClearCr4Mask : 1;
11551 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11552 uint32_t fCpe1Extra;
11553 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11554 uint32_t fCpe1Unwanted;
11555 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11556 uint32_t fCpe2Extra;
11557 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11558 uint32_t bmXcptExtra;
11559 /** The sequence number of the Dtrace provider settings the state was
11560 * configured against. */
11561 uint32_t uDtraceSettingsSeqNo;
11562 /** VM-exits to check (one bit per VM-exit). */
11563 uint32_t bmExitsToCheck[3];
11564
11565 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11566 uint32_t fProcCtlsInitial;
11567 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11568 uint32_t fProcCtls2Initial;
11569 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11570 uint32_t bmXcptInitial;
11571} VMXRUNDBGSTATE;
11572AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11573typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11574
11575
11576/**
11577 * Initializes the VMXRUNDBGSTATE structure.
11578 *
11579 * @param pVCpu The cross context virtual CPU structure of the
11580 * calling EMT.
11581 * @param pVmxTransient The VMX-transient structure.
11582 * @param pDbgState The debug state to initialize.
11583 */
11584static void hmR0VmxRunDebugStateInit(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11585{
11586 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11587 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11588
11589 pDbgState->fModifiedProcCtls = false;
11590 pDbgState->fModifiedProcCtls2 = false;
11591 pDbgState->fModifiedXcptBitmap = false;
11592 pDbgState->fClearCr0Mask = false;
11593 pDbgState->fClearCr4Mask = false;
11594 pDbgState->fCpe1Extra = 0;
11595 pDbgState->fCpe1Unwanted = 0;
11596 pDbgState->fCpe2Extra = 0;
11597 pDbgState->bmXcptExtra = 0;
11598 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11599 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11600 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11601}
11602
11603
11604/**
11605 * Updates the VMSC fields with changes requested by @a pDbgState.
11606 *
11607 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11608 * immediately before executing guest code, i.e. when interrupts are disabled.
11609 * We don't check status codes here as we cannot easily assert or return in the
11610 * latter case.
11611 *
11612 * @param pVCpu The cross context virtual CPU structure.
11613 * @param pVmxTransient The VMX-transient structure.
11614 * @param pDbgState The debug state.
11615 */
11616static void hmR0VmxPreRunGuestDebugStateApply(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11617{
11618 /*
11619 * Ensure desired flags in VMCS control fields are set.
11620 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11621 *
11622 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11623 * there should be no stale data in pCtx at this point.
11624 */
11625 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11626 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11627 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11628 {
11629 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11630 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11631 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11632 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11633 pDbgState->fModifiedProcCtls = true;
11634 }
11635
11636 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11637 {
11638 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11639 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11640 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11641 pDbgState->fModifiedProcCtls2 = true;
11642 }
11643
11644 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11645 {
11646 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11647 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11648 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11649 pDbgState->fModifiedXcptBitmap = true;
11650 }
11651
11652 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11653 {
11654 pVmcsInfo->u64Cr0Mask = 0;
11655 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, 0);
11656 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11657 }
11658
11659 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11660 {
11661 pVmcsInfo->u64Cr4Mask = 0;
11662 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, 0);
11663 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11664 }
11665
11666 NOREF(pVCpu);
11667}
11668
11669
11670/**
11671 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11672 * re-entry next time around.
11673 *
11674 * @returns Strict VBox status code (i.e. informational status codes too).
11675 * @param pVCpu The cross context virtual CPU structure.
11676 * @param pVmxTransient The VMX-transient structure.
11677 * @param pDbgState The debug state.
11678 * @param rcStrict The return code from executing the guest using single
11679 * stepping.
11680 */
11681static VBOXSTRICTRC hmR0VmxRunDebugStateRevert(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11682 VBOXSTRICTRC rcStrict)
11683{
11684 /*
11685 * Restore VM-exit control settings as we may not reenter this function the
11686 * next time around.
11687 */
11688 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11689
11690 /* We reload the initial value, trigger what we can of recalculations the
11691 next time around. From the looks of things, that's all that's required atm. */
11692 if (pDbgState->fModifiedProcCtls)
11693 {
11694 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11695 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11696 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11697 AssertRC(rc2);
11698 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11699 }
11700
11701 /* We're currently the only ones messing with this one, so just restore the
11702 cached value and reload the field. */
11703 if ( pDbgState->fModifiedProcCtls2
11704 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11705 {
11706 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11707 AssertRC(rc2);
11708 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11709 }
11710
11711 /* If we've modified the exception bitmap, we restore it and trigger
11712 reloading and partial recalculation the next time around. */
11713 if (pDbgState->fModifiedXcptBitmap)
11714 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11715
11716 return rcStrict;
11717}
11718
11719
11720/**
11721 * Configures VM-exit controls for current DBGF and DTrace settings.
11722 *
11723 * This updates @a pDbgState and the VMCS execution control fields to reflect
11724 * the necessary VM-exits demanded by DBGF and DTrace.
11725 *
11726 * @param pVCpu The cross context virtual CPU structure.
11727 * @param pVmxTransient The VMX-transient structure. May update
11728 * fUpdatedTscOffsettingAndPreemptTimer.
11729 * @param pDbgState The debug state.
11730 */
11731static void hmR0VmxPreRunGuestDebugStateUpdate(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11732{
11733 /*
11734 * Take down the dtrace serial number so we can spot changes.
11735 */
11736 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11737 ASMCompilerBarrier();
11738
11739 /*
11740 * We'll rebuild most of the middle block of data members (holding the
11741 * current settings) as we go along here, so start by clearing it all.
11742 */
11743 pDbgState->bmXcptExtra = 0;
11744 pDbgState->fCpe1Extra = 0;
11745 pDbgState->fCpe1Unwanted = 0;
11746 pDbgState->fCpe2Extra = 0;
11747 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11748 pDbgState->bmExitsToCheck[i] = 0;
11749
11750 /*
11751 * Software interrupts (INT XXh) - no idea how to trigger these...
11752 */
11753 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11754 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11755 || VBOXVMM_INT_SOFTWARE_ENABLED())
11756 {
11757 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11758 }
11759
11760 /*
11761 * INT3 breakpoints - triggered by #BP exceptions.
11762 */
11763 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11764 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11765
11766 /*
11767 * Exception bitmap and XCPT events+probes.
11768 */
11769 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11770 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11771 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11772
11773 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11774 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11775 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11776 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11777 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11778 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11779 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11780 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11781 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11782 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11783 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11784 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11785 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11786 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11787 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11788 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11789 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11790 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11791
11792 if (pDbgState->bmXcptExtra)
11793 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11794
11795 /*
11796 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11797 *
11798 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11799 * So, when adding/changing/removing please don't forget to update it.
11800 *
11801 * Some of the macros are picking up local variables to save horizontal space,
11802 * (being able to see it in a table is the lesser evil here).
11803 */
11804#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11805 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11806 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11807#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11808 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11809 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11810 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11811 } else do { } while (0)
11812#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11813 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11814 { \
11815 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11816 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11817 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11818 } else do { } while (0)
11819#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11820 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11821 { \
11822 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11823 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11824 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11825 } else do { } while (0)
11826#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11827 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11828 { \
11829 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11830 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11831 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11832 } else do { } while (0)
11833
11834 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11835 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11836 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11837 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11838 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11839
11840 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11841 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11842 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11843 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11844 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11845 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11846 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11847 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11848 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11849 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11850 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11851 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11852 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11853 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11854 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11855 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11856 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11857 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11858 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11859 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11860 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11861 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11862 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11863 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11864 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11865 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11866 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11867 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11868 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11869 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11870 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11871 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11872 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11873 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11874 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11875 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11876
11877 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11878 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11879 {
11880 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4
11881 | CPUMCTX_EXTRN_APIC_TPR);
11882 AssertRC(rc);
11883
11884#if 0 /** @todo fix me */
11885 pDbgState->fClearCr0Mask = true;
11886 pDbgState->fClearCr4Mask = true;
11887#endif
11888 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11889 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11890 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11891 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11892 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11893 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11894 require clearing here and in the loop if we start using it. */
11895 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11896 }
11897 else
11898 {
11899 if (pDbgState->fClearCr0Mask)
11900 {
11901 pDbgState->fClearCr0Mask = false;
11902 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR0);
11903 }
11904 if (pDbgState->fClearCr4Mask)
11905 {
11906 pDbgState->fClearCr4Mask = false;
11907 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR4);
11908 }
11909 }
11910 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11911 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11912
11913 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11914 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11915 {
11916 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11917 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11918 }
11919 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11920 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11921
11922 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11923 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11924 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11925 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11926 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11927 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11928 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11929 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11930#if 0 /** @todo too slow, fix handler. */
11931 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11932#endif
11933 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11934
11935 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11936 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11937 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11938 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11939 {
11940 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11941 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11942 }
11943 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11944 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11945 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11946 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11947
11948 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11949 || IS_EITHER_ENABLED(pVM, INSTR_STR)
11950 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
11951 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
11952 {
11953 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11954 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
11955 }
11956 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
11957 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
11958 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
11959 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
11960
11961 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
11962 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
11963 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
11964 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
11965 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
11966 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
11967 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
11968 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
11969 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
11970 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
11971 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
11972 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
11973 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
11974 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
11975 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
11976 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
11977 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
11978 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
11979 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
11980 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
11981 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
11982 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
11983
11984#undef IS_EITHER_ENABLED
11985#undef SET_ONLY_XBM_IF_EITHER_EN
11986#undef SET_CPE1_XBM_IF_EITHER_EN
11987#undef SET_CPEU_XBM_IF_EITHER_EN
11988#undef SET_CPE2_XBM_IF_EITHER_EN
11989
11990 /*
11991 * Sanitize the control stuff.
11992 */
11993 pDbgState->fCpe2Extra &= g_HmMsrs.u.vmx.ProcCtls2.n.allowed1;
11994 if (pDbgState->fCpe2Extra)
11995 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
11996 pDbgState->fCpe1Extra &= g_HmMsrs.u.vmx.ProcCtls.n.allowed1;
11997 pDbgState->fCpe1Unwanted &= ~g_HmMsrs.u.vmx.ProcCtls.n.allowed0;
11998 if (pVCpu->hmr0.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
11999 {
12000 pVCpu->hmr0.s.fDebugWantRdTscExit ^= true;
12001 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
12002 }
12003
12004 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
12005 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
12006 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
12007 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
12008}
12009
12010
12011/**
12012 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
12013 * appropriate.
12014 *
12015 * The caller has checked the VM-exit against the
12016 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
12017 * already, so we don't have to do that either.
12018 *
12019 * @returns Strict VBox status code (i.e. informational status codes too).
12020 * @param pVCpu The cross context virtual CPU structure.
12021 * @param pVmxTransient The VMX-transient structure.
12022 * @param uExitReason The VM-exit reason.
12023 *
12024 * @remarks The name of this function is displayed by dtrace, so keep it short
12025 * and to the point. No longer than 33 chars long, please.
12026 */
12027static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
12028{
12029 /*
12030 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
12031 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
12032 *
12033 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
12034 * does. Must add/change/remove both places. Same ordering, please.
12035 *
12036 * Added/removed events must also be reflected in the next section
12037 * where we dispatch dtrace events.
12038 */
12039 bool fDtrace1 = false;
12040 bool fDtrace2 = false;
12041 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
12042 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
12043 uint32_t uEventArg = 0;
12044#define SET_EXIT(a_EventSubName) \
12045 do { \
12046 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
12047 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
12048 } while (0)
12049#define SET_BOTH(a_EventSubName) \
12050 do { \
12051 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
12052 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
12053 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
12054 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
12055 } while (0)
12056 switch (uExitReason)
12057 {
12058 case VMX_EXIT_MTF:
12059 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
12060
12061 case VMX_EXIT_XCPT_OR_NMI:
12062 {
12063 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
12064 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
12065 {
12066 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
12067 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
12068 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
12069 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
12070 {
12071 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
12072 {
12073 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
12074 uEventArg = pVmxTransient->uExitIntErrorCode;
12075 }
12076 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
12077 switch (enmEvent1)
12078 {
12079 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
12080 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
12081 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
12082 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
12083 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
12084 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
12085 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
12086 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
12087 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
12088 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
12089 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
12090 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
12091 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
12092 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
12093 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
12094 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
12095 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
12096 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
12097 default: break;
12098 }
12099 }
12100 else
12101 AssertFailed();
12102 break;
12103
12104 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
12105 uEventArg = idxVector;
12106 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
12107 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
12108 break;
12109 }
12110 break;
12111 }
12112
12113 case VMX_EXIT_TRIPLE_FAULT:
12114 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
12115 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
12116 break;
12117 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
12118 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
12119 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
12120 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
12121 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
12122
12123 /* Instruction specific VM-exits: */
12124 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
12125 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
12126 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
12127 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
12128 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
12129 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
12130 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
12131 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
12132 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
12133 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
12134 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
12135 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
12136 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
12137 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
12138 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
12139 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
12140 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
12141 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
12142 case VMX_EXIT_MOV_CRX:
12143 hmR0VmxReadExitQualVmcs(pVmxTransient);
12144 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
12145 SET_BOTH(CRX_READ);
12146 else
12147 SET_BOTH(CRX_WRITE);
12148 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
12149 break;
12150 case VMX_EXIT_MOV_DRX:
12151 hmR0VmxReadExitQualVmcs(pVmxTransient);
12152 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
12153 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
12154 SET_BOTH(DRX_READ);
12155 else
12156 SET_BOTH(DRX_WRITE);
12157 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
12158 break;
12159 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
12160 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
12161 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
12162 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
12163 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
12164 case VMX_EXIT_GDTR_IDTR_ACCESS:
12165 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12166 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
12167 {
12168 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
12169 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
12170 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
12171 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
12172 }
12173 break;
12174
12175 case VMX_EXIT_LDTR_TR_ACCESS:
12176 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12177 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
12178 {
12179 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
12180 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
12181 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
12182 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
12183 }
12184 break;
12185
12186 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
12187 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
12188 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
12189 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
12190 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
12191 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
12192 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
12193 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
12194 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
12195 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
12196 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
12197
12198 /* Events that aren't relevant at this point. */
12199 case VMX_EXIT_EXT_INT:
12200 case VMX_EXIT_INT_WINDOW:
12201 case VMX_EXIT_NMI_WINDOW:
12202 case VMX_EXIT_TPR_BELOW_THRESHOLD:
12203 case VMX_EXIT_PREEMPT_TIMER:
12204 case VMX_EXIT_IO_INSTR:
12205 break;
12206
12207 /* Errors and unexpected events. */
12208 case VMX_EXIT_INIT_SIGNAL:
12209 case VMX_EXIT_SIPI:
12210 case VMX_EXIT_IO_SMI:
12211 case VMX_EXIT_SMI:
12212 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12213 case VMX_EXIT_ERR_MSR_LOAD:
12214 case VMX_EXIT_ERR_MACHINE_CHECK:
12215 case VMX_EXIT_PML_FULL:
12216 case VMX_EXIT_VIRTUALIZED_EOI:
12217 break;
12218
12219 default:
12220 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12221 break;
12222 }
12223#undef SET_BOTH
12224#undef SET_EXIT
12225
12226 /*
12227 * Dtrace tracepoints go first. We do them here at once so we don't
12228 * have to copy the guest state saving and stuff a few dozen times.
12229 * Down side is that we've got to repeat the switch, though this time
12230 * we use enmEvent since the probes are a subset of what DBGF does.
12231 */
12232 if (fDtrace1 || fDtrace2)
12233 {
12234 hmR0VmxReadExitQualVmcs(pVmxTransient);
12235 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12236 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12237 switch (enmEvent1)
12238 {
12239 /** @todo consider which extra parameters would be helpful for each probe. */
12240 case DBGFEVENT_END: break;
12241 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
12242 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
12243 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
12244 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
12245 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
12246 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
12247 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
12248 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
12249 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
12250 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
12251 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
12252 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
12253 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
12254 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
12255 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
12256 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
12257 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
12258 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
12259 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12260 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
12261 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
12262 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
12263 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
12264 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
12265 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
12266 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
12267 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
12268 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12269 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12270 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12271 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12272 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
12273 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
12274 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
12275 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
12276 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
12277 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
12278 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
12279 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
12280 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
12281 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
12282 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
12283 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
12284 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
12285 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
12286 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
12287 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
12288 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
12289 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
12290 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
12291 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
12292 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
12293 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
12294 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
12295 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
12296 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
12297 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
12298 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
12299 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
12300 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
12301 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
12302 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
12303 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
12304 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
12305 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
12306 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
12307 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
12308 }
12309 switch (enmEvent2)
12310 {
12311 /** @todo consider which extra parameters would be helpful for each probe. */
12312 case DBGFEVENT_END: break;
12313 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
12314 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
12315 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
12316 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
12317 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
12318 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
12319 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
12320 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
12321 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
12322 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12323 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12324 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12325 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12326 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
12327 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
12328 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
12329 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
12330 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
12331 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
12332 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
12333 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
12334 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
12335 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
12336 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
12337 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
12338 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
12339 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
12340 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
12341 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
12342 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
12343 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
12344 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
12345 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
12346 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
12347 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
12348 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
12349 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
12350 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
12351 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
12352 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
12353 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
12354 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
12355 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
12356 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
12357 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
12358 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
12359 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
12360 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
12361 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
12362 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
12363 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
12364 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
12365 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
12366 }
12367 }
12368
12369 /*
12370 * Fire of the DBGF event, if enabled (our check here is just a quick one,
12371 * the DBGF call will do a full check).
12372 *
12373 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
12374 * Note! If we have to events, we prioritize the first, i.e. the instruction
12375 * one, in order to avoid event nesting.
12376 */
12377 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
12378 if ( enmEvent1 != DBGFEVENT_END
12379 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
12380 {
12381 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12382 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
12383 if (rcStrict != VINF_SUCCESS)
12384 return rcStrict;
12385 }
12386 else if ( enmEvent2 != DBGFEVENT_END
12387 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
12388 {
12389 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12390 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
12391 if (rcStrict != VINF_SUCCESS)
12392 return rcStrict;
12393 }
12394
12395 return VINF_SUCCESS;
12396}
12397
12398
12399/**
12400 * Single-stepping VM-exit filtering.
12401 *
12402 * This is preprocessing the VM-exits and deciding whether we've gotten far
12403 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
12404 * handling is performed.
12405 *
12406 * @returns Strict VBox status code (i.e. informational status codes too).
12407 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
12408 * @param pVmxTransient The VMX-transient structure.
12409 * @param pDbgState The debug state.
12410 */
12411DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
12412{
12413 /*
12414 * Expensive (saves context) generic dtrace VM-exit probe.
12415 */
12416 uint32_t const uExitReason = pVmxTransient->uExitReason;
12417 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
12418 { /* more likely */ }
12419 else
12420 {
12421 hmR0VmxReadExitQualVmcs(pVmxTransient);
12422 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12423 AssertRC(rc);
12424 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
12425 }
12426
12427 /*
12428 * Check for host NMI, just to get that out of the way.
12429 */
12430 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
12431 { /* normally likely */ }
12432 else
12433 {
12434 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
12435 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
12436 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
12437 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
12438 }
12439
12440 /*
12441 * Check for single stepping event if we're stepping.
12442 */
12443 if (pVCpu->hm.s.fSingleInstruction)
12444 {
12445 switch (uExitReason)
12446 {
12447 case VMX_EXIT_MTF:
12448 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
12449
12450 /* Various events: */
12451 case VMX_EXIT_XCPT_OR_NMI:
12452 case VMX_EXIT_EXT_INT:
12453 case VMX_EXIT_TRIPLE_FAULT:
12454 case VMX_EXIT_INT_WINDOW:
12455 case VMX_EXIT_NMI_WINDOW:
12456 case VMX_EXIT_TASK_SWITCH:
12457 case VMX_EXIT_TPR_BELOW_THRESHOLD:
12458 case VMX_EXIT_APIC_ACCESS:
12459 case VMX_EXIT_EPT_VIOLATION:
12460 case VMX_EXIT_EPT_MISCONFIG:
12461 case VMX_EXIT_PREEMPT_TIMER:
12462
12463 /* Instruction specific VM-exits: */
12464 case VMX_EXIT_CPUID:
12465 case VMX_EXIT_GETSEC:
12466 case VMX_EXIT_HLT:
12467 case VMX_EXIT_INVD:
12468 case VMX_EXIT_INVLPG:
12469 case VMX_EXIT_RDPMC:
12470 case VMX_EXIT_RDTSC:
12471 case VMX_EXIT_RSM:
12472 case VMX_EXIT_VMCALL:
12473 case VMX_EXIT_VMCLEAR:
12474 case VMX_EXIT_VMLAUNCH:
12475 case VMX_EXIT_VMPTRLD:
12476 case VMX_EXIT_VMPTRST:
12477 case VMX_EXIT_VMREAD:
12478 case VMX_EXIT_VMRESUME:
12479 case VMX_EXIT_VMWRITE:
12480 case VMX_EXIT_VMXOFF:
12481 case VMX_EXIT_VMXON:
12482 case VMX_EXIT_MOV_CRX:
12483 case VMX_EXIT_MOV_DRX:
12484 case VMX_EXIT_IO_INSTR:
12485 case VMX_EXIT_RDMSR:
12486 case VMX_EXIT_WRMSR:
12487 case VMX_EXIT_MWAIT:
12488 case VMX_EXIT_MONITOR:
12489 case VMX_EXIT_PAUSE:
12490 case VMX_EXIT_GDTR_IDTR_ACCESS:
12491 case VMX_EXIT_LDTR_TR_ACCESS:
12492 case VMX_EXIT_INVEPT:
12493 case VMX_EXIT_RDTSCP:
12494 case VMX_EXIT_INVVPID:
12495 case VMX_EXIT_WBINVD:
12496 case VMX_EXIT_XSETBV:
12497 case VMX_EXIT_RDRAND:
12498 case VMX_EXIT_INVPCID:
12499 case VMX_EXIT_VMFUNC:
12500 case VMX_EXIT_RDSEED:
12501 case VMX_EXIT_XSAVES:
12502 case VMX_EXIT_XRSTORS:
12503 {
12504 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12505 AssertRCReturn(rc, rc);
12506 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
12507 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
12508 return VINF_EM_DBG_STEPPED;
12509 break;
12510 }
12511
12512 /* Errors and unexpected events: */
12513 case VMX_EXIT_INIT_SIGNAL:
12514 case VMX_EXIT_SIPI:
12515 case VMX_EXIT_IO_SMI:
12516 case VMX_EXIT_SMI:
12517 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12518 case VMX_EXIT_ERR_MSR_LOAD:
12519 case VMX_EXIT_ERR_MACHINE_CHECK:
12520 case VMX_EXIT_PML_FULL:
12521 case VMX_EXIT_VIRTUALIZED_EOI:
12522 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
12523 break;
12524
12525 default:
12526 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12527 break;
12528 }
12529 }
12530
12531 /*
12532 * Check for debugger event breakpoints and dtrace probes.
12533 */
12534 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12535 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12536 {
12537 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12538 if (rcStrict != VINF_SUCCESS)
12539 return rcStrict;
12540 }
12541
12542 /*
12543 * Normal processing.
12544 */
12545#ifdef HMVMX_USE_FUNCTION_TABLE
12546 return g_aVMExitHandlers[uExitReason].pfn(pVCpu, pVmxTransient);
12547#else
12548 return hmR0VmxHandleExit(pVCpu, pVmxTransient, uExitReason);
12549#endif
12550}
12551
12552
12553/**
12554 * Single steps guest code using hardware-assisted VMX.
12555 *
12556 * This is -not- the same as the guest single-stepping itself (say using EFLAGS.TF)
12557 * but single-stepping through the hypervisor debugger.
12558 *
12559 * @returns Strict VBox status code (i.e. informational status codes too).
12560 * @param pVCpu The cross context virtual CPU structure.
12561 * @param pcLoops Pointer to the number of executed loops.
12562 *
12563 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
12564 */
12565static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVMCPUCC pVCpu, uint32_t *pcLoops)
12566{
12567 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
12568 Assert(pcLoops);
12569 Assert(*pcLoops <= cMaxResumeLoops);
12570
12571 VMXTRANSIENT VmxTransient;
12572 RT_ZERO(VmxTransient);
12573 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
12574
12575 /* Set HMCPU indicators. */
12576 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
12577 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
12578 pVCpu->hmr0.s.fDebugWantRdTscExit = false;
12579 pVCpu->hmr0.s.fUsingDebugLoop = true;
12580
12581 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
12582 VMXRUNDBGSTATE DbgState;
12583 hmR0VmxRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
12584 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12585
12586 /*
12587 * The loop.
12588 */
12589 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
12590 for (;;)
12591 {
12592 Assert(!HMR0SuspendPending());
12593 HMVMX_ASSERT_CPU_SAFE(pVCpu);
12594 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
12595 bool fStepping = pVCpu->hm.s.fSingleInstruction;
12596
12597 /* Set up VM-execution controls the next two can respond to. */
12598 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12599
12600 /*
12601 * Preparatory work for running guest code, this may force us to
12602 * return to ring-3.
12603 *
12604 * Warning! This bugger disables interrupts on VINF_SUCCESS!
12605 */
12606 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, fStepping);
12607 if (rcStrict != VINF_SUCCESS)
12608 break;
12609
12610 /* Interrupts are disabled at this point! */
12611 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
12612
12613 /* Override any obnoxious code in the above two calls. */
12614 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12615
12616 /*
12617 * Finally execute the guest.
12618 */
12619 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
12620
12621 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
12622 /* Interrupts are re-enabled at this point! */
12623
12624 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
12625 if (RT_SUCCESS(rcRun))
12626 { /* very likely */ }
12627 else
12628 {
12629 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
12630 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
12631 return rcRun;
12632 }
12633
12634 /* Profile the VM-exit. */
12635 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
12636 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
12637 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
12638 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
12639 HMVMX_START_EXIT_DISPATCH_PROF();
12640
12641 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
12642
12643 /*
12644 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
12645 */
12646 rcStrict = hmR0VmxRunDebugHandleExit(pVCpu, &VmxTransient, &DbgState);
12647 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
12648 if (rcStrict != VINF_SUCCESS)
12649 break;
12650 if (++(*pcLoops) > cMaxResumeLoops)
12651 {
12652 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
12653 rcStrict = VINF_EM_RAW_INTERRUPT;
12654 break;
12655 }
12656
12657 /*
12658 * Stepping: Did the RIP change, if so, consider it a single step.
12659 * Otherwise, make sure one of the TFs gets set.
12660 */
12661 if (fStepping)
12662 {
12663 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12664 AssertRC(rc);
12665 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
12666 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
12667 {
12668 rcStrict = VINF_EM_DBG_STEPPED;
12669 break;
12670 }
12671 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
12672 }
12673
12674 /*
12675 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
12676 */
12677 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
12678 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12679
12680 /* Restore all controls applied by hmR0VmxPreRunGuestDebugStateApply above. */
12681 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
12682 Assert(rcStrict == VINF_SUCCESS);
12683 }
12684
12685 /*
12686 * Clear the X86_EFL_TF if necessary.
12687 */
12688 if (pVCpu->hmr0.s.fClearTrapFlag)
12689 {
12690 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
12691 AssertRC(rc);
12692 pVCpu->hmr0.s.fClearTrapFlag = false;
12693 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
12694 }
12695 /** @todo there seems to be issues with the resume flag when the monitor trap
12696 * flag is pending without being used. Seen early in bios init when
12697 * accessing APIC page in protected mode. */
12698
12699 /* Restore HMCPU indicators. */
12700 pVCpu->hmr0.s.fUsingDebugLoop = false;
12701 pVCpu->hmr0.s.fDebugWantRdTscExit = false;
12702 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
12703
12704 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
12705 return rcStrict;
12706}
12707
12708
12709/** @} */
12710
12711
12712/**
12713 * Checks if any expensive dtrace probes are enabled and we should go to the
12714 * debug loop.
12715 *
12716 * @returns true if we should use debug loop, false if not.
12717 */
12718static bool hmR0VmxAnyExpensiveProbesEnabled(void)
12719{
12720 /* It's probably faster to OR the raw 32-bit counter variables together.
12721 Since the variables are in an array and the probes are next to one
12722 another (more or less), we have good locality. So, better read
12723 eight-nine cache lines ever time and only have one conditional, than
12724 128+ conditionals, right? */
12725 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
12726 | VBOXVMM_XCPT_DE_ENABLED_RAW()
12727 | VBOXVMM_XCPT_DB_ENABLED_RAW()
12728 | VBOXVMM_XCPT_BP_ENABLED_RAW()
12729 | VBOXVMM_XCPT_OF_ENABLED_RAW()
12730 | VBOXVMM_XCPT_BR_ENABLED_RAW()
12731 | VBOXVMM_XCPT_UD_ENABLED_RAW()
12732 | VBOXVMM_XCPT_NM_ENABLED_RAW()
12733 | VBOXVMM_XCPT_DF_ENABLED_RAW()
12734 | VBOXVMM_XCPT_TS_ENABLED_RAW()
12735 | VBOXVMM_XCPT_NP_ENABLED_RAW()
12736 | VBOXVMM_XCPT_SS_ENABLED_RAW()
12737 | VBOXVMM_XCPT_GP_ENABLED_RAW()
12738 | VBOXVMM_XCPT_PF_ENABLED_RAW()
12739 | VBOXVMM_XCPT_MF_ENABLED_RAW()
12740 | VBOXVMM_XCPT_AC_ENABLED_RAW()
12741 | VBOXVMM_XCPT_XF_ENABLED_RAW()
12742 | VBOXVMM_XCPT_VE_ENABLED_RAW()
12743 | VBOXVMM_XCPT_SX_ENABLED_RAW()
12744 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
12745 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
12746 ) != 0
12747 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
12748 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
12749 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
12750 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
12751 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
12752 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
12753 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
12754 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
12755 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
12756 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
12757 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
12758 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
12759 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
12760 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
12761 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
12762 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
12763 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
12764 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
12765 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
12766 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
12767 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
12768 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
12769 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
12770 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
12771 | VBOXVMM_INSTR_STR_ENABLED_RAW()
12772 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
12773 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
12774 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
12775 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
12776 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
12777 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
12778 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
12779 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
12780 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
12781 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
12782 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
12783 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
12784 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
12785 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
12786 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
12787 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
12788 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
12789 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
12790 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
12791 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
12792 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
12793 ) != 0
12794 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
12795 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
12796 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
12797 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
12798 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
12799 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
12800 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
12801 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
12802 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
12803 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
12804 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
12805 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
12806 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
12807 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
12808 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
12809 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
12810 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
12811 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
12812 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
12813 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
12814 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
12815 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
12816 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
12817 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
12818 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
12819 | VBOXVMM_EXIT_STR_ENABLED_RAW()
12820 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
12821 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
12822 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
12823 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
12824 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
12825 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
12826 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
12827 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
12828 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
12829 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
12830 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
12831 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
12832 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
12833 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
12834 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
12835 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
12836 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
12837 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
12838 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
12839 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
12840 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
12841 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
12842 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
12843 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
12844 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
12845 ) != 0;
12846}
12847
12848
12849/**
12850 * Runs the guest using hardware-assisted VMX.
12851 *
12852 * @returns Strict VBox status code (i.e. informational status codes too).
12853 * @param pVCpu The cross context virtual CPU structure.
12854 */
12855VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVMCPUCC pVCpu)
12856{
12857 AssertPtr(pVCpu);
12858 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12859 Assert(VMMRZCallRing3IsEnabled(pVCpu));
12860 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12861 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
12862
12863 VBOXSTRICTRC rcStrict;
12864 uint32_t cLoops = 0;
12865 for (;;)
12866 {
12867#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12868 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(pCtx);
12869#else
12870 NOREF(pCtx);
12871 bool const fInNestedGuestMode = false;
12872#endif
12873 if (!fInNestedGuestMode)
12874 {
12875 if ( !pVCpu->hm.s.fUseDebugLoop
12876 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
12877 && !DBGFIsStepping(pVCpu)
12878 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
12879 rcStrict = hmR0VmxRunGuestCodeNormal(pVCpu, &cLoops);
12880 else
12881 rcStrict = hmR0VmxRunGuestCodeDebug(pVCpu, &cLoops);
12882 }
12883#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12884 else
12885 rcStrict = hmR0VmxRunGuestCodeNested(pVCpu, &cLoops);
12886
12887 if (rcStrict == VINF_VMX_VMLAUNCH_VMRESUME)
12888 {
12889 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
12890 continue;
12891 }
12892 if (rcStrict == VINF_VMX_VMEXIT)
12893 {
12894 Assert(!CPUMIsGuestInVmxNonRootMode(pCtx));
12895 continue;
12896 }
12897#endif
12898 break;
12899 }
12900
12901 int const rcLoop = VBOXSTRICTRC_VAL(rcStrict);
12902 switch (rcLoop)
12903 {
12904 case VERR_EM_INTERPRETER: rcStrict = VINF_EM_RAW_EMULATE_INSTR; break;
12905 case VINF_EM_RESET: rcStrict = VINF_EM_TRIPLE_FAULT; break;
12906 }
12907
12908 int rc2 = hmR0VmxExitToRing3(pVCpu, rcStrict);
12909 if (RT_FAILURE(rc2))
12910 {
12911 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
12912 rcStrict = rc2;
12913 }
12914 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12915 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
12916 return rcStrict;
12917}
12918
12919
12920#ifndef HMVMX_USE_FUNCTION_TABLE
12921/**
12922 * Handles a guest VM-exit from hardware-assisted VMX execution.
12923 *
12924 * @returns Strict VBox status code (i.e. informational status codes too).
12925 * @param pVCpu The cross context virtual CPU structure.
12926 * @param pVmxTransient The VMX-transient structure.
12927 */
12928DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12929{
12930#ifdef DEBUG_ramshankar
12931# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
12932 do { \
12933 if (a_fSave != 0) \
12934 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
12935 VBOXSTRICTRC rcStrict = a_CallExpr; \
12936 if (a_fSave != 0) \
12937 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST); \
12938 return rcStrict; \
12939 } while (0)
12940#else
12941# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
12942#endif
12943 uint32_t const uExitReason = pVmxTransient->uExitReason;
12944 switch (uExitReason)
12945 {
12946 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient));
12947 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, hmR0VmxExitEptViolation(pVCpu, pVmxTransient));
12948 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, hmR0VmxExitIoInstr(pVCpu, pVmxTransient));
12949 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, hmR0VmxExitCpuid(pVCpu, pVmxTransient));
12950 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, hmR0VmxExitRdtsc(pVCpu, pVmxTransient));
12951 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, hmR0VmxExitRdtscp(pVCpu, pVmxTransient));
12952 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, hmR0VmxExitApicAccess(pVCpu, pVmxTransient));
12953 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, hmR0VmxExitXcptOrNmi(pVCpu, pVmxTransient));
12954 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovCRx(pVCpu, pVmxTransient));
12955 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, hmR0VmxExitExtInt(pVCpu, pVmxTransient));
12956 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, hmR0VmxExitIntWindow(pVCpu, pVmxTransient));
12957 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient));
12958 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, hmR0VmxExitMwait(pVCpu, pVmxTransient));
12959 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, hmR0VmxExitMonitor(pVCpu, pVmxTransient));
12960 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, hmR0VmxExitTaskSwitch(pVCpu, pVmxTransient));
12961 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient));
12962 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, hmR0VmxExitRdmsr(pVCpu, pVmxTransient));
12963 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, hmR0VmxExitWrmsr(pVCpu, pVmxTransient));
12964 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, hmR0VmxExitVmcall(pVCpu, pVmxTransient));
12965 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovDRx(pVCpu, pVmxTransient));
12966 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, hmR0VmxExitHlt(pVCpu, pVmxTransient));
12967 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, hmR0VmxExitInvd(pVCpu, pVmxTransient));
12968 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, hmR0VmxExitInvlpg(pVCpu, pVmxTransient));
12969 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, hmR0VmxExitMtf(pVCpu, pVmxTransient));
12970 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, hmR0VmxExitPause(pVCpu, pVmxTransient));
12971 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, hmR0VmxExitWbinvd(pVCpu, pVmxTransient));
12972 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, hmR0VmxExitXsetbv(pVCpu, pVmxTransient));
12973 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, hmR0VmxExitInvpcid(pVCpu, pVmxTransient));
12974 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, hmR0VmxExitGetsec(pVCpu, pVmxTransient));
12975 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, hmR0VmxExitRdpmc(pVCpu, pVmxTransient));
12976#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12977 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, hmR0VmxExitVmclear(pVCpu, pVmxTransient));
12978 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, hmR0VmxExitVmlaunch(pVCpu, pVmxTransient));
12979 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrld(pVCpu, pVmxTransient));
12980 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrst(pVCpu, pVmxTransient));
12981 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, hmR0VmxExitVmread(pVCpu, pVmxTransient));
12982 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, hmR0VmxExitVmwrite(pVCpu, pVmxTransient));
12983 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, hmR0VmxExitVmresume(pVCpu, pVmxTransient));
12984 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, hmR0VmxExitVmxoff(pVCpu, pVmxTransient));
12985 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, hmR0VmxExitVmxon(pVCpu, pVmxTransient));
12986 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, hmR0VmxExitInvvpid(pVCpu, pVmxTransient));
12987 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient));
12988#else
12989 case VMX_EXIT_VMCLEAR:
12990 case VMX_EXIT_VMLAUNCH:
12991 case VMX_EXIT_VMPTRLD:
12992 case VMX_EXIT_VMPTRST:
12993 case VMX_EXIT_VMREAD:
12994 case VMX_EXIT_VMRESUME:
12995 case VMX_EXIT_VMWRITE:
12996 case VMX_EXIT_VMXOFF:
12997 case VMX_EXIT_VMXON:
12998 case VMX_EXIT_INVVPID:
12999 case VMX_EXIT_INVEPT:
13000 return hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient);
13001#endif
13002
13003 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pVmxTransient);
13004 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pVmxTransient);
13005 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
13006
13007 case VMX_EXIT_INIT_SIGNAL:
13008 case VMX_EXIT_SIPI:
13009 case VMX_EXIT_IO_SMI:
13010 case VMX_EXIT_SMI:
13011 case VMX_EXIT_ERR_MSR_LOAD:
13012 case VMX_EXIT_ERR_MACHINE_CHECK:
13013 case VMX_EXIT_PML_FULL:
13014 case VMX_EXIT_VIRTUALIZED_EOI:
13015 case VMX_EXIT_GDTR_IDTR_ACCESS:
13016 case VMX_EXIT_LDTR_TR_ACCESS:
13017 case VMX_EXIT_APIC_WRITE:
13018 case VMX_EXIT_RDRAND:
13019 case VMX_EXIT_RSM:
13020 case VMX_EXIT_VMFUNC:
13021 case VMX_EXIT_ENCLS:
13022 case VMX_EXIT_RDSEED:
13023 case VMX_EXIT_XSAVES:
13024 case VMX_EXIT_XRSTORS:
13025 case VMX_EXIT_UMWAIT:
13026 case VMX_EXIT_TPAUSE:
13027 default:
13028 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
13029 }
13030#undef VMEXIT_CALL_RET
13031}
13032#endif /* !HMVMX_USE_FUNCTION_TABLE */
13033
13034
13035#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13036/**
13037 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
13038 *
13039 * @returns Strict VBox status code (i.e. informational status codes too).
13040 * @param pVCpu The cross context virtual CPU structure.
13041 * @param pVmxTransient The VMX-transient structure.
13042 */
13043DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13044{
13045 uint32_t const uExitReason = pVmxTransient->uExitReason;
13046 switch (uExitReason)
13047 {
13048 case VMX_EXIT_EPT_MISCONFIG: return hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
13049 case VMX_EXIT_EPT_VIOLATION: return hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
13050 case VMX_EXIT_XCPT_OR_NMI: return hmR0VmxExitXcptOrNmiNested(pVCpu, pVmxTransient);
13051 case VMX_EXIT_IO_INSTR: return hmR0VmxExitIoInstrNested(pVCpu, pVmxTransient);
13052 case VMX_EXIT_HLT: return hmR0VmxExitHltNested(pVCpu, pVmxTransient);
13053
13054 /*
13055 * We shouldn't direct host physical interrupts to the nested-guest.
13056 */
13057 case VMX_EXIT_EXT_INT:
13058 return hmR0VmxExitExtInt(pVCpu, pVmxTransient);
13059
13060 /*
13061 * Instructions that cause VM-exits unconditionally or the condition is
13062 * always is taken solely from the nested hypervisor (meaning if the VM-exit
13063 * happens, it's guaranteed to be a nested-guest VM-exit).
13064 *
13065 * - Provides VM-exit instruction length ONLY.
13066 */
13067 case VMX_EXIT_CPUID: /* Unconditional. */
13068 case VMX_EXIT_VMCALL:
13069 case VMX_EXIT_GETSEC:
13070 case VMX_EXIT_INVD:
13071 case VMX_EXIT_XSETBV:
13072 case VMX_EXIT_VMLAUNCH:
13073 case VMX_EXIT_VMRESUME:
13074 case VMX_EXIT_VMXOFF:
13075 case VMX_EXIT_ENCLS: /* Condition specified solely by nested hypervisor. */
13076 case VMX_EXIT_VMFUNC:
13077 return hmR0VmxExitInstrNested(pVCpu, pVmxTransient);
13078
13079 /*
13080 * Instructions that cause VM-exits unconditionally or the condition is
13081 * always is taken solely from the nested hypervisor (meaning if the VM-exit
13082 * happens, it's guaranteed to be a nested-guest VM-exit).
13083 *
13084 * - Provides VM-exit instruction length.
13085 * - Provides VM-exit information.
13086 * - Optionally provides Exit qualification.
13087 *
13088 * Since Exit qualification is 0 for all VM-exits where it is not
13089 * applicable, reading and passing it to the guest should produce
13090 * defined behavior.
13091 *
13092 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
13093 */
13094 case VMX_EXIT_INVEPT: /* Unconditional. */
13095 case VMX_EXIT_INVVPID:
13096 case VMX_EXIT_VMCLEAR:
13097 case VMX_EXIT_VMPTRLD:
13098 case VMX_EXIT_VMPTRST:
13099 case VMX_EXIT_VMXON:
13100 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by nested hypervisor. */
13101 case VMX_EXIT_LDTR_TR_ACCESS:
13102 case VMX_EXIT_RDRAND:
13103 case VMX_EXIT_RDSEED:
13104 case VMX_EXIT_XSAVES:
13105 case VMX_EXIT_XRSTORS:
13106 case VMX_EXIT_UMWAIT:
13107 case VMX_EXIT_TPAUSE:
13108 return hmR0VmxExitInstrWithInfoNested(pVCpu, pVmxTransient);
13109
13110 case VMX_EXIT_RDTSC: return hmR0VmxExitRdtscNested(pVCpu, pVmxTransient);
13111 case VMX_EXIT_RDTSCP: return hmR0VmxExitRdtscpNested(pVCpu, pVmxTransient);
13112 case VMX_EXIT_RDMSR: return hmR0VmxExitRdmsrNested(pVCpu, pVmxTransient);
13113 case VMX_EXIT_WRMSR: return hmR0VmxExitWrmsrNested(pVCpu, pVmxTransient);
13114 case VMX_EXIT_INVLPG: return hmR0VmxExitInvlpgNested(pVCpu, pVmxTransient);
13115 case VMX_EXIT_INVPCID: return hmR0VmxExitInvpcidNested(pVCpu, pVmxTransient);
13116 case VMX_EXIT_TASK_SWITCH: return hmR0VmxExitTaskSwitchNested(pVCpu, pVmxTransient);
13117 case VMX_EXIT_WBINVD: return hmR0VmxExitWbinvdNested(pVCpu, pVmxTransient);
13118 case VMX_EXIT_MTF: return hmR0VmxExitMtfNested(pVCpu, pVmxTransient);
13119 case VMX_EXIT_APIC_ACCESS: return hmR0VmxExitApicAccessNested(pVCpu, pVmxTransient);
13120 case VMX_EXIT_APIC_WRITE: return hmR0VmxExitApicWriteNested(pVCpu, pVmxTransient);
13121 case VMX_EXIT_VIRTUALIZED_EOI: return hmR0VmxExitVirtEoiNested(pVCpu, pVmxTransient);
13122 case VMX_EXIT_MOV_CRX: return hmR0VmxExitMovCRxNested(pVCpu, pVmxTransient);
13123 case VMX_EXIT_INT_WINDOW: return hmR0VmxExitIntWindowNested(pVCpu, pVmxTransient);
13124 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindowNested(pVCpu, pVmxTransient);
13125 case VMX_EXIT_TPR_BELOW_THRESHOLD: return hmR0VmxExitTprBelowThresholdNested(pVCpu, pVmxTransient);
13126 case VMX_EXIT_MWAIT: return hmR0VmxExitMwaitNested(pVCpu, pVmxTransient);
13127 case VMX_EXIT_MONITOR: return hmR0VmxExitMonitorNested(pVCpu, pVmxTransient);
13128 case VMX_EXIT_PAUSE: return hmR0VmxExitPauseNested(pVCpu, pVmxTransient);
13129
13130 case VMX_EXIT_PREEMPT_TIMER:
13131 {
13132 /** @todo NSTVMX: Preempt timer. */
13133 return hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient);
13134 }
13135
13136 case VMX_EXIT_MOV_DRX: return hmR0VmxExitMovDRxNested(pVCpu, pVmxTransient);
13137 case VMX_EXIT_RDPMC: return hmR0VmxExitRdpmcNested(pVCpu, pVmxTransient);
13138
13139 case VMX_EXIT_VMREAD:
13140 case VMX_EXIT_VMWRITE: return hmR0VmxExitVmreadVmwriteNested(pVCpu, pVmxTransient);
13141
13142 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFaultNested(pVCpu, pVmxTransient);
13143 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestStateNested(pVCpu, pVmxTransient);
13144
13145 case VMX_EXIT_INIT_SIGNAL:
13146 case VMX_EXIT_SIPI:
13147 case VMX_EXIT_IO_SMI:
13148 case VMX_EXIT_SMI:
13149 case VMX_EXIT_ERR_MSR_LOAD:
13150 case VMX_EXIT_ERR_MACHINE_CHECK:
13151 case VMX_EXIT_PML_FULL:
13152 case VMX_EXIT_RSM:
13153 default:
13154 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
13155 }
13156}
13157#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13158
13159
13160/** @name VM-exit helpers.
13161 * @{
13162 */
13163/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13164/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
13165/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13166
13167/** Macro for VM-exits called unexpectedly. */
13168#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
13169 do { \
13170 (a_pVCpu)->hm.s.u32HMError = (a_HmError); \
13171 return VERR_VMX_UNEXPECTED_EXIT; \
13172 } while (0)
13173
13174#ifdef VBOX_STRICT
13175/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
13176# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
13177 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
13178
13179# define HMVMX_ASSERT_PREEMPT_CPUID() \
13180 do { \
13181 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
13182 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
13183 } while (0)
13184
13185# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13186 do { \
13187 AssertPtr((a_pVCpu)); \
13188 AssertPtr((a_pVmxTransient)); \
13189 Assert((a_pVmxTransient)->fVMEntryFailed == false); \
13190 Assert((a_pVmxTransient)->pVmcsInfo); \
13191 Assert(ASMIntAreEnabled()); \
13192 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
13193 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
13194 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
13195 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
13196 if (VMMR0IsLogFlushDisabled((a_pVCpu))) \
13197 HMVMX_ASSERT_PREEMPT_CPUID(); \
13198 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
13199 } while (0)
13200
13201# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13202 do { \
13203 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
13204 Assert((a_pVmxTransient)->fIsNestedGuest); \
13205 } while (0)
13206
13207# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13208 do { \
13209 Log4Func(("\n")); \
13210 } while (0)
13211#else
13212# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13213 do { \
13214 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
13215 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
13216 } while (0)
13217
13218# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13219 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
13220
13221# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
13222#endif
13223
13224#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13225/** Macro that does the necessary privilege checks and intercepted VM-exits for
13226 * guests that attempted to execute a VMX instruction. */
13227# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
13228 do \
13229 { \
13230 VBOXSTRICTRC rcStrictTmp = hmR0VmxCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
13231 if (rcStrictTmp == VINF_SUCCESS) \
13232 { /* likely */ } \
13233 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
13234 { \
13235 Assert((a_pVCpu)->hm.s.Event.fPending); \
13236 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
13237 return VINF_SUCCESS; \
13238 } \
13239 else \
13240 { \
13241 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
13242 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
13243 } \
13244 } while (0)
13245
13246/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
13247# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
13248 do \
13249 { \
13250 VBOXSTRICTRC rcStrictTmp = hmR0VmxDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
13251 (a_pGCPtrEffAddr)); \
13252 if (rcStrictTmp == VINF_SUCCESS) \
13253 { /* likely */ } \
13254 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
13255 { \
13256 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
13257 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
13258 NOREF(uXcptTmp); \
13259 return VINF_SUCCESS; \
13260 } \
13261 else \
13262 { \
13263 Log4Func(("hmR0VmxDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
13264 return rcStrictTmp; \
13265 } \
13266 } while (0)
13267#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13268
13269
13270/**
13271 * Advances the guest RIP by the specified number of bytes.
13272 *
13273 * @param pVCpu The cross context virtual CPU structure.
13274 * @param cbInstr Number of bytes to advance the RIP by.
13275 *
13276 * @remarks No-long-jump zone!!!
13277 */
13278DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPUCC pVCpu, uint32_t cbInstr)
13279{
13280 /* Advance the RIP. */
13281 pVCpu->cpum.GstCtx.rip += cbInstr;
13282 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
13283
13284 /* Update interrupt inhibition. */
13285 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
13286 && pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
13287 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
13288}
13289
13290
13291/**
13292 * Advances the guest RIP after reading it from the VMCS.
13293 *
13294 * @returns VBox status code, no informational status codes.
13295 * @param pVCpu The cross context virtual CPU structure.
13296 * @param pVmxTransient The VMX-transient structure.
13297 *
13298 * @remarks No-long-jump zone!!!
13299 */
13300static int hmR0VmxAdvanceGuestRip(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13301{
13302 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13303 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
13304 AssertRCReturn(rc, rc);
13305
13306 hmR0VmxAdvanceGuestRipBy(pVCpu, pVmxTransient->cbExitInstr);
13307 return VINF_SUCCESS;
13308}
13309
13310
13311/**
13312 * Handle a condition that occurred while delivering an event through the guest or
13313 * nested-guest IDT.
13314 *
13315 * @returns Strict VBox status code (i.e. informational status codes too).
13316 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13317 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
13318 * to continue execution of the guest which will delivery the \#DF.
13319 * @retval VINF_EM_RESET if we detected a triple-fault condition.
13320 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
13321 *
13322 * @param pVCpu The cross context virtual CPU structure.
13323 * @param pVmxTransient The VMX-transient structure.
13324 *
13325 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13326 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
13327 * is due to an EPT violation, PML full or SPP-related event.
13328 *
13329 * @remarks No-long-jump zone!!!
13330 */
13331static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13332{
13333 Assert(!pVCpu->hm.s.Event.fPending);
13334 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
13335 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13336 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13337 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13338 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
13339
13340 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
13341 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13342 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
13343 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
13344 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
13345 {
13346 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
13347 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
13348
13349 /*
13350 * If the event was a software interrupt (generated with INT n) or a software exception
13351 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
13352 * can handle the VM-exit and continue guest execution which will re-execute the
13353 * instruction rather than re-injecting the exception, as that can cause premature
13354 * trips to ring-3 before injection and involve TRPM which currently has no way of
13355 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
13356 * the problem).
13357 */
13358 IEMXCPTRAISE enmRaise;
13359 IEMXCPTRAISEINFO fRaiseInfo;
13360 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
13361 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
13362 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
13363 {
13364 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
13365 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
13366 }
13367 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
13368 {
13369 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
13370 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
13371 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
13372
13373 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
13374 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
13375
13376 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
13377
13378 /* Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF(). */
13379 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
13380 {
13381 pVmxTransient->fVectoringPF = true;
13382 enmRaise = IEMXCPTRAISE_PREV_EVENT;
13383 }
13384 }
13385 else
13386 {
13387 /*
13388 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
13389 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
13390 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
13391 */
13392 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
13393 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
13394 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
13395 enmRaise = IEMXCPTRAISE_PREV_EVENT;
13396 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
13397 }
13398
13399 /*
13400 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
13401 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
13402 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
13403 * subsequent VM-entry would fail, see @bugref{7445}.
13404 *
13405 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
13406 */
13407 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
13408 && enmRaise == IEMXCPTRAISE_PREV_EVENT
13409 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13410 && CPUMIsGuestNmiBlocking(pVCpu))
13411 {
13412 CPUMSetGuestNmiBlocking(pVCpu, false);
13413 }
13414
13415 switch (enmRaise)
13416 {
13417 case IEMXCPTRAISE_CURRENT_XCPT:
13418 {
13419 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
13420 Assert(rcStrict == VINF_SUCCESS);
13421 break;
13422 }
13423
13424 case IEMXCPTRAISE_PREV_EVENT:
13425 {
13426 uint32_t u32ErrCode;
13427 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
13428 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
13429 else
13430 u32ErrCode = 0;
13431
13432 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
13433 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect);
13434 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */,
13435 u32ErrCode, pVCpu->cpum.GstCtx.cr2);
13436
13437 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo,
13438 pVCpu->hm.s.Event.u32ErrCode));
13439 Assert(rcStrict == VINF_SUCCESS);
13440 break;
13441 }
13442
13443 case IEMXCPTRAISE_REEXEC_INSTR:
13444 Assert(rcStrict == VINF_SUCCESS);
13445 break;
13446
13447 case IEMXCPTRAISE_DOUBLE_FAULT:
13448 {
13449 /*
13450 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
13451 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
13452 */
13453 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
13454 {
13455 pVmxTransient->fVectoringDoublePF = true;
13456 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo,
13457 pVCpu->cpum.GstCtx.cr2));
13458 rcStrict = VINF_SUCCESS;
13459 }
13460 else
13461 {
13462 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectConvertDF);
13463 hmR0VmxSetPendingXcptDF(pVCpu);
13464 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
13465 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
13466 rcStrict = VINF_HM_DOUBLE_FAULT;
13467 }
13468 break;
13469 }
13470
13471 case IEMXCPTRAISE_TRIPLE_FAULT:
13472 {
13473 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
13474 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
13475 rcStrict = VINF_EM_RESET;
13476 break;
13477 }
13478
13479 case IEMXCPTRAISE_CPU_HANG:
13480 {
13481 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
13482 rcStrict = VERR_EM_GUEST_CPU_HANG;
13483 break;
13484 }
13485
13486 default:
13487 {
13488 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
13489 rcStrict = VERR_VMX_IPE_2;
13490 break;
13491 }
13492 }
13493 }
13494 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13495 && !CPUMIsGuestNmiBlocking(pVCpu))
13496 {
13497 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
13498 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
13499 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
13500 {
13501 /*
13502 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
13503 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13504 * that virtual NMIs remain blocked until the IRET execution is completed.
13505 *
13506 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
13507 */
13508 CPUMSetGuestNmiBlocking(pVCpu, true);
13509 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13510 }
13511 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13512 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13513 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13514 {
13515 /*
13516 * Execution of IRET caused an EPT violation, page-modification log-full event or
13517 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
13518 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13519 * that virtual NMIs remain blocked until the IRET execution is completed.
13520 *
13521 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
13522 */
13523 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
13524 {
13525 CPUMSetGuestNmiBlocking(pVCpu, true);
13526 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13527 }
13528 }
13529 }
13530
13531 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
13532 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
13533 return rcStrict;
13534}
13535
13536
13537#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13538/**
13539 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
13540 * guest attempting to execute a VMX instruction.
13541 *
13542 * @returns Strict VBox status code (i.e. informational status codes too).
13543 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13544 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
13545 *
13546 * @param pVCpu The cross context virtual CPU structure.
13547 * @param uExitReason The VM-exit reason.
13548 *
13549 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
13550 * @remarks No-long-jump zone!!!
13551 */
13552static VBOXSTRICTRC hmR0VmxCheckExitDueToVmxInstr(PVMCPUCC pVCpu, uint32_t uExitReason)
13553{
13554 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
13555 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
13556
13557 /*
13558 * The physical CPU would have already checked the CPU mode/code segment.
13559 * We shall just assert here for paranoia.
13560 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
13561 */
13562 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13563 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
13564 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
13565
13566 if (uExitReason == VMX_EXIT_VMXON)
13567 {
13568 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
13569
13570 /*
13571 * We check CR4.VMXE because it is required to be always set while in VMX operation
13572 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
13573 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
13574 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
13575 */
13576 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
13577 {
13578 Log4Func(("CR4.VMXE is not set -> #UD\n"));
13579 hmR0VmxSetPendingXcptUD(pVCpu);
13580 return VINF_HM_PENDING_XCPT;
13581 }
13582 }
13583 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
13584 {
13585 /*
13586 * The guest has not entered VMX operation but attempted to execute a VMX instruction
13587 * (other than VMXON), we need to raise a #UD.
13588 */
13589 Log4Func(("Not in VMX root mode -> #UD\n"));
13590 hmR0VmxSetPendingXcptUD(pVCpu);
13591 return VINF_HM_PENDING_XCPT;
13592 }
13593
13594 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
13595 return VINF_SUCCESS;
13596}
13597
13598
13599/**
13600 * Decodes the memory operand of an instruction that caused a VM-exit.
13601 *
13602 * The Exit qualification field provides the displacement field for memory
13603 * operand instructions, if any.
13604 *
13605 * @returns Strict VBox status code (i.e. informational status codes too).
13606 * @retval VINF_SUCCESS if the operand was successfully decoded.
13607 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
13608 * operand.
13609 * @param pVCpu The cross context virtual CPU structure.
13610 * @param uExitInstrInfo The VM-exit instruction information field.
13611 * @param enmMemAccess The memory operand's access type (read or write).
13612 * @param GCPtrDisp The instruction displacement field, if any. For
13613 * RIP-relative addressing pass RIP + displacement here.
13614 * @param pGCPtrMem Where to store the effective destination memory address.
13615 *
13616 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
13617 * virtual-8086 mode hence skips those checks while verifying if the
13618 * segment is valid.
13619 */
13620static VBOXSTRICTRC hmR0VmxDecodeMemOperand(PVMCPUCC pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
13621 PRTGCPTR pGCPtrMem)
13622{
13623 Assert(pGCPtrMem);
13624 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
13625 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
13626 | CPUMCTX_EXTRN_CR0);
13627
13628 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
13629 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
13630 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
13631
13632 VMXEXITINSTRINFO ExitInstrInfo;
13633 ExitInstrInfo.u = uExitInstrInfo;
13634 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
13635 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
13636 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
13637 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
13638 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
13639 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
13640 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
13641 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
13642 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
13643
13644 /*
13645 * Validate instruction information.
13646 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
13647 */
13648 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
13649 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
13650 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
13651 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
13652 AssertLogRelMsgReturn(fIsMemOperand,
13653 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
13654
13655 /*
13656 * Compute the complete effective address.
13657 *
13658 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
13659 * See AMD spec. 4.5.2 "Segment Registers".
13660 */
13661 RTGCPTR GCPtrMem = GCPtrDisp;
13662 if (fBaseRegValid)
13663 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
13664 if (fIdxRegValid)
13665 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
13666
13667 RTGCPTR const GCPtrOff = GCPtrMem;
13668 if ( !fIsLongMode
13669 || iSegReg >= X86_SREG_FS)
13670 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
13671 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
13672
13673 /*
13674 * Validate effective address.
13675 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
13676 */
13677 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
13678 Assert(cbAccess > 0);
13679 if (fIsLongMode)
13680 {
13681 if (X86_IS_CANONICAL(GCPtrMem))
13682 {
13683 *pGCPtrMem = GCPtrMem;
13684 return VINF_SUCCESS;
13685 }
13686
13687 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
13688 * "Data Limit Checks in 64-bit Mode". */
13689 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
13690 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13691 return VINF_HM_PENDING_XCPT;
13692 }
13693
13694 /*
13695 * This is a watered down version of iemMemApplySegment().
13696 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
13697 * and segment CPL/DPL checks are skipped.
13698 */
13699 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
13700 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
13701 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
13702
13703 /* Check if the segment is present and usable. */
13704 if ( pSel->Attr.n.u1Present
13705 && !pSel->Attr.n.u1Unusable)
13706 {
13707 Assert(pSel->Attr.n.u1DescType);
13708 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
13709 {
13710 /* Check permissions for the data segment. */
13711 if ( enmMemAccess == VMXMEMACCESS_WRITE
13712 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
13713 {
13714 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13715 hmR0VmxSetPendingXcptGP(pVCpu, iSegReg);
13716 return VINF_HM_PENDING_XCPT;
13717 }
13718
13719 /* Check limits if it's a normal data segment. */
13720 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
13721 {
13722 if ( GCPtrFirst32 > pSel->u32Limit
13723 || GCPtrLast32 > pSel->u32Limit)
13724 {
13725 Log4Func(("Data segment limit exceeded. "
13726 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13727 GCPtrLast32, pSel->u32Limit));
13728 if (iSegReg == X86_SREG_SS)
13729 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13730 else
13731 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13732 return VINF_HM_PENDING_XCPT;
13733 }
13734 }
13735 else
13736 {
13737 /* Check limits if it's an expand-down data segment.
13738 Note! The upper boundary is defined by the B bit, not the G bit! */
13739 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
13740 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
13741 {
13742 Log4Func(("Expand-down data segment limit exceeded. "
13743 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13744 GCPtrLast32, pSel->u32Limit));
13745 if (iSegReg == X86_SREG_SS)
13746 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13747 else
13748 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13749 return VINF_HM_PENDING_XCPT;
13750 }
13751 }
13752 }
13753 else
13754 {
13755 /* Check permissions for the code segment. */
13756 if ( enmMemAccess == VMXMEMACCESS_WRITE
13757 || ( enmMemAccess == VMXMEMACCESS_READ
13758 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
13759 {
13760 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
13761 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13762 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13763 return VINF_HM_PENDING_XCPT;
13764 }
13765
13766 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
13767 if ( GCPtrFirst32 > pSel->u32Limit
13768 || GCPtrLast32 > pSel->u32Limit)
13769 {
13770 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
13771 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
13772 if (iSegReg == X86_SREG_SS)
13773 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13774 else
13775 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13776 return VINF_HM_PENDING_XCPT;
13777 }
13778 }
13779 }
13780 else
13781 {
13782 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13783 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13784 return VINF_HM_PENDING_XCPT;
13785 }
13786
13787 *pGCPtrMem = GCPtrMem;
13788 return VINF_SUCCESS;
13789}
13790#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13791
13792
13793/**
13794 * VM-exit helper for LMSW.
13795 */
13796static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
13797{
13798 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13799 AssertRCReturn(rc, rc);
13800
13801 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
13802 AssertMsg( rcStrict == VINF_SUCCESS
13803 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13804
13805 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13806 if (rcStrict == VINF_IEM_RAISED_XCPT)
13807 {
13808 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13809 rcStrict = VINF_SUCCESS;
13810 }
13811
13812 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
13813 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13814 return rcStrict;
13815}
13816
13817
13818/**
13819 * VM-exit helper for CLTS.
13820 */
13821static VBOXSTRICTRC hmR0VmxExitClts(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
13822{
13823 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13824 AssertRCReturn(rc, rc);
13825
13826 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
13827 AssertMsg( rcStrict == VINF_SUCCESS
13828 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13829
13830 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13831 if (rcStrict == VINF_IEM_RAISED_XCPT)
13832 {
13833 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13834 rcStrict = VINF_SUCCESS;
13835 }
13836
13837 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
13838 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13839 return rcStrict;
13840}
13841
13842
13843/**
13844 * VM-exit helper for MOV from CRx (CRx read).
13845 */
13846static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13847{
13848 Assert(iCrReg < 16);
13849 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
13850
13851 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13852 AssertRCReturn(rc, rc);
13853
13854 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
13855 AssertMsg( rcStrict == VINF_SUCCESS
13856 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13857
13858 if (iGReg == X86_GREG_xSP)
13859 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
13860 else
13861 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13862#ifdef VBOX_WITH_STATISTICS
13863 switch (iCrReg)
13864 {
13865 case 0: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Read); break;
13866 case 2: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Read); break;
13867 case 3: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Read); break;
13868 case 4: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Read); break;
13869 case 8: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Read); break;
13870 }
13871#endif
13872 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
13873 return rcStrict;
13874}
13875
13876
13877/**
13878 * VM-exit helper for MOV to CRx (CRx write).
13879 */
13880static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13881{
13882 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13883 AssertRCReturn(rc, rc);
13884
13885 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
13886 AssertMsg( rcStrict == VINF_SUCCESS
13887 || rcStrict == VINF_IEM_RAISED_XCPT
13888 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13889
13890 switch (iCrReg)
13891 {
13892 case 0:
13893 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0
13894 | HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
13895 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Write);
13896 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
13897 break;
13898
13899 case 2:
13900 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Write);
13901 /* Nothing to do here, CR2 it's not part of the VMCS. */
13902 break;
13903
13904 case 3:
13905 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
13906 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Write);
13907 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
13908 break;
13909
13910 case 4:
13911 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
13912 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Write);
13913 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
13914 pVCpu->cpum.GstCtx.cr4, pVCpu->hmr0.s.fLoadSaveGuestXcr0));
13915 break;
13916
13917 case 8:
13918 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
13919 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
13920 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Write);
13921 break;
13922
13923 default:
13924 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
13925 break;
13926 }
13927
13928 if (rcStrict == VINF_IEM_RAISED_XCPT)
13929 {
13930 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13931 rcStrict = VINF_SUCCESS;
13932 }
13933 return rcStrict;
13934}
13935
13936
13937/**
13938 * VM-exit exception handler for \#PF (Page-fault exception).
13939 *
13940 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13941 */
13942static VBOXSTRICTRC hmR0VmxExitXcptPF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13943{
13944 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13945 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
13946 hmR0VmxReadExitQualVmcs(pVmxTransient);
13947
13948 if (!pVM->hmr0.s.fNestedPaging)
13949 { /* likely */ }
13950 else
13951 {
13952#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13953 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hmr0.s.fUsingDebugLoop);
13954#endif
13955 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13956 if (!pVmxTransient->fVectoringDoublePF)
13957 {
13958 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13959 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
13960 }
13961 else
13962 {
13963 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13964 Assert(!pVmxTransient->fIsNestedGuest);
13965 hmR0VmxSetPendingXcptDF(pVCpu);
13966 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
13967 }
13968 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13969 return VINF_SUCCESS;
13970 }
13971
13972 Assert(!pVmxTransient->fIsNestedGuest);
13973
13974 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
13975 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
13976 if (pVmxTransient->fVectoringPF)
13977 {
13978 Assert(pVCpu->hm.s.Event.fPending);
13979 return VINF_EM_RAW_INJECT_TRPM_EVENT;
13980 }
13981
13982 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
13983 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
13984 AssertRCReturn(rc, rc);
13985
13986 Log4Func(("#PF: cs:rip=%#04x:%#RX64 err_code=%#RX32 exit_qual=%#RX64 cr3=%#RX64\n", pCtx->cs.Sel, pCtx->rip,
13987 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual, pCtx->cr3));
13988
13989 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
13990 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pCtx), (RTGCPTR)pVmxTransient->uExitQual);
13991
13992 Log4Func(("#PF: rc=%Rrc\n", rc));
13993 if (rc == VINF_SUCCESS)
13994 {
13995 /*
13996 * This is typically a shadow page table sync or a MMIO instruction. But we may have
13997 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
13998 */
13999 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14000 TRPMResetTrap(pVCpu);
14001 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
14002 return rc;
14003 }
14004
14005 if (rc == VINF_EM_RAW_GUEST_TRAP)
14006 {
14007 if (!pVmxTransient->fVectoringDoublePF)
14008 {
14009 /* It's a guest page fault and needs to be reflected to the guest. */
14010 uint32_t const uGstErrorCode = TRPMGetErrorCode(pVCpu);
14011 TRPMResetTrap(pVCpu);
14012 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
14013 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
14014 uGstErrorCode, pVmxTransient->uExitQual);
14015 }
14016 else
14017 {
14018 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
14019 TRPMResetTrap(pVCpu);
14020 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
14021 hmR0VmxSetPendingXcptDF(pVCpu);
14022 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
14023 }
14024
14025 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
14026 return VINF_SUCCESS;
14027 }
14028
14029 TRPMResetTrap(pVCpu);
14030 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
14031 return rc;
14032}
14033
14034
14035/**
14036 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
14037 *
14038 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14039 */
14040static VBOXSTRICTRC hmR0VmxExitXcptMF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14041{
14042 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14043 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
14044
14045 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0);
14046 AssertRCReturn(rc, rc);
14047
14048 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
14049 {
14050 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
14051 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
14052
14053 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
14054 * provides VM-exit instruction length. If this causes problem later,
14055 * disassemble the instruction like it's done on AMD-V. */
14056 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14057 AssertRCReturn(rc2, rc2);
14058 return rc;
14059 }
14060
14061 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbExitInstr,
14062 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14063 return VINF_SUCCESS;
14064}
14065
14066
14067/**
14068 * VM-exit exception handler for \#BP (Breakpoint exception).
14069 *
14070 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14071 */
14072static VBOXSTRICTRC hmR0VmxExitXcptBP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14073{
14074 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14075 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
14076
14077 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14078 AssertRCReturn(rc, rc);
14079
14080 if (!pVmxTransient->fIsNestedGuest)
14081 rc = DBGFTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx));
14082 else
14083 rc = VINF_EM_RAW_GUEST_TRAP;
14084
14085 if (rc == VINF_EM_RAW_GUEST_TRAP)
14086 {
14087 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14088 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14089 rc = VINF_SUCCESS;
14090 }
14091
14092 Assert(rc == VINF_SUCCESS || rc == VINF_EM_DBG_BREAKPOINT);
14093 return rc;
14094}
14095
14096
14097/**
14098 * VM-exit exception handler for \#AC (Alignment-check exception).
14099 *
14100 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14101 */
14102static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14103{
14104 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14105 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC);
14106
14107 /* Re-inject it. We'll detect any nesting before getting here. */
14108 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14109 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14110 return VINF_SUCCESS;
14111}
14112
14113
14114/**
14115 * VM-exit exception handler for \#DB (Debug exception).
14116 *
14117 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14118 */
14119static VBOXSTRICTRC hmR0VmxExitXcptDB(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14120{
14121 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14122 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
14123
14124 /*
14125 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
14126 */
14127 hmR0VmxReadExitQualVmcs(pVmxTransient);
14128
14129 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
14130 uint64_t const uDR6 = X86_DR6_INIT_VAL
14131 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
14132 | X86_DR6_BD | X86_DR6_BS));
14133
14134 int rc;
14135 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14136 if (!pVmxTransient->fIsNestedGuest)
14137 {
14138 rc = DBGFTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
14139
14140 /*
14141 * Prevents stepping twice over the same instruction when the guest is stepping using
14142 * EFLAGS.TF and the hypervisor debugger is stepping using MTF.
14143 * Testcase: DOSQEMM, break (using "ba x 1") at cs:rip 0x70:0x774 and step (using "t").
14144 */
14145 if ( rc == VINF_EM_DBG_STEPPED
14146 && (pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MONITOR_TRAP_FLAG))
14147 {
14148 Assert(pVCpu->hm.s.fSingleInstruction);
14149 rc = VINF_EM_RAW_GUEST_TRAP;
14150 }
14151 }
14152 else
14153 rc = VINF_EM_RAW_GUEST_TRAP;
14154 Log6Func(("rc=%Rrc\n", rc));
14155 if (rc == VINF_EM_RAW_GUEST_TRAP)
14156 {
14157 /*
14158 * The exception was for the guest. Update DR6, DR7.GD and
14159 * IA32_DEBUGCTL.LBR before forwarding it.
14160 * See Intel spec. 27.1 "Architectural State before a VM-Exit".
14161 */
14162 VMMRZCallRing3Disable(pVCpu);
14163 HM_DISABLE_PREEMPT(pVCpu);
14164
14165 pCtx->dr[6] &= ~X86_DR6_B_MASK;
14166 pCtx->dr[6] |= uDR6;
14167 if (CPUMIsGuestDebugStateActive(pVCpu))
14168 ASMSetDR6(pCtx->dr[6]);
14169
14170 HM_RESTORE_PREEMPT();
14171 VMMRZCallRing3Enable(pVCpu);
14172
14173 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_DR7);
14174 AssertRCReturn(rc, rc);
14175
14176 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
14177 pCtx->dr[7] &= ~(uint64_t)X86_DR7_GD;
14178
14179 /* Paranoia. */
14180 pCtx->dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
14181 pCtx->dr[7] |= X86_DR7_RA1_MASK;
14182
14183 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, pCtx->dr[7]);
14184 AssertRC(rc);
14185
14186 /*
14187 * Raise #DB in the guest.
14188 *
14189 * It is important to reflect exactly what the VM-exit gave us (preserving the
14190 * interruption-type) rather than use hmR0VmxSetPendingXcptDB() as the #DB could've
14191 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
14192 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
14193 *
14194 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
14195 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
14196 */
14197 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14198 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14199 return VINF_SUCCESS;
14200 }
14201
14202 /*
14203 * Not a guest trap, must be a hypervisor related debug event then.
14204 * Update DR6 in case someone is interested in it.
14205 */
14206 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
14207 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
14208 CPUMSetHyperDR6(pVCpu, uDR6);
14209
14210 return rc;
14211}
14212
14213
14214/**
14215 * Hacks its way around the lovely mesa driver's backdoor accesses.
14216 *
14217 * @sa hmR0SvmHandleMesaDrvGp.
14218 */
14219static int hmR0VmxHandleMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
14220{
14221 LogFunc(("cs:rip=%#04x:%#RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
14222 RT_NOREF(pCtx);
14223
14224 /* For now we'll just skip the instruction. */
14225 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14226}
14227
14228
14229/**
14230 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
14231 * backdoor logging w/o checking what it is running inside.
14232 *
14233 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
14234 * backdoor port and magic numbers loaded in registers.
14235 *
14236 * @returns true if it is, false if it isn't.
14237 * @sa hmR0SvmIsMesaDrvGp.
14238 */
14239DECLINLINE(bool) hmR0VmxIsMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
14240{
14241 /* 0xed: IN eAX,dx */
14242 uint8_t abInstr[1];
14243 if (pVmxTransient->cbExitInstr != sizeof(abInstr))
14244 return false;
14245
14246 /* Check that it is #GP(0). */
14247 if (pVmxTransient->uExitIntErrorCode != 0)
14248 return false;
14249
14250 /* Check magic and port. */
14251 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
14252 /*Log(("hmR0VmxIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
14253 if (pCtx->rax != UINT32_C(0x564d5868))
14254 return false;
14255 if (pCtx->dx != UINT32_C(0x5658))
14256 return false;
14257
14258 /* Flat ring-3 CS. */
14259 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
14260 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
14261 /*Log(("hmR0VmxIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
14262 if (pCtx->cs.Attr.n.u2Dpl != 3)
14263 return false;
14264 if (pCtx->cs.u64Base != 0)
14265 return false;
14266
14267 /* Check opcode. */
14268 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
14269 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
14270 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
14271 /*Log(("hmR0VmxIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
14272 if (RT_FAILURE(rc))
14273 return false;
14274 if (abInstr[0] != 0xed)
14275 return false;
14276
14277 return true;
14278}
14279
14280
14281/**
14282 * VM-exit exception handler for \#GP (General-protection exception).
14283 *
14284 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14285 */
14286static VBOXSTRICTRC hmR0VmxExitXcptGP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14287{
14288 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14289 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
14290
14291 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14292 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14293 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
14294 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
14295 { /* likely */ }
14296 else
14297 {
14298#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14299 Assert(pVCpu->hmr0.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
14300#endif
14301 /*
14302 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
14303 * executing a nested-guest, reflect #GP to the guest or nested-guest.
14304 */
14305 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14306 AssertRCReturn(rc, rc);
14307 Log4Func(("Gst: cs:rip=%#04x:%#RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
14308 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
14309
14310 if ( pVmxTransient->fIsNestedGuest
14311 || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
14312 || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
14313 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14314 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14315 else
14316 rc = hmR0VmxHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
14317 return rc;
14318 }
14319
14320 Assert(CPUMIsGuestInRealModeEx(pCtx));
14321 Assert(!pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest);
14322 Assert(!pVmxTransient->fIsNestedGuest);
14323
14324 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14325 AssertRCReturn(rc, rc);
14326
14327 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
14328 if (rcStrict == VINF_SUCCESS)
14329 {
14330 if (!CPUMIsGuestInRealModeEx(pCtx))
14331 {
14332 /*
14333 * The guest is no longer in real-mode, check if we can continue executing the
14334 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
14335 */
14336 pVmcsInfoShared->RealMode.fRealOnV86Active = false;
14337 if (HMCanExecuteVmxGuest(pVCpu->pVMR0, pVCpu, pCtx))
14338 {
14339 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
14340 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14341 }
14342 else
14343 {
14344 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
14345 rcStrict = VINF_EM_RESCHEDULE;
14346 }
14347 }
14348 else
14349 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14350 }
14351 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14352 {
14353 rcStrict = VINF_SUCCESS;
14354 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14355 }
14356 return VBOXSTRICTRC_VAL(rcStrict);
14357}
14358
14359
14360/**
14361 * VM-exit exception handler wrapper for all other exceptions that are not handled
14362 * by a specific handler.
14363 *
14364 * This simply re-injects the exception back into the VM without any special
14365 * processing.
14366 *
14367 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14368 */
14369static VBOXSTRICTRC hmR0VmxExitXcptOthers(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14370{
14371 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14372
14373#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14374 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14375 AssertMsg(pVCpu->hmr0.s.fUsingDebugLoop || pVmcsInfo->pShared->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
14376 ("uVector=%#x u32XcptBitmap=%#X32\n",
14377 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
14378 NOREF(pVmcsInfo);
14379#endif
14380
14381 /*
14382 * Re-inject the exception into the guest. This cannot be a double-fault condition which
14383 * would have been handled while checking exits due to event delivery.
14384 */
14385 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14386
14387#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14388 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
14389 AssertRCReturn(rc, rc);
14390 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
14391#endif
14392
14393#ifdef VBOX_WITH_STATISTICS
14394 switch (uVector)
14395 {
14396 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE); break;
14397 case X86_XCPT_DB: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB); break;
14398 case X86_XCPT_BP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); break;
14399 case X86_XCPT_OF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
14400 case X86_XCPT_BR: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBR); break;
14401 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); break;
14402 case X86_XCPT_NM: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
14403 case X86_XCPT_DF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDF); break;
14404 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS); break;
14405 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP); break;
14406 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS); break;
14407 case X86_XCPT_GP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP); break;
14408 case X86_XCPT_PF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); break;
14409 case X86_XCPT_MF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF); break;
14410 case X86_XCPT_AC: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC); break;
14411 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF); break;
14412 default:
14413 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
14414 break;
14415 }
14416#endif
14417
14418 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
14419 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
14420 NOREF(uVector);
14421
14422 /* Re-inject the original exception into the guest. */
14423 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14424 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14425 return VINF_SUCCESS;
14426}
14427
14428
14429/**
14430 * VM-exit exception handler for all exceptions (except NMIs!).
14431 *
14432 * @remarks This may be called for both guests and nested-guests. Take care to not
14433 * make assumptions and avoid doing anything that is not relevant when
14434 * executing a nested-guest (e.g., Mesa driver hacks).
14435 */
14436static VBOXSTRICTRC hmR0VmxExitXcpt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14437{
14438 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
14439
14440 /*
14441 * If this VM-exit occurred while delivering an event through the guest IDT, take
14442 * action based on the return code and additional hints (e.g. for page-faults)
14443 * that will be updated in the VMX transient structure.
14444 */
14445 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
14446 if (rcStrict == VINF_SUCCESS)
14447 {
14448 /*
14449 * If an exception caused a VM-exit due to delivery of an event, the original
14450 * event may have to be re-injected into the guest. We shall reinject it and
14451 * continue guest execution. However, page-fault is a complicated case and
14452 * needs additional processing done in hmR0VmxExitXcptPF().
14453 */
14454 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14455 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14456 if ( !pVCpu->hm.s.Event.fPending
14457 || uVector == X86_XCPT_PF)
14458 {
14459 switch (uVector)
14460 {
14461 case X86_XCPT_PF: return hmR0VmxExitXcptPF(pVCpu, pVmxTransient);
14462 case X86_XCPT_GP: return hmR0VmxExitXcptGP(pVCpu, pVmxTransient);
14463 case X86_XCPT_MF: return hmR0VmxExitXcptMF(pVCpu, pVmxTransient);
14464 case X86_XCPT_DB: return hmR0VmxExitXcptDB(pVCpu, pVmxTransient);
14465 case X86_XCPT_BP: return hmR0VmxExitXcptBP(pVCpu, pVmxTransient);
14466 case X86_XCPT_AC: return hmR0VmxExitXcptAC(pVCpu, pVmxTransient);
14467 default:
14468 return hmR0VmxExitXcptOthers(pVCpu, pVmxTransient);
14469 }
14470 }
14471 /* else: inject pending event before resuming guest execution. */
14472 }
14473 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
14474 {
14475 Assert(pVCpu->hm.s.Event.fPending);
14476 rcStrict = VINF_SUCCESS;
14477 }
14478
14479 return rcStrict;
14480}
14481/** @} */
14482
14483
14484/** @name VM-exit handlers.
14485 * @{
14486 */
14487/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
14488/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
14489/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
14490
14491/**
14492 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
14493 */
14494HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14495{
14496 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14497 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
14498 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
14499 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
14500 return VINF_SUCCESS;
14501 return VINF_EM_RAW_INTERRUPT;
14502}
14503
14504
14505/**
14506 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
14507 * VM-exit.
14508 */
14509HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14510{
14511 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14512 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
14513
14514 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
14515
14516 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
14517 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14518 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14519
14520 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14521 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
14522 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
14523 NOREF(pVmcsInfo);
14524
14525 VBOXSTRICTRC rcStrict;
14526 switch (uExitIntType)
14527 {
14528 /*
14529 * Host physical NMIs:
14530 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
14531 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
14532 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
14533 *
14534 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
14535 * See Intel spec. 27.5.5 "Updating Non-Register State".
14536 */
14537 case VMX_EXIT_INT_INFO_TYPE_NMI:
14538 {
14539 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
14540 break;
14541 }
14542
14543 /*
14544 * Privileged software exceptions (#DB from ICEBP),
14545 * Software exceptions (#BP and #OF),
14546 * Hardware exceptions:
14547 * Process the required exceptions and resume guest execution if possible.
14548 */
14549 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
14550 Assert(uVector == X86_XCPT_DB);
14551 RT_FALL_THRU();
14552 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
14553 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
14554 RT_FALL_THRU();
14555 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
14556 {
14557 NOREF(uVector);
14558 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
14559 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14560 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
14561 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
14562
14563 rcStrict = hmR0VmxExitXcpt(pVCpu, pVmxTransient);
14564 break;
14565 }
14566
14567 default:
14568 {
14569 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
14570 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
14571 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
14572 break;
14573 }
14574 }
14575
14576 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
14577 return rcStrict;
14578}
14579
14580
14581/**
14582 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
14583 */
14584HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14585{
14586 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14587
14588 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
14589 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14590 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
14591
14592 /* Evaluate and deliver pending events and resume guest execution. */
14593 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
14594 return VINF_SUCCESS;
14595}
14596
14597
14598/**
14599 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
14600 */
14601HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14602{
14603 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14604
14605 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14606 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
14607 {
14608 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
14609 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14610 }
14611
14612 Assert(!CPUMIsGuestNmiBlocking(pVCpu));
14613
14614 /*
14615 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
14616 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
14617 */
14618 uint32_t fIntrState;
14619 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14620 AssertRC(rc);
14621 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
14622 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
14623 {
14624 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
14625 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
14626
14627 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
14628 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
14629 AssertRC(rc);
14630 }
14631
14632 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
14633 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
14634
14635 /* Evaluate and deliver pending events and resume guest execution. */
14636 return VINF_SUCCESS;
14637}
14638
14639
14640/**
14641 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
14642 */
14643HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14644{
14645 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14646 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14647}
14648
14649
14650/**
14651 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
14652 */
14653HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14654{
14655 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14656 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14657}
14658
14659
14660/**
14661 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
14662 */
14663HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14664{
14665 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14666
14667 /*
14668 * Get the state we need and update the exit history entry.
14669 */
14670 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14671 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14672
14673 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14674 AssertRCReturn(rc, rc);
14675
14676 VBOXSTRICTRC rcStrict;
14677 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
14678 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
14679 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
14680 if (!pExitRec)
14681 {
14682 /*
14683 * Regular CPUID instruction execution.
14684 */
14685 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbExitInstr);
14686 if (rcStrict == VINF_SUCCESS)
14687 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14688 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14689 {
14690 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14691 rcStrict = VINF_SUCCESS;
14692 }
14693 }
14694 else
14695 {
14696 /*
14697 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
14698 */
14699 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14700 AssertRCReturn(rc2, rc2);
14701
14702 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
14703 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
14704
14705 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
14706 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14707
14708 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
14709 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14710 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
14711 }
14712 return rcStrict;
14713}
14714
14715
14716/**
14717 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
14718 */
14719HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14720{
14721 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14722
14723 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14724 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
14725 AssertRCReturn(rc, rc);
14726
14727 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
14728 return VINF_EM_RAW_EMULATE_INSTR;
14729
14730 AssertMsgFailed(("hmR0VmxExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
14731 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14732}
14733
14734
14735/**
14736 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
14737 */
14738HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14739{
14740 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14741
14742 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14743 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14744 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14745 AssertRCReturn(rc, rc);
14746
14747 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbExitInstr);
14748 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14749 {
14750 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14751 we must reset offsetting on VM-entry. See @bugref{6634}. */
14752 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14753 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14754 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14755 }
14756 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14757 {
14758 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14759 rcStrict = VINF_SUCCESS;
14760 }
14761 return rcStrict;
14762}
14763
14764
14765/**
14766 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
14767 */
14768HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14769{
14770 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14771
14772 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14773 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14774 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
14775 AssertRCReturn(rc, rc);
14776
14777 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbExitInstr);
14778 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14779 {
14780 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14781 we must reset offsetting on VM-reentry. See @bugref{6634}. */
14782 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14783 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14784 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14785 }
14786 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14787 {
14788 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14789 rcStrict = VINF_SUCCESS;
14790 }
14791 return rcStrict;
14792}
14793
14794
14795/**
14796 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
14797 */
14798HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14799{
14800 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14801
14802 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14803 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0
14804 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
14805 AssertRCReturn(rc, rc);
14806
14807 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14808 rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
14809 if (RT_LIKELY(rc == VINF_SUCCESS))
14810 {
14811 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14812 Assert(pVmxTransient->cbExitInstr == 2);
14813 }
14814 else
14815 {
14816 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
14817 rc = VERR_EM_INTERPRETER;
14818 }
14819 return rc;
14820}
14821
14822
14823/**
14824 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
14825 */
14826HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14827{
14828 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14829
14830 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
14831 if (EMAreHypercallInstructionsEnabled(pVCpu))
14832 {
14833 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14834 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
14835 | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
14836 AssertRCReturn(rc, rc);
14837
14838 /* Perform the hypercall. */
14839 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
14840 if (rcStrict == VINF_SUCCESS)
14841 {
14842 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14843 AssertRCReturn(rc, rc);
14844 }
14845 else
14846 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
14847 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
14848 || RT_FAILURE(rcStrict));
14849
14850 /* If the hypercall changes anything other than guest's general-purpose registers,
14851 we would need to reload the guest changed bits here before VM-entry. */
14852 }
14853 else
14854 Log4Func(("Hypercalls not enabled\n"));
14855
14856 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
14857 if (RT_FAILURE(rcStrict))
14858 {
14859 hmR0VmxSetPendingXcptUD(pVCpu);
14860 rcStrict = VINF_SUCCESS;
14861 }
14862
14863 return rcStrict;
14864}
14865
14866
14867/**
14868 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
14869 */
14870HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14871{
14872 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14873 Assert(!pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging || pVCpu->hmr0.s.fUsingDebugLoop);
14874
14875 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14876 hmR0VmxReadExitQualVmcs(pVmxTransient);
14877 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14878 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
14879 AssertRCReturn(rc, rc);
14880
14881 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->uExitQual);
14882
14883 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
14884 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14885 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14886 {
14887 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14888 rcStrict = VINF_SUCCESS;
14889 }
14890 else
14891 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
14892 VBOXSTRICTRC_VAL(rcStrict)));
14893 return rcStrict;
14894}
14895
14896
14897/**
14898 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
14899 */
14900HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14901{
14902 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14903
14904 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14905 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14906 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
14907 AssertRCReturn(rc, rc);
14908
14909 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbExitInstr);
14910 if (rcStrict == VINF_SUCCESS)
14911 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14912 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14913 {
14914 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14915 rcStrict = VINF_SUCCESS;
14916 }
14917
14918 return rcStrict;
14919}
14920
14921
14922/**
14923 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
14924 */
14925HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14926{
14927 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14928
14929 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14930 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14931 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14932 AssertRCReturn(rc, rc);
14933
14934 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbExitInstr);
14935 if (RT_SUCCESS(rcStrict))
14936 {
14937 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14938 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
14939 rcStrict = VINF_SUCCESS;
14940 }
14941
14942 return rcStrict;
14943}
14944
14945
14946/**
14947 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
14948 * VM-exit.
14949 */
14950HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14951{
14952 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14953 return VINF_EM_RESET;
14954}
14955
14956
14957/**
14958 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
14959 */
14960HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14961{
14962 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14963
14964 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14965 AssertRCReturn(rc, rc);
14966
14967 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
14968 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
14969 rc = VINF_SUCCESS;
14970 else
14971 rc = VINF_EM_HALT;
14972
14973 if (rc != VINF_SUCCESS)
14974 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
14975 return rc;
14976}
14977
14978
14979/**
14980 * VM-exit handler for instructions that result in a \#UD exception delivered to
14981 * the guest.
14982 */
14983HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14984{
14985 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14986 hmR0VmxSetPendingXcptUD(pVCpu);
14987 return VINF_SUCCESS;
14988}
14989
14990
14991/**
14992 * VM-exit handler for expiry of the VMX-preemption timer.
14993 */
14994HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14995{
14996 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14997
14998 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
14999 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
15000
15001 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
15002 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15003 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
15004 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
15005 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
15006}
15007
15008
15009/**
15010 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
15011 */
15012HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15013{
15014 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15015
15016 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15017 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15018 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
15019 AssertRCReturn(rc, rc);
15020
15021 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbExitInstr);
15022 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
15023 : HM_CHANGED_RAISED_XCPT_MASK);
15024
15025 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15026 bool const fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
15027 if (fLoadSaveGuestXcr0 != pVCpu->hmr0.s.fLoadSaveGuestXcr0)
15028 {
15029 pVCpu->hmr0.s.fLoadSaveGuestXcr0 = fLoadSaveGuestXcr0;
15030 hmR0VmxUpdateStartVmFunction(pVCpu);
15031 }
15032
15033 return rcStrict;
15034}
15035
15036
15037/**
15038 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
15039 */
15040HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15041{
15042 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15043
15044 /** @todo Enable the new code after finding a reliably guest test-case. */
15045#if 1
15046 return VERR_EM_INTERPRETER;
15047#else
15048 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15049 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15050 hmR0VmxReadExitQualVmcs(pVmxTransient);
15051 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15052 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15053 AssertRCReturn(rc, rc);
15054
15055 /* Paranoia. Ensure this has a memory operand. */
15056 Assert(!pVmxTransient->ExitInstrInfo.Inv.u1Cleared0);
15057
15058 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
15059 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
15060 uint64_t const uType = CPUMIsGuestIn64BitCode(pVCpu) ? pVCpu->cpum.GstCtx.aGRegs[iGReg].u64
15061 : pVCpu->cpum.GstCtx.aGRegs[iGReg].u32;
15062
15063 RTGCPTR GCPtrDesc;
15064 HMVMX_DECODE_MEM_OPERAND(pVCpu, pVmxTransient->ExitInstrInfo.u, pVmxTransient->uExitQual, VMXMEMACCESS_READ, &GCPtrDesc);
15065
15066 VBOXSTRICTRC rcStrict = IEMExecDecodedInvpcid(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->ExitInstrInfo.Inv.iSegReg,
15067 GCPtrDesc, uType);
15068 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15069 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15070 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15071 {
15072 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15073 rcStrict = VINF_SUCCESS;
15074 }
15075 return rcStrict;
15076#endif
15077}
15078
15079
15080/**
15081 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
15082 * VM-exit.
15083 */
15084HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15085{
15086 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15087 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15088 AssertRCReturn(rc, rc);
15089
15090 rc = hmR0VmxCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
15091 if (RT_FAILURE(rc))
15092 return rc;
15093
15094 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
15095 NOREF(uInvalidReason);
15096
15097#ifdef VBOX_STRICT
15098 uint32_t fIntrState;
15099 uint64_t u64Val;
15100 hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
15101 hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
15102 hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
15103
15104 Log4(("uInvalidReason %u\n", uInvalidReason));
15105 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
15106 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
15107 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
15108
15109 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState); AssertRC(rc);
15110 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
15111 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Val); AssertRC(rc);
15112 Log4(("VMX_VMCS_GUEST_CR0 %#RX64\n", u64Val));
15113 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_MASK, &u64Val); AssertRC(rc);
15114 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RX64\n", u64Val));
15115 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Val); AssertRC(rc);
15116 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
15117 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_MASK, &u64Val); AssertRC(rc);
15118 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RX64\n", u64Val));
15119 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Val); AssertRC(rc);
15120 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
15121 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging)
15122 {
15123 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
15124 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
15125 }
15126 hmR0DumpRegs(pVCpu, HM_DUMP_REG_FLAGS_ALL);
15127#endif
15128
15129 return VERR_VMX_INVALID_GUEST_STATE;
15130}
15131
15132/**
15133 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
15134 */
15135HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUnexpected(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15136{
15137 /*
15138 * Cumulative notes of all recognized but unexpected VM-exits.
15139 *
15140 * 1. This does -not- cover scenarios like a page-fault VM-exit occurring when
15141 * nested-paging is used.
15142 *
15143 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
15144 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
15145 * this function (and thereby stop VM execution) for handling such instructions.
15146 *
15147 *
15148 * VMX_EXIT_INIT_SIGNAL:
15149 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
15150 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
15151 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
15152 *
15153 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
15154 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
15155 * See Intel spec. "23.8 Restrictions on VMX operation".
15156 *
15157 * VMX_EXIT_SIPI:
15158 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
15159 * activity state is used. We don't make use of it as our guests don't have direct
15160 * access to the host local APIC.
15161 *
15162 * See Intel spec. 25.3 "Other Causes of VM-exits".
15163 *
15164 * VMX_EXIT_IO_SMI:
15165 * VMX_EXIT_SMI:
15166 * This can only happen if we support dual-monitor treatment of SMI, which can be
15167 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
15168 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
15169 * VMX root mode or receive an SMI. If we get here, something funny is going on.
15170 *
15171 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
15172 * See Intel spec. 25.3 "Other Causes of VM-Exits"
15173 *
15174 * VMX_EXIT_ERR_MSR_LOAD:
15175 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
15176 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
15177 * execution.
15178 *
15179 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
15180 *
15181 * VMX_EXIT_ERR_MACHINE_CHECK:
15182 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
15183 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
15184 * #MC exception abort class exception is raised. We thus cannot assume a
15185 * reasonable chance of continuing any sort of execution and we bail.
15186 *
15187 * See Intel spec. 15.1 "Machine-check Architecture".
15188 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
15189 *
15190 * VMX_EXIT_PML_FULL:
15191 * VMX_EXIT_VIRTUALIZED_EOI:
15192 * VMX_EXIT_APIC_WRITE:
15193 * We do not currently support any of these features and thus they are all unexpected
15194 * VM-exits.
15195 *
15196 * VMX_EXIT_GDTR_IDTR_ACCESS:
15197 * VMX_EXIT_LDTR_TR_ACCESS:
15198 * VMX_EXIT_RDRAND:
15199 * VMX_EXIT_RSM:
15200 * VMX_EXIT_VMFUNC:
15201 * VMX_EXIT_ENCLS:
15202 * VMX_EXIT_RDSEED:
15203 * VMX_EXIT_XSAVES:
15204 * VMX_EXIT_XRSTORS:
15205 * VMX_EXIT_UMWAIT:
15206 * VMX_EXIT_TPAUSE:
15207 * These VM-exits are -not- caused unconditionally by execution of the corresponding
15208 * instruction. Any VM-exit for these instructions indicate a hardware problem,
15209 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
15210 *
15211 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
15212 */
15213 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15214 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
15215 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
15216}
15217
15218
15219/**
15220 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
15221 */
15222HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15223{
15224 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15225
15226 /** @todo Optimize this: We currently drag in the whole MSR state
15227 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
15228 * MSRs required. That would require changes to IEM and possibly CPUM too.
15229 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
15230 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15231 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
15232 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
15233 switch (idMsr)
15234 {
15235 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
15236 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
15237 }
15238
15239 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15240 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
15241 AssertRCReturn(rc, rc);
15242
15243 Log4Func(("ecx=%#RX32\n", idMsr));
15244
15245#ifdef VBOX_STRICT
15246 Assert(!pVmxTransient->fIsNestedGuest);
15247 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
15248 {
15249 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
15250 && idMsr != MSR_K6_EFER)
15251 {
15252 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
15253 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15254 }
15255 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15256 {
15257 Assert(pVmcsInfo->pvMsrBitmap);
15258 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
15259 if (fMsrpm & VMXMSRPM_ALLOW_RD)
15260 {
15261 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
15262 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15263 }
15264 }
15265 }
15266#endif
15267
15268 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbExitInstr);
15269 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
15270 if (rcStrict == VINF_SUCCESS)
15271 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15272 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15273 {
15274 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15275 rcStrict = VINF_SUCCESS;
15276 }
15277 else
15278 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ || rcStrict == VINF_EM_TRIPLE_FAULT,
15279 ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
15280
15281 return rcStrict;
15282}
15283
15284
15285/**
15286 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
15287 */
15288HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15289{
15290 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15291
15292 /** @todo Optimize this: We currently drag in the whole MSR state
15293 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
15294 * MSRs required. That would require changes to IEM and possibly CPUM too.
15295 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
15296 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
15297 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
15298
15299 /*
15300 * The FS and GS base MSRs are not part of the above all-MSRs mask.
15301 * Although we don't need to fetch the base as it will be overwritten shortly, while
15302 * loading guest-state we would also load the entire segment register including limit
15303 * and attributes and thus we need to load them here.
15304 */
15305 switch (idMsr)
15306 {
15307 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
15308 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
15309 }
15310
15311 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15312 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15313 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
15314 AssertRCReturn(rc, rc);
15315
15316 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
15317
15318 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbExitInstr);
15319 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
15320
15321 if (rcStrict == VINF_SUCCESS)
15322 {
15323 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15324
15325 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
15326 if ( idMsr == MSR_IA32_APICBASE
15327 || ( idMsr >= MSR_IA32_X2APIC_START
15328 && idMsr <= MSR_IA32_X2APIC_END))
15329 {
15330 /*
15331 * We've already saved the APIC related guest-state (TPR) in post-run phase.
15332 * When full APIC register virtualization is implemented we'll have to make
15333 * sure APIC state is saved from the VMCS before IEM changes it.
15334 */
15335 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
15336 }
15337 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
15338 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
15339 else if (idMsr == MSR_K6_EFER)
15340 {
15341 /*
15342 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
15343 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
15344 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
15345 */
15346 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
15347 }
15348
15349 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
15350 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
15351 {
15352 switch (idMsr)
15353 {
15354 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
15355 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
15356 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
15357 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_FS); break;
15358 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_GS); break;
15359 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
15360 default:
15361 {
15362 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15363 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
15364 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
15365 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
15366 break;
15367 }
15368 }
15369 }
15370#ifdef VBOX_STRICT
15371 else
15372 {
15373 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
15374 switch (idMsr)
15375 {
15376 case MSR_IA32_SYSENTER_CS:
15377 case MSR_IA32_SYSENTER_EIP:
15378 case MSR_IA32_SYSENTER_ESP:
15379 case MSR_K8_FS_BASE:
15380 case MSR_K8_GS_BASE:
15381 {
15382 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
15383 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15384 }
15385
15386 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
15387 default:
15388 {
15389 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
15390 {
15391 /* EFER MSR writes are always intercepted. */
15392 if (idMsr != MSR_K6_EFER)
15393 {
15394 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
15395 idMsr));
15396 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15397 }
15398 }
15399
15400 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15401 {
15402 Assert(pVmcsInfo->pvMsrBitmap);
15403 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
15404 if (fMsrpm & VMXMSRPM_ALLOW_WR)
15405 {
15406 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
15407 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15408 }
15409 }
15410 break;
15411 }
15412 }
15413 }
15414#endif /* VBOX_STRICT */
15415 }
15416 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15417 {
15418 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15419 rcStrict = VINF_SUCCESS;
15420 }
15421 else
15422 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE || rcStrict == VINF_EM_TRIPLE_FAULT,
15423 ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
15424
15425 return rcStrict;
15426}
15427
15428
15429/**
15430 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
15431 */
15432HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15433{
15434 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15435
15436 /** @todo The guest has likely hit a contended spinlock. We might want to
15437 * poke a schedule different guest VCPU. */
15438 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15439 if (RT_SUCCESS(rc))
15440 return VINF_EM_RAW_INTERRUPT;
15441
15442 AssertMsgFailed(("hmR0VmxExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
15443 return rc;
15444}
15445
15446
15447/**
15448 * VM-exit handler for when the TPR value is lowered below the specified
15449 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
15450 */
15451HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15452{
15453 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15454 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
15455
15456 /*
15457 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
15458 * We'll re-evaluate pending interrupts and inject them before the next VM
15459 * entry so we can just continue execution here.
15460 */
15461 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
15462 return VINF_SUCCESS;
15463}
15464
15465
15466/**
15467 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
15468 * VM-exit.
15469 *
15470 * @retval VINF_SUCCESS when guest execution can continue.
15471 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
15472 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
15473 * incompatible guest state for VMX execution (real-on-v86 case).
15474 */
15475HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15476{
15477 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15478 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
15479
15480 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15481 hmR0VmxReadExitQualVmcs(pVmxTransient);
15482 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15483
15484 VBOXSTRICTRC rcStrict;
15485 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15486 uint64_t const uExitQual = pVmxTransient->uExitQual;
15487 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
15488 switch (uAccessType)
15489 {
15490 /*
15491 * MOV to CRx.
15492 */
15493 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
15494 {
15495 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15496 AssertRCReturn(rc, rc);
15497
15498 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
15499 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
15500 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15501 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15502
15503 /*
15504 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
15505 * - When nested paging isn't used.
15506 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
15507 * - We are executing in the VM debug loop.
15508 */
15509 Assert( iCrReg != 3
15510 || !pVM->hmr0.s.fNestedPaging
15511 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15512 || pVCpu->hmr0.s.fUsingDebugLoop);
15513
15514 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
15515 Assert( iCrReg != 8
15516 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15517
15518 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15519 AssertMsg( rcStrict == VINF_SUCCESS
15520 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15521
15522 /*
15523 * This is a kludge for handling switches back to real mode when we try to use
15524 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
15525 * deal with special selector values, so we have to return to ring-3 and run
15526 * there till the selector values are V86 mode compatible.
15527 *
15528 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
15529 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
15530 * this function.
15531 */
15532 if ( iCrReg == 0
15533 && rcStrict == VINF_SUCCESS
15534 && !pVM->hmr0.s.vmx.fUnrestrictedGuest
15535 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
15536 && (uOldCr0 & X86_CR0_PE)
15537 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
15538 {
15539 /** @todo Check selectors rather than returning all the time. */
15540 Assert(!pVmxTransient->fIsNestedGuest);
15541 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
15542 rcStrict = VINF_EM_RESCHEDULE_REM;
15543 }
15544 break;
15545 }
15546
15547 /*
15548 * MOV from CRx.
15549 */
15550 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
15551 {
15552 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15553 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15554
15555 /*
15556 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
15557 * - When nested paging isn't used.
15558 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
15559 * - We are executing in the VM debug loop.
15560 */
15561 Assert( iCrReg != 3
15562 || !pVM->hmr0.s.fNestedPaging
15563 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15564 || pVCpu->hmr0.s.fLeaveDone);
15565
15566 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
15567 Assert( iCrReg != 8
15568 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15569
15570 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15571 break;
15572 }
15573
15574 /*
15575 * CLTS (Clear Task-Switch Flag in CR0).
15576 */
15577 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
15578 {
15579 rcStrict = hmR0VmxExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr);
15580 break;
15581 }
15582
15583 /*
15584 * LMSW (Load Machine-Status Word into CR0).
15585 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
15586 */
15587 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
15588 {
15589 RTGCPTR GCPtrEffDst;
15590 uint8_t const cbInstr = pVmxTransient->cbExitInstr;
15591 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
15592 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
15593 if (fMemOperand)
15594 {
15595 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
15596 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
15597 }
15598 else
15599 GCPtrEffDst = NIL_RTGCPTR;
15600 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
15601 break;
15602 }
15603
15604 default:
15605 {
15606 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
15607 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
15608 }
15609 }
15610
15611 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
15612 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
15613 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15614
15615 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
15616 NOREF(pVM);
15617 return rcStrict;
15618}
15619
15620
15621/**
15622 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
15623 * VM-exit.
15624 */
15625HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15626{
15627 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15628 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
15629
15630 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15631 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15632 hmR0VmxReadExitQualVmcs(pVmxTransient);
15633 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15634 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK
15635 | CPUMCTX_EXTRN_EFER);
15636 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
15637 AssertRCReturn(rc, rc);
15638
15639 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
15640 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
15641 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
15642 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
15643 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
15644 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
15645 bool const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
15646 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
15647
15648 /*
15649 * Update exit history to see if this exit can be optimized.
15650 */
15651 VBOXSTRICTRC rcStrict;
15652 PCEMEXITREC pExitRec = NULL;
15653 if ( !fGstStepping
15654 && !fDbgStepping)
15655 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15656 !fIOString
15657 ? !fIOWrite
15658 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
15659 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
15660 : !fIOWrite
15661 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
15662 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
15663 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15664 if (!pExitRec)
15665 {
15666 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
15667 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
15668
15669 uint32_t const cbValue = s_aIOSizes[uIOSize];
15670 uint32_t const cbInstr = pVmxTransient->cbExitInstr;
15671 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
15672 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15673 if (fIOString)
15674 {
15675 /*
15676 * INS/OUTS - I/O String instruction.
15677 *
15678 * Use instruction-information if available, otherwise fall back on
15679 * interpreting the instruction.
15680 */
15681 Log4Func(("cs:rip=%#04x:%#RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15682 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
15683 bool const fInsOutsInfo = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
15684 if (fInsOutsInfo)
15685 {
15686 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15687 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
15688 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
15689 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
15690 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
15691 if (fIOWrite)
15692 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
15693 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
15694 else
15695 {
15696 /*
15697 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
15698 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
15699 * See Intel Instruction spec. for "INS".
15700 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
15701 */
15702 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
15703 }
15704 }
15705 else
15706 rcStrict = IEMExecOne(pVCpu);
15707
15708 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15709 fUpdateRipAlready = true;
15710 }
15711 else
15712 {
15713 /*
15714 * IN/OUT - I/O instruction.
15715 */
15716 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15717 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
15718 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
15719 if (fIOWrite)
15720 {
15721 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
15722 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
15723 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15724 && !pCtx->eflags.Bits.u1TF)
15725 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
15726 }
15727 else
15728 {
15729 uint32_t u32Result = 0;
15730 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
15731 if (IOM_SUCCESS(rcStrict))
15732 {
15733 /* Save result of I/O IN instr. in AL/AX/EAX. */
15734 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
15735 }
15736 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15737 && !pCtx->eflags.Bits.u1TF)
15738 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
15739 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
15740 }
15741 }
15742
15743 if (IOM_SUCCESS(rcStrict))
15744 {
15745 if (!fUpdateRipAlready)
15746 {
15747 hmR0VmxAdvanceGuestRipBy(pVCpu, cbInstr);
15748 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15749 }
15750
15751 /*
15752 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
15753 * while booting Fedora 17 64-bit guest.
15754 *
15755 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
15756 */
15757 if (fIOString)
15758 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
15759
15760 /*
15761 * If any I/O breakpoints are armed, we need to check if one triggered
15762 * and take appropriate action.
15763 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
15764 */
15765 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_DR7);
15766 AssertRCReturn(rc, rc);
15767
15768 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
15769 * execution engines about whether hyper BPs and such are pending. */
15770 uint32_t const uDr7 = pCtx->dr[7];
15771 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
15772 && X86_DR7_ANY_RW_IO(uDr7)
15773 && (pCtx->cr4 & X86_CR4_DE))
15774 || DBGFBpIsHwIoArmed(pVM)))
15775 {
15776 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
15777
15778 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
15779 VMMRZCallRing3Disable(pVCpu);
15780 HM_DISABLE_PREEMPT(pVCpu);
15781
15782 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
15783
15784 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
15785 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
15786 {
15787 /* Raise #DB. */
15788 if (fIsGuestDbgActive)
15789 ASMSetDR6(pCtx->dr[6]);
15790 if (pCtx->dr[7] != uDr7)
15791 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_DR7;
15792
15793 hmR0VmxSetPendingXcptDB(pVCpu);
15794 }
15795 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
15796 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
15797 else if ( rcStrict2 != VINF_SUCCESS
15798 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
15799 rcStrict = rcStrict2;
15800 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
15801
15802 HM_RESTORE_PREEMPT();
15803 VMMRZCallRing3Enable(pVCpu);
15804 }
15805 }
15806
15807#ifdef VBOX_STRICT
15808 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15809 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
15810 Assert(!fIOWrite);
15811 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15812 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
15813 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
15814 Assert(fIOWrite);
15815 else
15816 {
15817# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
15818 * statuses, that the VMM device and some others may return. See
15819 * IOM_SUCCESS() for guidance. */
15820 AssertMsg( RT_FAILURE(rcStrict)
15821 || rcStrict == VINF_SUCCESS
15822 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
15823 || rcStrict == VINF_EM_DBG_BREAKPOINT
15824 || rcStrict == VINF_EM_RAW_GUEST_TRAP
15825 || rcStrict == VINF_EM_RAW_TO_R3
15826 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15827# endif
15828 }
15829#endif
15830 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
15831 }
15832 else
15833 {
15834 /*
15835 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
15836 */
15837 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15838 AssertRCReturn(rc2, rc2);
15839 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &pVCpu->hm.s.StatExitIOWrite : &pVCpu->hm.s.StatExitIORead
15840 : fIOWrite ? &pVCpu->hm.s.StatExitIOStringWrite : &pVCpu->hm.s.StatExitIOStringRead);
15841 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
15842 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15843 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
15844 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
15845
15846 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15847 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15848
15849 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15850 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15851 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15852 }
15853 return rcStrict;
15854}
15855
15856
15857/**
15858 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
15859 * VM-exit.
15860 */
15861HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15862{
15863 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15864
15865 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
15866 hmR0VmxReadExitQualVmcs(pVmxTransient);
15867 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
15868 {
15869 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15870 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
15871 {
15872 uint32_t uErrCode;
15873 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
15874 {
15875 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15876 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
15877 }
15878 else
15879 uErrCode = 0;
15880
15881 RTGCUINTPTR GCPtrFaultAddress;
15882 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
15883 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
15884 else
15885 GCPtrFaultAddress = 0;
15886
15887 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15888
15889 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
15890 pVmxTransient->cbExitInstr, uErrCode, GCPtrFaultAddress);
15891
15892 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
15893 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
15894 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15895 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15896 }
15897 }
15898
15899 /* Fall back to the interpreter to emulate the task-switch. */
15900 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15901 return VERR_EM_INTERPRETER;
15902}
15903
15904
15905/**
15906 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
15907 */
15908HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15909{
15910 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15911
15912 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15913 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
15914 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15915 AssertRC(rc);
15916 return VINF_EM_DBG_STEPPED;
15917}
15918
15919
15920/**
15921 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
15922 */
15923HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15924{
15925 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15926 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
15927
15928 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15929 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15930 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15931 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15932 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15933
15934 /*
15935 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15936 */
15937 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15938 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15939 {
15940 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
15941 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
15942 {
15943 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15944 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15945 }
15946 }
15947 else
15948 {
15949 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15950 return rcStrict;
15951 }
15952
15953 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
15954 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15955 hmR0VmxReadExitQualVmcs(pVmxTransient);
15956 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15957 AssertRCReturn(rc, rc);
15958
15959 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
15960 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
15961 switch (uAccessType)
15962 {
15963 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
15964 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
15965 {
15966 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
15967 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
15968 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
15969
15970 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
15971 GCPhys &= PAGE_BASE_GC_MASK;
15972 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
15973 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
15974 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
15975
15976 rcStrict = IOMR0MmioPhysHandler(pVCpu->CTX_SUFF(pVM), pVCpu,
15977 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW, GCPhys);
15978 Log4Func(("IOMMMIOPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15979 if ( rcStrict == VINF_SUCCESS
15980 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
15981 || rcStrict == VERR_PAGE_NOT_PRESENT)
15982 {
15983 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
15984 | HM_CHANGED_GUEST_APIC_TPR);
15985 rcStrict = VINF_SUCCESS;
15986 }
15987 break;
15988 }
15989
15990 default:
15991 {
15992 Log4Func(("uAccessType=%#x\n", uAccessType));
15993 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
15994 break;
15995 }
15996 }
15997
15998 if (rcStrict != VINF_SUCCESS)
15999 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
16000 return rcStrict;
16001}
16002
16003
16004/**
16005 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
16006 * VM-exit.
16007 */
16008HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16009{
16010 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16011 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16012
16013 /* We might get this VM-exit if the nested-guest is not intercepting MOV DRx accesses. */
16014 if (!pVmxTransient->fIsNestedGuest)
16015 {
16016 /* We should -not- get this VM-exit if the guest's debug registers were active. */
16017 if (pVmxTransient->fWasGuestDebugStateActive)
16018 {
16019 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
16020 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
16021 }
16022
16023 if ( !pVCpu->hm.s.fSingleInstruction
16024 && !pVmxTransient->fWasHyperDebugStateActive)
16025 {
16026 Assert(!DBGFIsStepping(pVCpu));
16027 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
16028
16029 /* Don't intercept MOV DRx any more. */
16030 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
16031 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
16032 AssertRC(rc);
16033
16034 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
16035 VMMRZCallRing3Disable(pVCpu);
16036 HM_DISABLE_PREEMPT(pVCpu);
16037
16038 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
16039 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
16040 Assert(CPUMIsGuestDebugStateActive(pVCpu));
16041
16042 HM_RESTORE_PREEMPT();
16043 VMMRZCallRing3Enable(pVCpu);
16044
16045#ifdef VBOX_WITH_STATISTICS
16046 hmR0VmxReadExitQualVmcs(pVmxTransient);
16047 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
16048 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
16049 else
16050 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
16051#endif
16052 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
16053 return VINF_SUCCESS;
16054 }
16055 }
16056
16057 /*
16058 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER MSR, CS.
16059 * The EFER MSR is always up-to-date.
16060 * Update the segment registers and DR7 from the CPU.
16061 */
16062 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16063 hmR0VmxReadExitQualVmcs(pVmxTransient);
16064 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_DR7);
16065 AssertRCReturn(rc, rc);
16066 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
16067
16068 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16069 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
16070 {
16071 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
16072 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual),
16073 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual));
16074 if (RT_SUCCESS(rc))
16075 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
16076 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
16077 }
16078 else
16079 {
16080 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
16081 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual),
16082 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual));
16083 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
16084 }
16085
16086 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
16087 if (RT_SUCCESS(rc))
16088 {
16089 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
16090 AssertRCReturn(rc2, rc2);
16091 return VINF_SUCCESS;
16092 }
16093 return rc;
16094}
16095
16096
16097/**
16098 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
16099 * Conditional VM-exit.
16100 */
16101HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16102{
16103 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16104 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16105
16106 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16107 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16108 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16109 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16110 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16111
16112 /*
16113 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
16114 */
16115 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
16116 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16117 {
16118 /*
16119 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
16120 * instruction emulation to inject the original event. Otherwise, injecting the original event
16121 * using hardware-assisted VMX would trigger the same EPT misconfig VM-exit again.
16122 */
16123 if (!pVCpu->hm.s.Event.fPending)
16124 { /* likely */ }
16125 else
16126 {
16127 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
16128#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16129 /** @todo NSTVMX: Think about how this should be handled. */
16130 if (pVmxTransient->fIsNestedGuest)
16131 return VERR_VMX_IPE_3;
16132#endif
16133 return VINF_EM_RAW_INJECT_TRPM_EVENT;
16134 }
16135 }
16136 else
16137 {
16138 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
16139 return rcStrict;
16140 }
16141
16142 /*
16143 * Get sufficient state and update the exit history entry.
16144 */
16145 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16146 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
16147 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
16148 AssertRCReturn(rc, rc);
16149
16150 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
16151 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
16152 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
16153 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
16154 if (!pExitRec)
16155 {
16156 /*
16157 * If we succeed, resume guest execution.
16158 * If we fail in interpreting the instruction because we couldn't get the guest physical address
16159 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
16160 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
16161 * weird case. See @bugref{6043}.
16162 */
16163 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16164 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16165/** @todo bird: We can probably just go straight to IOM here and assume that
16166 * it's MMIO, then fall back on PGM if that hunch didn't work out so
16167 * well. However, we need to address that aliasing workarounds that
16168 * PGMR0Trap0eHandlerNPMisconfig implements. So, some care is needed.
16169 *
16170 * Might also be interesting to see if we can get this done more or
16171 * less locklessly inside IOM. Need to consider the lookup table
16172 * updating and use a bit more carefully first (or do all updates via
16173 * rendezvous) */
16174 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
16175 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pCtx->rip, VBOXSTRICTRC_VAL(rcStrict)));
16176 if ( rcStrict == VINF_SUCCESS
16177 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16178 || rcStrict == VERR_PAGE_NOT_PRESENT)
16179 {
16180 /* Successfully handled MMIO operation. */
16181 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
16182 | HM_CHANGED_GUEST_APIC_TPR);
16183 rcStrict = VINF_SUCCESS;
16184 }
16185 }
16186 else
16187 {
16188 /*
16189 * Frequent exit or something needing probing. Call EMHistoryExec.
16190 */
16191 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
16192 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
16193
16194 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
16195 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16196
16197 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
16198 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
16199 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
16200 }
16201 return rcStrict;
16202}
16203
16204
16205/**
16206 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
16207 * VM-exit.
16208 */
16209HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16210{
16211 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16212 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16213
16214 hmR0VmxReadExitQualVmcs(pVmxTransient);
16215 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16216 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16217 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16218 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16219 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16220
16221 /*
16222 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
16223 */
16224 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
16225 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16226 {
16227 /*
16228 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
16229 * we shall resolve the nested #PF and re-inject the original event.
16230 */
16231 if (pVCpu->hm.s.Event.fPending)
16232 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflectNPF);
16233 }
16234 else
16235 {
16236 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
16237 return rcStrict;
16238 }
16239
16240 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16241 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
16242 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
16243 AssertRCReturn(rc, rc);
16244
16245 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
16246 uint64_t const uExitQual = pVmxTransient->uExitQual;
16247 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
16248
16249 RTGCUINT uErrorCode = 0;
16250 if (uExitQual & VMX_EXIT_QUAL_EPT_INSTR_FETCH)
16251 uErrorCode |= X86_TRAP_PF_ID;
16252 if (uExitQual & VMX_EXIT_QUAL_EPT_DATA_WRITE)
16253 uErrorCode |= X86_TRAP_PF_RW;
16254 if (uExitQual & VMX_EXIT_QUAL_EPT_ENTRY_PRESENT)
16255 uErrorCode |= X86_TRAP_PF_P;
16256
16257 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16258 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16259 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%#RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
16260
16261 /*
16262 * Handle the pagefault trap for the nested shadow table.
16263 */
16264 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
16265 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pCtx), GCPhys);
16266 TRPMResetTrap(pVCpu);
16267
16268 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
16269 if ( rcStrict == VINF_SUCCESS
16270 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16271 || rcStrict == VERR_PAGE_NOT_PRESENT)
16272 {
16273 /* Successfully synced our nested page tables. */
16274 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
16275 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
16276 return VINF_SUCCESS;
16277 }
16278
16279 Log4Func(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
16280 return rcStrict;
16281}
16282
16283
16284#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16285/**
16286 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
16287 */
16288HMVMX_EXIT_DECL hmR0VmxExitVmclear(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16289{
16290 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16291
16292 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16293 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16294 hmR0VmxReadExitQualVmcs(pVmxTransient);
16295 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16296 | CPUMCTX_EXTRN_HWVIRT
16297 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16298 AssertRCReturn(rc, rc);
16299
16300 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16301
16302 VMXVEXITINFO ExitInfo;
16303 RT_ZERO(ExitInfo);
16304 ExitInfo.uReason = pVmxTransient->uExitReason;
16305 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16306 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16307 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16308 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16309
16310 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
16311 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16312 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16313 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16314 {
16315 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16316 rcStrict = VINF_SUCCESS;
16317 }
16318 return rcStrict;
16319}
16320
16321
16322/**
16323 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
16324 */
16325HMVMX_EXIT_DECL hmR0VmxExitVmlaunch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16326{
16327 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16328
16329 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
16330 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
16331 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16332 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16333 AssertRCReturn(rc, rc);
16334
16335 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16336
16337 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
16338 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMLAUNCH);
16339 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
16340 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16341 {
16342 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16343 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
16344 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
16345 }
16346 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
16347 return rcStrict;
16348}
16349
16350
16351/**
16352 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
16353 */
16354HMVMX_EXIT_DECL hmR0VmxExitVmptrld(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16355{
16356 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16357
16358 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16359 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16360 hmR0VmxReadExitQualVmcs(pVmxTransient);
16361 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16362 | CPUMCTX_EXTRN_HWVIRT
16363 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16364 AssertRCReturn(rc, rc);
16365
16366 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16367
16368 VMXVEXITINFO ExitInfo;
16369 RT_ZERO(ExitInfo);
16370 ExitInfo.uReason = pVmxTransient->uExitReason;
16371 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16372 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16373 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16374 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16375
16376 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
16377 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16378 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16379 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16380 {
16381 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16382 rcStrict = VINF_SUCCESS;
16383 }
16384 return rcStrict;
16385}
16386
16387
16388/**
16389 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
16390 */
16391HMVMX_EXIT_DECL hmR0VmxExitVmptrst(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16392{
16393 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16394
16395 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16396 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16397 hmR0VmxReadExitQualVmcs(pVmxTransient);
16398 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16399 | CPUMCTX_EXTRN_HWVIRT
16400 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16401 AssertRCReturn(rc, rc);
16402
16403 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16404
16405 VMXVEXITINFO ExitInfo;
16406 RT_ZERO(ExitInfo);
16407 ExitInfo.uReason = pVmxTransient->uExitReason;
16408 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16409 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16410 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16411 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
16412
16413 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
16414 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16415 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16416 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16417 {
16418 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16419 rcStrict = VINF_SUCCESS;
16420 }
16421 return rcStrict;
16422}
16423
16424
16425/**
16426 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
16427 */
16428HMVMX_EXIT_DECL hmR0VmxExitVmread(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16429{
16430 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16431
16432 /*
16433 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
16434 * thus might not need to import the shadow VMCS state, it's safer just in case
16435 * code elsewhere dares look at unsynced VMCS fields.
16436 */
16437 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16438 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16439 hmR0VmxReadExitQualVmcs(pVmxTransient);
16440 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16441 | CPUMCTX_EXTRN_HWVIRT
16442 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16443 AssertRCReturn(rc, rc);
16444
16445 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16446
16447 VMXVEXITINFO ExitInfo;
16448 RT_ZERO(ExitInfo);
16449 ExitInfo.uReason = pVmxTransient->uExitReason;
16450 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16451 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16452 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16453 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
16454 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
16455
16456 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
16457 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16458 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16459 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16460 {
16461 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16462 rcStrict = VINF_SUCCESS;
16463 }
16464 return rcStrict;
16465}
16466
16467
16468/**
16469 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
16470 */
16471HMVMX_EXIT_DECL hmR0VmxExitVmresume(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16472{
16473 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16474
16475 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
16476 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
16477 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16478 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16479 AssertRCReturn(rc, rc);
16480
16481 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16482
16483 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
16484 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMRESUME);
16485 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
16486 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16487 {
16488 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16489 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
16490 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
16491 }
16492 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
16493 return rcStrict;
16494}
16495
16496
16497/**
16498 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
16499 */
16500HMVMX_EXIT_DECL hmR0VmxExitVmwrite(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16501{
16502 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16503
16504 /*
16505 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
16506 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
16507 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
16508 */
16509 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16510 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16511 hmR0VmxReadExitQualVmcs(pVmxTransient);
16512 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16513 | CPUMCTX_EXTRN_HWVIRT
16514 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16515 AssertRCReturn(rc, rc);
16516
16517 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16518
16519 VMXVEXITINFO ExitInfo;
16520 RT_ZERO(ExitInfo);
16521 ExitInfo.uReason = pVmxTransient->uExitReason;
16522 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16523 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16524 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16525 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
16526 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16527
16528 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
16529 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16530 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16531 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16532 {
16533 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16534 rcStrict = VINF_SUCCESS;
16535 }
16536 return rcStrict;
16537}
16538
16539
16540/**
16541 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
16542 */
16543HMVMX_EXIT_DECL hmR0VmxExitVmxoff(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16544{
16545 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16546
16547 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16548 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
16549 | CPUMCTX_EXTRN_HWVIRT
16550 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
16551 AssertRCReturn(rc, rc);
16552
16553 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16554
16555 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbExitInstr);
16556 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16557 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
16558 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16559 {
16560 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16561 rcStrict = VINF_SUCCESS;
16562 }
16563 return rcStrict;
16564}
16565
16566
16567/**
16568 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
16569 */
16570HMVMX_EXIT_DECL hmR0VmxExitVmxon(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16571{
16572 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16573
16574 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16575 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16576 hmR0VmxReadExitQualVmcs(pVmxTransient);
16577 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16578 | CPUMCTX_EXTRN_HWVIRT
16579 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16580 AssertRCReturn(rc, rc);
16581
16582 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16583
16584 VMXVEXITINFO ExitInfo;
16585 RT_ZERO(ExitInfo);
16586 ExitInfo.uReason = pVmxTransient->uExitReason;
16587 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16588 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16589 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16590 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16591
16592 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
16593 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16594 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16595 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16596 {
16597 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16598 rcStrict = VINF_SUCCESS;
16599 }
16600 return rcStrict;
16601}
16602
16603
16604/**
16605 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
16606 */
16607HMVMX_EXIT_DECL hmR0VmxExitInvvpid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16608{
16609 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16610
16611 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16612 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16613 hmR0VmxReadExitQualVmcs(pVmxTransient);
16614 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16615 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16616 AssertRCReturn(rc, rc);
16617
16618 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16619
16620 VMXVEXITINFO ExitInfo;
16621 RT_ZERO(ExitInfo);
16622 ExitInfo.uReason = pVmxTransient->uExitReason;
16623 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16624 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16625 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16626 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16627
16628 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
16629 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16630 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16631 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16632 {
16633 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16634 rcStrict = VINF_SUCCESS;
16635 }
16636 return rcStrict;
16637}
16638#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16639/** @} */
16640
16641
16642#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16643/** @name Nested-guest VM-exit handlers.
16644 * @{
16645 */
16646/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16647/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16648/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16649
16650/**
16651 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
16652 * Conditional VM-exit.
16653 */
16654HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16655{
16656 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16657
16658 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16659
16660 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
16661 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
16662 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
16663
16664 switch (uExitIntType)
16665 {
16666 /*
16667 * Physical NMIs:
16668 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
16669 */
16670 case VMX_EXIT_INT_INFO_TYPE_NMI:
16671 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
16672
16673 /*
16674 * Hardware exceptions,
16675 * Software exceptions,
16676 * Privileged software exceptions:
16677 * Figure out if the exception must be delivered to the guest or the nested-guest.
16678 */
16679 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
16680 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
16681 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
16682 {
16683 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16684 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16685 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16686 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16687
16688 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16689 bool const fIntercept = CPUMIsGuestVmxXcptInterceptSet(pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo),
16690 pVmxTransient->uExitIntErrorCode);
16691 if (fIntercept)
16692 {
16693 /* Exit qualification is required for debug and page-fault exceptions. */
16694 hmR0VmxReadExitQualVmcs(pVmxTransient);
16695
16696 /*
16697 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
16698 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
16699 * length. However, if delivery of a software interrupt, software exception or privileged
16700 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
16701 */
16702 VMXVEXITINFO ExitInfo;
16703 RT_ZERO(ExitInfo);
16704 ExitInfo.uReason = pVmxTransient->uExitReason;
16705 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16706 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16707
16708 VMXVEXITEVENTINFO ExitEventInfo;
16709 RT_ZERO(ExitEventInfo);
16710 ExitEventInfo.uExitIntInfo = pVmxTransient->uExitIntInfo;
16711 ExitEventInfo.uExitIntErrCode = pVmxTransient->uExitIntErrorCode;
16712 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16713 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16714
16715#ifdef DEBUG_ramshankar
16716 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16717 Log4Func(("exit_int_info=%#RX32 err_code=%#RX32 exit_qual=%#RX64\n", pVmxTransient->uExitIntInfo,
16718 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
16719 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
16720 {
16721 Log4Func(("idt_info=%#RX32 idt_errcode=%#RX32 cr2=%#RX64\n", pVmxTransient->uIdtVectoringInfo,
16722 pVmxTransient->uIdtVectoringErrorCode, pCtx->cr2));
16723 }
16724#endif
16725 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo);
16726 }
16727
16728 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs in hmR0VmxExitXcptPF. */
16729 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16730 return hmR0VmxExitXcpt(pVCpu, pVmxTransient);
16731 }
16732
16733 /*
16734 * Software interrupts:
16735 * VM-exits cannot be caused by software interrupts.
16736 *
16737 * External interrupts:
16738 * This should only happen when "acknowledge external interrupts on VM-exit"
16739 * control is set. However, we never set this when executing a guest or
16740 * nested-guest. For nested-guests it is emulated while injecting interrupts into
16741 * the guest.
16742 */
16743 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
16744 case VMX_EXIT_INT_INFO_TYPE_EXT_INT:
16745 default:
16746 {
16747 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
16748 return VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
16749 }
16750 }
16751}
16752
16753
16754/**
16755 * Nested-guest VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT).
16756 * Unconditional VM-exit.
16757 */
16758HMVMX_EXIT_DECL hmR0VmxExitTripleFaultNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16759{
16760 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16761 return IEMExecVmxVmexitTripleFault(pVCpu);
16762}
16763
16764
16765/**
16766 * Nested-guest VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
16767 */
16768HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16769{
16770 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16771
16772 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
16773 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16774 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16775}
16776
16777
16778/**
16779 * Nested-guest VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
16780 */
16781HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16782{
16783 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16784
16785 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
16786 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16787 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16788}
16789
16790
16791/**
16792 * Nested-guest VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH).
16793 * Unconditional VM-exit.
16794 */
16795HMVMX_EXIT_DECL hmR0VmxExitTaskSwitchNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16796{
16797 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16798
16799 hmR0VmxReadExitQualVmcs(pVmxTransient);
16800 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16801 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16802 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16803
16804 VMXVEXITINFO ExitInfo;
16805 RT_ZERO(ExitInfo);
16806 ExitInfo.uReason = pVmxTransient->uExitReason;
16807 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16808 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16809
16810 VMXVEXITEVENTINFO ExitEventInfo;
16811 RT_ZERO(ExitEventInfo);
16812 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16813 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16814 return IEMExecVmxVmexitTaskSwitch(pVCpu, &ExitInfo, &ExitEventInfo);
16815}
16816
16817
16818/**
16819 * Nested-guest VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
16820 */
16821HMVMX_EXIT_DECL hmR0VmxExitHltNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16822{
16823 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16824
16825 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_HLT_EXIT))
16826 {
16827 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16828 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16829 }
16830 return hmR0VmxExitHlt(pVCpu, pVmxTransient);
16831}
16832
16833
16834/**
16835 * Nested-guest VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
16836 */
16837HMVMX_EXIT_DECL hmR0VmxExitInvlpgNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16838{
16839 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16840
16841 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16842 {
16843 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16844 hmR0VmxReadExitQualVmcs(pVmxTransient);
16845
16846 VMXVEXITINFO ExitInfo;
16847 RT_ZERO(ExitInfo);
16848 ExitInfo.uReason = pVmxTransient->uExitReason;
16849 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16850 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16851 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16852 }
16853 return hmR0VmxExitInvlpg(pVCpu, pVmxTransient);
16854}
16855
16856
16857/**
16858 * Nested-guest VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
16859 */
16860HMVMX_EXIT_DECL hmR0VmxExitRdpmcNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16861{
16862 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16863
16864 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDPMC_EXIT))
16865 {
16866 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16867 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16868 }
16869 return hmR0VmxExitRdpmc(pVCpu, pVmxTransient);
16870}
16871
16872
16873/**
16874 * Nested-guest VM-exit handler for VMREAD (VMX_EXIT_VMREAD) and VMWRITE
16875 * (VMX_EXIT_VMWRITE). Conditional VM-exit.
16876 */
16877HMVMX_EXIT_DECL hmR0VmxExitVmreadVmwriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16878{
16879 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16880
16881 Assert( pVmxTransient->uExitReason == VMX_EXIT_VMREAD
16882 || pVmxTransient->uExitReason == VMX_EXIT_VMWRITE);
16883
16884 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16885
16886 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
16887 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16888 uint64_t u64VmcsField = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16889
16890 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
16891 if (!CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
16892 u64VmcsField &= UINT64_C(0xffffffff);
16893
16894 if (CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, pVmxTransient->uExitReason, u64VmcsField))
16895 {
16896 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16897 hmR0VmxReadExitQualVmcs(pVmxTransient);
16898
16899 VMXVEXITINFO ExitInfo;
16900 RT_ZERO(ExitInfo);
16901 ExitInfo.uReason = pVmxTransient->uExitReason;
16902 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16903 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16904 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16905 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16906 }
16907
16908 if (pVmxTransient->uExitReason == VMX_EXIT_VMREAD)
16909 return hmR0VmxExitVmread(pVCpu, pVmxTransient);
16910 return hmR0VmxExitVmwrite(pVCpu, pVmxTransient);
16911}
16912
16913
16914/**
16915 * Nested-guest VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
16916 */
16917HMVMX_EXIT_DECL hmR0VmxExitRdtscNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16918{
16919 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16920
16921 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16922 {
16923 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16924 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16925 }
16926
16927 return hmR0VmxExitRdtsc(pVCpu, pVmxTransient);
16928}
16929
16930
16931/**
16932 * Nested-guest VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX).
16933 * Conditional VM-exit.
16934 */
16935HMVMX_EXIT_DECL hmR0VmxExitMovCRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16936{
16937 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16938
16939 hmR0VmxReadExitQualVmcs(pVmxTransient);
16940 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16941
16942 VBOXSTRICTRC rcStrict;
16943 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual);
16944 switch (uAccessType)
16945 {
16946 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
16947 {
16948 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16949 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16950 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16951 uint64_t const uNewCrX = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16952
16953 bool fIntercept;
16954 switch (iCrReg)
16955 {
16956 case 0:
16957 case 4:
16958 fIntercept = CPUMIsGuestVmxMovToCr0Cr4InterceptSet(&pVCpu->cpum.GstCtx, iCrReg, uNewCrX);
16959 break;
16960
16961 case 3:
16962 fIntercept = CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCrX);
16963 break;
16964
16965 case 8:
16966 fIntercept = CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_CR8_LOAD_EXIT);
16967 break;
16968
16969 default:
16970 fIntercept = false;
16971 break;
16972 }
16973 if (fIntercept)
16974 {
16975 VMXVEXITINFO ExitInfo;
16976 RT_ZERO(ExitInfo);
16977 ExitInfo.uReason = pVmxTransient->uExitReason;
16978 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16979 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16980 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16981 }
16982 else
16983 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
16984 break;
16985 }
16986
16987 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
16988 {
16989 /*
16990 * CR0/CR4 reads do not cause VM-exits, the read-shadow is used (subject to masking).
16991 * CR2 reads do not cause a VM-exit.
16992 * CR3 reads cause a VM-exit depending on the "CR3 store exiting" control.
16993 * CR8 reads cause a VM-exit depending on the "CR8 store exiting" control.
16994 */
16995 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16996 if ( iCrReg == 3
16997 || iCrReg == 8)
16998 {
16999 static const uint32_t s_auCrXReadIntercepts[] = { 0, 0, 0, VMX_PROC_CTLS_CR3_STORE_EXIT, 0,
17000 0, 0, 0, VMX_PROC_CTLS_CR8_STORE_EXIT };
17001 uint32_t const uIntercept = s_auCrXReadIntercepts[iCrReg];
17002 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uIntercept))
17003 {
17004 VMXVEXITINFO ExitInfo;
17005 RT_ZERO(ExitInfo);
17006 ExitInfo.uReason = pVmxTransient->uExitReason;
17007 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17008 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17009 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17010 }
17011 else
17012 {
17013 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
17014 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
17015 }
17016 }
17017 else
17018 {
17019 AssertMsgFailed(("MOV from CR%d VM-exit must not happen\n", iCrReg));
17020 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, iCrReg);
17021 }
17022 break;
17023 }
17024
17025 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
17026 {
17027 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
17028 Assert(pVmcsNstGst);
17029 uint64_t const uGstHostMask = pVmcsNstGst->u64Cr0Mask.u;
17030 uint64_t const uReadShadow = pVmcsNstGst->u64Cr0ReadShadow.u;
17031 if ( (uGstHostMask & X86_CR0_TS)
17032 && (uReadShadow & X86_CR0_TS))
17033 {
17034 VMXVEXITINFO ExitInfo;
17035 RT_ZERO(ExitInfo);
17036 ExitInfo.uReason = pVmxTransient->uExitReason;
17037 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17038 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17039 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17040 }
17041 else
17042 rcStrict = hmR0VmxExitClts(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr);
17043 break;
17044 }
17045
17046 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
17047 {
17048 RTGCPTR GCPtrEffDst;
17049 uint16_t const uNewMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(pVmxTransient->uExitQual);
17050 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(pVmxTransient->uExitQual);
17051 if (fMemOperand)
17052 {
17053 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
17054 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
17055 }
17056 else
17057 GCPtrEffDst = NIL_RTGCPTR;
17058
17059 if (CPUMIsGuestVmxLmswInterceptSet(&pVCpu->cpum.GstCtx, uNewMsw))
17060 {
17061 VMXVEXITINFO ExitInfo;
17062 RT_ZERO(ExitInfo);
17063 ExitInfo.uReason = pVmxTransient->uExitReason;
17064 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17065 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
17066 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17067 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17068 }
17069 else
17070 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, uNewMsw, GCPtrEffDst);
17071 break;
17072 }
17073
17074 default:
17075 {
17076 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
17077 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
17078 }
17079 }
17080
17081 if (rcStrict == VINF_IEM_RAISED_XCPT)
17082 {
17083 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
17084 rcStrict = VINF_SUCCESS;
17085 }
17086 return rcStrict;
17087}
17088
17089
17090/**
17091 * Nested-guest VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX).
17092 * Conditional VM-exit.
17093 */
17094HMVMX_EXIT_DECL hmR0VmxExitMovDRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17095{
17096 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17097
17098 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MOV_DR_EXIT))
17099 {
17100 hmR0VmxReadExitQualVmcs(pVmxTransient);
17101 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17102
17103 VMXVEXITINFO ExitInfo;
17104 RT_ZERO(ExitInfo);
17105 ExitInfo.uReason = pVmxTransient->uExitReason;
17106 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17107 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17108 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17109 }
17110 return hmR0VmxExitMovDRx(pVCpu, pVmxTransient);
17111}
17112
17113
17114/**
17115 * Nested-guest VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR).
17116 * Conditional VM-exit.
17117 */
17118HMVMX_EXIT_DECL hmR0VmxExitIoInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17119{
17120 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17121
17122 hmR0VmxReadExitQualVmcs(pVmxTransient);
17123
17124 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
17125 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
17126 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
17127
17128 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
17129 uint8_t const cbAccess = s_aIOSizes[uIOSize];
17130 if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
17131 {
17132 /*
17133 * IN/OUT instruction:
17134 * - Provides VM-exit instruction length.
17135 *
17136 * INS/OUTS instruction:
17137 * - Provides VM-exit instruction length.
17138 * - Provides Guest-linear address.
17139 * - Optionally provides VM-exit instruction info (depends on CPU feature).
17140 */
17141 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
17142 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17143
17144 /* Make sure we don't use stale/uninitialized VMX-transient info. below. */
17145 pVmxTransient->ExitInstrInfo.u = 0;
17146 pVmxTransient->uGuestLinearAddr = 0;
17147
17148 bool const fVmxInsOutsInfo = pVM->cpum.ro.GuestFeatures.fVmxInsOutInfo;
17149 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
17150 if (fIOString)
17151 {
17152 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
17153 if (fVmxInsOutsInfo)
17154 {
17155 Assert(RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS)); /* Paranoia. */
17156 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17157 }
17158 }
17159
17160 VMXVEXITINFO ExitInfo;
17161 RT_ZERO(ExitInfo);
17162 ExitInfo.uReason = pVmxTransient->uExitReason;
17163 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17164 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17165 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17166 ExitInfo.u64GuestLinearAddr = pVmxTransient->uGuestLinearAddr;
17167 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17168 }
17169 return hmR0VmxExitIoInstr(pVCpu, pVmxTransient);
17170}
17171
17172
17173/**
17174 * Nested-guest VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
17175 */
17176HMVMX_EXIT_DECL hmR0VmxExitRdmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17177{
17178 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17179
17180 uint32_t fMsrpm;
17181 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
17182 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
17183 else
17184 fMsrpm = VMXMSRPM_EXIT_RD;
17185
17186 if (fMsrpm & VMXMSRPM_EXIT_RD)
17187 {
17188 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17189 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17190 }
17191 return hmR0VmxExitRdmsr(pVCpu, pVmxTransient);
17192}
17193
17194
17195/**
17196 * Nested-guest VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
17197 */
17198HMVMX_EXIT_DECL hmR0VmxExitWrmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17199{
17200 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17201
17202 uint32_t fMsrpm;
17203 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
17204 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
17205 else
17206 fMsrpm = VMXMSRPM_EXIT_WR;
17207
17208 if (fMsrpm & VMXMSRPM_EXIT_WR)
17209 {
17210 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17211 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17212 }
17213 return hmR0VmxExitWrmsr(pVCpu, pVmxTransient);
17214}
17215
17216
17217/**
17218 * Nested-guest VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
17219 */
17220HMVMX_EXIT_DECL hmR0VmxExitMwaitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17221{
17222 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17223
17224 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MWAIT_EXIT))
17225 {
17226 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17227 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17228 }
17229 return hmR0VmxExitMwait(pVCpu, pVmxTransient);
17230}
17231
17232
17233/**
17234 * Nested-guest VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional
17235 * VM-exit.
17236 */
17237HMVMX_EXIT_DECL hmR0VmxExitMtfNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17238{
17239 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17240
17241 /** @todo NSTVMX: Should consider debugging nested-guests using VM debugger. */
17242 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
17243 VMXVEXITINFO ExitInfo;
17244 RT_ZERO(ExitInfo);
17245 ExitInfo.uReason = pVmxTransient->uExitReason;
17246 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
17247 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
17248}
17249
17250
17251/**
17252 * Nested-guest VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
17253 */
17254HMVMX_EXIT_DECL hmR0VmxExitMonitorNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17255{
17256 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17257
17258 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MONITOR_EXIT))
17259 {
17260 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17261 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17262 }
17263 return hmR0VmxExitMonitor(pVCpu, pVmxTransient);
17264}
17265
17266
17267/**
17268 * Nested-guest VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
17269 */
17270HMVMX_EXIT_DECL hmR0VmxExitPauseNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17271{
17272 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17273
17274 /** @todo NSTVMX: Think about this more. Does the outer guest need to intercept
17275 * PAUSE when executing a nested-guest? If it does not, we would not need
17276 * to check for the intercepts here. Just call VM-exit... */
17277
17278 /* The CPU would have already performed the necessary CPL checks for PAUSE-loop exiting. */
17279 if ( CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_PAUSE_EXIT)
17280 || CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
17281 {
17282 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17283 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17284 }
17285 return hmR0VmxExitPause(pVCpu, pVmxTransient);
17286}
17287
17288
17289/**
17290 * Nested-guest VM-exit handler for when the TPR value is lowered below the
17291 * specified threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
17292 */
17293HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThresholdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17294{
17295 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17296
17297 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_TPR_SHADOW))
17298 {
17299 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
17300 VMXVEXITINFO ExitInfo;
17301 RT_ZERO(ExitInfo);
17302 ExitInfo.uReason = pVmxTransient->uExitReason;
17303 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
17304 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
17305 }
17306 return hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient);
17307}
17308
17309
17310/**
17311 * Nested-guest VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional
17312 * VM-exit.
17313 */
17314HMVMX_EXIT_DECL hmR0VmxExitApicAccessNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17315{
17316 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17317
17318 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17319 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
17320 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
17321 hmR0VmxReadExitQualVmcs(pVmxTransient);
17322
17323 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
17324
17325 Log4Func(("at offset %#x type=%u\n", VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual),
17326 VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual)));
17327
17328 VMXVEXITINFO ExitInfo;
17329 RT_ZERO(ExitInfo);
17330 ExitInfo.uReason = pVmxTransient->uExitReason;
17331 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17332 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17333
17334 VMXVEXITEVENTINFO ExitEventInfo;
17335 RT_ZERO(ExitEventInfo);
17336 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
17337 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
17338 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
17339}
17340
17341
17342/**
17343 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
17344 * Conditional VM-exit.
17345 */
17346HMVMX_EXIT_DECL hmR0VmxExitApicWriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17347{
17348 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17349
17350 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
17351 hmR0VmxReadExitQualVmcs(pVmxTransient);
17352 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
17353}
17354
17355
17356/**
17357 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
17358 * Conditional VM-exit.
17359 */
17360HMVMX_EXIT_DECL hmR0VmxExitVirtEoiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17361{
17362 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17363
17364 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
17365 hmR0VmxReadExitQualVmcs(pVmxTransient);
17366 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
17367}
17368
17369
17370/**
17371 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
17372 */
17373HMVMX_EXIT_DECL hmR0VmxExitRdtscpNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17374{
17375 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17376
17377 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
17378 {
17379 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
17380 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17381 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17382 }
17383 return hmR0VmxExitRdtscp(pVCpu, pVmxTransient);
17384}
17385
17386
17387/**
17388 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
17389 */
17390HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17391{
17392 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17393
17394 if (CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
17395 {
17396 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17397 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17398 }
17399 return hmR0VmxExitWbinvd(pVCpu, pVmxTransient);
17400}
17401
17402
17403/**
17404 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
17405 */
17406HMVMX_EXIT_DECL hmR0VmxExitInvpcidNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17407{
17408 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17409
17410 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
17411 {
17412 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
17413 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17414 hmR0VmxReadExitQualVmcs(pVmxTransient);
17415 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17416
17417 VMXVEXITINFO ExitInfo;
17418 RT_ZERO(ExitInfo);
17419 ExitInfo.uReason = pVmxTransient->uExitReason;
17420 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17421 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17422 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17423 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17424 }
17425 return hmR0VmxExitInvpcid(pVCpu, pVmxTransient);
17426}
17427
17428
17429/**
17430 * Nested-guest VM-exit handler for invalid-guest state
17431 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
17432 */
17433HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestStateNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17434{
17435 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17436
17437 /*
17438 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
17439 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
17440 * Handle it like it's in an invalid guest state of the outer guest.
17441 *
17442 * When the fast path is implemented, this should be changed to cause the corresponding
17443 * nested-guest VM-exit.
17444 */
17445 return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
17446}
17447
17448
17449/**
17450 * Nested-guest VM-exit handler for instructions that cause VM-exits uncondtionally
17451 * and only provide the instruction length.
17452 *
17453 * Unconditional VM-exit.
17454 */
17455HMVMX_EXIT_DECL hmR0VmxExitInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17456{
17457 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17458
17459#ifdef VBOX_STRICT
17460 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
17461 switch (pVmxTransient->uExitReason)
17462 {
17463 case VMX_EXIT_ENCLS:
17464 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
17465 break;
17466
17467 case VMX_EXIT_VMFUNC:
17468 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_VMFUNC));
17469 break;
17470 }
17471#endif
17472
17473 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17474 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17475}
17476
17477
17478/**
17479 * Nested-guest VM-exit handler for instructions that provide instruction length as
17480 * well as more information.
17481 *
17482 * Unconditional VM-exit.
17483 */
17484HMVMX_EXIT_DECL hmR0VmxExitInstrWithInfoNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17485{
17486 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17487
17488#ifdef VBOX_STRICT
17489 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
17490 switch (pVmxTransient->uExitReason)
17491 {
17492 case VMX_EXIT_GDTR_IDTR_ACCESS:
17493 case VMX_EXIT_LDTR_TR_ACCESS:
17494 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
17495 break;
17496
17497 case VMX_EXIT_RDRAND:
17498 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
17499 break;
17500
17501 case VMX_EXIT_RDSEED:
17502 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
17503 break;
17504
17505 case VMX_EXIT_XSAVES:
17506 case VMX_EXIT_XRSTORS:
17507 /** @todo NSTVMX: Verify XSS-bitmap. */
17508 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
17509 break;
17510
17511 case VMX_EXIT_UMWAIT:
17512 case VMX_EXIT_TPAUSE:
17513 Assert(CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
17514 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
17515 break;
17516 }
17517#endif
17518
17519 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17520 hmR0VmxReadExitQualVmcs(pVmxTransient);
17521 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17522
17523 VMXVEXITINFO ExitInfo;
17524 RT_ZERO(ExitInfo);
17525 ExitInfo.uReason = pVmxTransient->uExitReason;
17526 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17527 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17528 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17529 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17530}
17531
17532/** @} */
17533#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
17534
Note: See TracBrowser for help on using the repository browser.

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