VirtualBox

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

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

VMM/HMVMXR0: Nested VMX: hmR0VmxRemoveProcCtlsVmcs nit.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 734.7 KB
Line 
1/* $Id: HMVMXR0.cpp 87966 2021-03-05 04:58:50Z 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(PCVMCC pVM, uint32_t idMsr, uint32_t *pidxMsr)
878{
879 Assert(pVM->hmr0.s.vmx.fLbr);
880 Assert(pVM->hmr0.s.vmx.idLbrFromIpMsrFirst);
881 uint32_t const cLbrStack = pVM->hmr0.s.vmx.idLbrFromIpMsrLast - pVM->hmr0.s.vmx.idLbrFromIpMsrFirst + 1;
882 uint32_t const idxMsr = idMsr - pVM->hmr0.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(PCVMCC pVM, uint32_t idMsr, uint32_t *pidxMsr)
906{
907 Assert(pVM->hmr0.s.vmx.fLbr);
908 if (pVM->hmr0.s.vmx.idLbrToIpMsrFirst)
909 {
910 uint32_t const cLbrStack = pVM->hmr0.s.vmx.idLbrToIpMsrLast - pVM->hmr0.s.vmx.idLbrToIpMsrFirst + 1;
911 uint32_t const idxMsr = idMsr - pVM->hmr0.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 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 if ( !pVmxTransient->fIsNestedGuest
1082 || !CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uProcCtls))
1083#else
1084 NOREF(pVCpu);
1085 if (!pVmxTransient->fIsNestedGuest)
1086#endif
1087 {
1088 pVmcsInfo->u32ProcCtls &= ~uProcCtls;
1089 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
1090 AssertRC(rc);
1091 }
1092 }
1093}
1094
1095
1096/**
1097 * Sets the TSC offset for the current VMCS.
1098 *
1099 * @param uTscOffset The TSC offset to set.
1100 * @param pVmcsInfo The VMCS info. object.
1101 */
1102static void hmR0VmxSetTscOffsetVmcs(PVMXVMCSINFO pVmcsInfo, uint64_t uTscOffset)
1103{
1104 if (pVmcsInfo->u64TscOffset != uTscOffset)
1105 {
1106 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
1107 AssertRC(rc);
1108 pVmcsInfo->u64TscOffset = uTscOffset;
1109 }
1110}
1111
1112
1113/**
1114 * Adds one or more exceptions to the exception bitmap and commits it to the current
1115 * VMCS.
1116 *
1117 * @param pVmxTransient The VMX-transient structure.
1118 * @param uXcptMask The exception(s) to add.
1119 */
1120static void hmR0VmxAddXcptInterceptMask(PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1121{
1122 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1123 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
1124 if ((uXcptBitmap & uXcptMask) != uXcptMask)
1125 {
1126 uXcptBitmap |= uXcptMask;
1127 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
1128 AssertRC(rc);
1129 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
1130 }
1131}
1132
1133
1134/**
1135 * Adds an exception to the exception bitmap and commits it to the current VMCS.
1136 *
1137 * @param pVmxTransient The VMX-transient structure.
1138 * @param uXcpt The exception to add.
1139 */
1140static void hmR0VmxAddXcptIntercept(PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1141{
1142 Assert(uXcpt <= X86_XCPT_LAST);
1143 hmR0VmxAddXcptInterceptMask(pVmxTransient, RT_BIT_32(uXcpt));
1144}
1145
1146
1147/**
1148 * Remove one or more exceptions from the exception bitmap and commits it to the
1149 * current VMCS.
1150 *
1151 * This takes care of not removing the exception intercept if a nested-guest
1152 * requires the exception to be intercepted.
1153 *
1154 * @returns VBox status code.
1155 * @param pVCpu The cross context virtual CPU structure.
1156 * @param pVmxTransient The VMX-transient structure.
1157 * @param uXcptMask The exception(s) to remove.
1158 */
1159static int hmR0VmxRemoveXcptInterceptMask(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1160{
1161 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1162 uint32_t u32XcptBitmap = pVmcsInfo->u32XcptBitmap;
1163 if (u32XcptBitmap & uXcptMask)
1164 {
1165#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1166 if (!pVmxTransient->fIsNestedGuest)
1167 { /* likely */ }
1168 else
1169 {
1170 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
1171 uXcptMask &= ~pVmcsNstGst->u32XcptBitmap;
1172 }
1173#endif
1174#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
1175 uXcptMask &= ~( RT_BIT(X86_XCPT_BP)
1176 | RT_BIT(X86_XCPT_DE)
1177 | RT_BIT(X86_XCPT_NM)
1178 | RT_BIT(X86_XCPT_TS)
1179 | RT_BIT(X86_XCPT_UD)
1180 | RT_BIT(X86_XCPT_NP)
1181 | RT_BIT(X86_XCPT_SS)
1182 | RT_BIT(X86_XCPT_GP)
1183 | RT_BIT(X86_XCPT_PF)
1184 | RT_BIT(X86_XCPT_MF));
1185#elif defined(HMVMX_ALWAYS_TRAP_PF)
1186 uXcptMask &= ~RT_BIT(X86_XCPT_PF);
1187#endif
1188 if (uXcptMask)
1189 {
1190 /* Validate we are not removing any essential exception intercepts. */
1191 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging || !(uXcptMask & RT_BIT(X86_XCPT_PF)));
1192 NOREF(pVCpu);
1193 Assert(!(uXcptMask & RT_BIT(X86_XCPT_DB)));
1194 Assert(!(uXcptMask & RT_BIT(X86_XCPT_AC)));
1195
1196 /* Remove it from the exception bitmap. */
1197 u32XcptBitmap &= ~uXcptMask;
1198
1199 /* Commit and update the cache if necessary. */
1200 if (pVmcsInfo->u32XcptBitmap != u32XcptBitmap)
1201 {
1202 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
1203 AssertRC(rc);
1204 pVmcsInfo->u32XcptBitmap = u32XcptBitmap;
1205 }
1206 }
1207 }
1208 return VINF_SUCCESS;
1209}
1210
1211
1212/**
1213 * Remove an exceptions from the exception bitmap and commits it to the current
1214 * VMCS.
1215 *
1216 * @returns VBox status code.
1217 * @param pVCpu The cross context virtual CPU structure.
1218 * @param pVmxTransient The VMX-transient structure.
1219 * @param uXcpt The exception to remove.
1220 */
1221static int hmR0VmxRemoveXcptIntercept(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1222{
1223 return hmR0VmxRemoveXcptInterceptMask(pVCpu, pVmxTransient, RT_BIT(uXcpt));
1224}
1225
1226
1227/**
1228 * Loads the VMCS specified by the VMCS info. object.
1229 *
1230 * @returns VBox status code.
1231 * @param pVmcsInfo The VMCS info. object.
1232 *
1233 * @remarks Can be called with interrupts disabled.
1234 */
1235static int hmR0VmxLoadVmcs(PVMXVMCSINFO pVmcsInfo)
1236{
1237 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1238 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1239
1240 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysVmcs);
1241 if (RT_SUCCESS(rc))
1242 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1243 return rc;
1244}
1245
1246
1247/**
1248 * Clears the VMCS specified by the VMCS info. object.
1249 *
1250 * @returns VBox status code.
1251 * @param pVmcsInfo The VMCS info. object.
1252 *
1253 * @remarks Can be called with interrupts disabled.
1254 */
1255static int hmR0VmxClearVmcs(PVMXVMCSINFO pVmcsInfo)
1256{
1257 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1258 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1259
1260 int rc = VMXClearVmcs(pVmcsInfo->HCPhysVmcs);
1261 if (RT_SUCCESS(rc))
1262 pVmcsInfo->fVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1263 return rc;
1264}
1265
1266
1267#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1268/**
1269 * Loads the shadow VMCS specified by the VMCS info. object.
1270 *
1271 * @returns VBox status code.
1272 * @param pVmcsInfo The VMCS info. object.
1273 *
1274 * @remarks Can be called with interrupts disabled.
1275 */
1276static int hmR0VmxLoadShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1277{
1278 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1279 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1280
1281 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
1282 if (RT_SUCCESS(rc))
1283 pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1284 return rc;
1285}
1286
1287
1288/**
1289 * Clears the shadow VMCS specified by the VMCS info. object.
1290 *
1291 * @returns VBox status code.
1292 * @param pVmcsInfo The VMCS info. object.
1293 *
1294 * @remarks Can be called with interrupts disabled.
1295 */
1296static int hmR0VmxClearShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1297{
1298 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1299 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1300
1301 int rc = VMXClearVmcs(pVmcsInfo->HCPhysShadowVmcs);
1302 if (RT_SUCCESS(rc))
1303 pVmcsInfo->fShadowVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1304 return rc;
1305}
1306
1307
1308/**
1309 * Switches from and to the specified VMCSes.
1310 *
1311 * @returns VBox status code.
1312 * @param pVmcsInfoFrom The VMCS info. object we are switching from.
1313 * @param pVmcsInfoTo The VMCS info. object we are switching to.
1314 *
1315 * @remarks Called with interrupts disabled.
1316 */
1317static int hmR0VmxSwitchVmcs(PVMXVMCSINFO pVmcsInfoFrom, PVMXVMCSINFO pVmcsInfoTo)
1318{
1319 /*
1320 * Clear the VMCS we are switching out if it has not already been cleared.
1321 * This will sync any CPU internal data back to the VMCS.
1322 */
1323 if (pVmcsInfoFrom->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1324 {
1325 int rc = hmR0VmxClearVmcs(pVmcsInfoFrom);
1326 if (RT_SUCCESS(rc))
1327 {
1328 /*
1329 * The shadow VMCS, if any, would not be active at this point since we
1330 * would have cleared it while importing the virtual hardware-virtualization
1331 * state as part the VMLAUNCH/VMRESUME VM-exit. Hence, there's no need to
1332 * clear the shadow VMCS here, just assert for safety.
1333 */
1334 Assert(!pVmcsInfoFrom->pvShadowVmcs || pVmcsInfoFrom->fShadowVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR);
1335 }
1336 else
1337 return rc;
1338 }
1339
1340 /*
1341 * Clear the VMCS we are switching to if it has not already been cleared.
1342 * This will initialize the VMCS launch state to "clear" required for loading it.
1343 *
1344 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
1345 */
1346 if (pVmcsInfoTo->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1347 {
1348 int rc = hmR0VmxClearVmcs(pVmcsInfoTo);
1349 if (RT_SUCCESS(rc))
1350 { /* likely */ }
1351 else
1352 return rc;
1353 }
1354
1355 /*
1356 * Finally, load the VMCS we are switching to.
1357 */
1358 return hmR0VmxLoadVmcs(pVmcsInfoTo);
1359}
1360
1361
1362/**
1363 * Switches between the guest VMCS and the nested-guest VMCS as specified by the
1364 * caller.
1365 *
1366 * @returns VBox status code.
1367 * @param pVCpu The cross context virtual CPU structure.
1368 * @param fSwitchToNstGstVmcs Whether to switch to the nested-guest VMCS (pass
1369 * true) or guest VMCS (pass false).
1370 */
1371static int hmR0VmxSwitchToGstOrNstGstVmcs(PVMCPUCC pVCpu, bool fSwitchToNstGstVmcs)
1372{
1373 /* Ensure we have synced everything from the guest-CPU context to the VMCS before switching. */
1374 HMVMX_CPUMCTX_ASSERT(pVCpu, HMVMX_CPUMCTX_EXTRN_ALL);
1375
1376 PVMXVMCSINFO pVmcsInfoFrom;
1377 PVMXVMCSINFO pVmcsInfoTo;
1378 if (fSwitchToNstGstVmcs)
1379 {
1380 pVmcsInfoFrom = &pVCpu->hmr0.s.vmx.VmcsInfo;
1381 pVmcsInfoTo = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1382 }
1383 else
1384 {
1385 pVmcsInfoFrom = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1386 pVmcsInfoTo = &pVCpu->hmr0.s.vmx.VmcsInfo;
1387 }
1388
1389 /*
1390 * Disable interrupts to prevent being preempted while we switch the current VMCS as the
1391 * preemption hook code path acquires the current VMCS.
1392 */
1393 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1394
1395 int rc = hmR0VmxSwitchVmcs(pVmcsInfoFrom, pVmcsInfoTo);
1396 if (RT_SUCCESS(rc))
1397 {
1398 pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs = fSwitchToNstGstVmcs;
1399 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcsCopyForRing3 = fSwitchToNstGstVmcs;
1400
1401 /*
1402 * If we are switching to a VMCS that was executed on a different host CPU or was
1403 * never executed before, flag that we need to export the host state before executing
1404 * guest/nested-guest code using hardware-assisted VMX.
1405 *
1406 * This could probably be done in a preemptible context since the preemption hook
1407 * will flag the necessary change in host context. However, since preemption is
1408 * already disabled and to avoid making assumptions about host specific code in
1409 * RTMpCpuId when called with preemption enabled, we'll do this while preemption is
1410 * disabled.
1411 */
1412 if (pVmcsInfoTo->idHostCpuState == RTMpCpuId())
1413 { /* likely */ }
1414 else
1415 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE);
1416
1417 ASMSetFlags(fEFlags);
1418
1419 /*
1420 * We use a different VM-exit MSR-store areas for the guest and nested-guest. Hence,
1421 * flag that we need to update the host MSR values there. Even if we decide in the
1422 * future to share the VM-exit MSR-store area page between the guest and nested-guest,
1423 * if its content differs, we would have to update the host MSRs anyway.
1424 */
1425 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
1426 }
1427 else
1428 ASMSetFlags(fEFlags);
1429 return rc;
1430}
1431#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
1432
1433
1434/**
1435 * Updates the VM's last error record.
1436 *
1437 * If there was a VMX instruction error, reads the error data from the VMCS and
1438 * updates VCPU's last error record as well.
1439 *
1440 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1441 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
1442 * VERR_VMX_INVALID_VMCS_FIELD.
1443 * @param rc The error code.
1444 */
1445static void hmR0VmxUpdateErrorRecord(PVMCPUCC pVCpu, int rc)
1446{
1447 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
1448 || rc == VERR_VMX_UNABLE_TO_START_VM)
1449 {
1450 AssertPtrReturnVoid(pVCpu);
1451 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
1452 }
1453 pVCpu->CTX_SUFF(pVM)->hm.s.ForR3.rcInit = rc;
1454}
1455
1456
1457#ifdef VBOX_STRICT
1458/**
1459 * Reads the VM-entry interruption-information field from the VMCS into the VMX
1460 * transient structure.
1461 *
1462 * @param pVmxTransient The VMX-transient structure.
1463 */
1464DECLINLINE(void) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1465{
1466 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
1467 AssertRC(rc);
1468}
1469
1470
1471/**
1472 * Reads the VM-entry exception error code field from the VMCS into
1473 * the VMX transient structure.
1474 *
1475 * @param pVmxTransient The VMX-transient structure.
1476 */
1477DECLINLINE(void) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1478{
1479 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
1480 AssertRC(rc);
1481}
1482
1483
1484/**
1485 * Reads the VM-entry exception error code field from the VMCS into
1486 * the VMX transient structure.
1487 *
1488 * @param pVmxTransient The VMX-transient structure.
1489 */
1490DECLINLINE(void) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1491{
1492 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
1493 AssertRC(rc);
1494}
1495#endif /* VBOX_STRICT */
1496
1497
1498/**
1499 * Reads the VM-exit interruption-information field from the VMCS into the VMX
1500 * transient structure.
1501 *
1502 * @param pVmxTransient The VMX-transient structure.
1503 */
1504DECLINLINE(void) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1505{
1506 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_INFO))
1507 {
1508 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1509 AssertRC(rc);
1510 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_INFO;
1511 }
1512}
1513
1514
1515/**
1516 * Reads the VM-exit interruption error code from the VMCS into the VMX
1517 * transient structure.
1518 *
1519 * @param pVmxTransient The VMX-transient structure.
1520 */
1521DECLINLINE(void) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1522{
1523 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE))
1524 {
1525 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1526 AssertRC(rc);
1527 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE;
1528 }
1529}
1530
1531
1532/**
1533 * Reads the VM-exit instruction length field from the VMCS into the VMX
1534 * transient structure.
1535 *
1536 * @param pVmxTransient The VMX-transient structure.
1537 */
1538DECLINLINE(void) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1539{
1540 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_LEN))
1541 {
1542 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1543 AssertRC(rc);
1544 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_LEN;
1545 }
1546}
1547
1548
1549/**
1550 * Reads the VM-exit instruction-information field from the VMCS into
1551 * the VMX transient structure.
1552 *
1553 * @param pVmxTransient The VMX-transient structure.
1554 */
1555DECLINLINE(void) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
1556{
1557 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_INFO))
1558 {
1559 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1560 AssertRC(rc);
1561 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_INFO;
1562 }
1563}
1564
1565
1566/**
1567 * Reads the Exit Qualification from the VMCS into the VMX transient structure.
1568 *
1569 * @param pVmxTransient The VMX-transient structure.
1570 */
1571DECLINLINE(void) hmR0VmxReadExitQualVmcs(PVMXTRANSIENT pVmxTransient)
1572{
1573 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_QUALIFICATION))
1574 {
1575 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1576 AssertRC(rc);
1577 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION;
1578 }
1579}
1580
1581
1582/**
1583 * Reads the Guest-linear address from the VMCS into the VMX transient structure.
1584 *
1585 * @param pVmxTransient The VMX-transient structure.
1586 */
1587DECLINLINE(void) hmR0VmxReadGuestLinearAddrVmcs(PVMXTRANSIENT pVmxTransient)
1588{
1589 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_LINEAR_ADDR))
1590 {
1591 int rc = VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1592 AssertRC(rc);
1593 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_LINEAR_ADDR;
1594 }
1595}
1596
1597
1598/**
1599 * Reads the Guest-physical address from the VMCS into the VMX transient structure.
1600 *
1601 * @param pVmxTransient The VMX-transient structure.
1602 */
1603DECLINLINE(void) hmR0VmxReadGuestPhysicalAddrVmcs(PVMXTRANSIENT pVmxTransient)
1604{
1605 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PHYSICAL_ADDR))
1606 {
1607 int rc = VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1608 AssertRC(rc);
1609 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PHYSICAL_ADDR;
1610 }
1611}
1612
1613#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1614/**
1615 * Reads the Guest pending-debug exceptions from the VMCS into the VMX transient
1616 * structure.
1617 *
1618 * @param pVmxTransient The VMX-transient structure.
1619 */
1620DECLINLINE(void) hmR0VmxReadGuestPendingDbgXctps(PVMXTRANSIENT pVmxTransient)
1621{
1622 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PENDING_DBG_XCPTS))
1623 {
1624 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &pVmxTransient->uGuestPendingDbgXcpts);
1625 AssertRC(rc);
1626 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PENDING_DBG_XCPTS;
1627 }
1628}
1629#endif
1630
1631/**
1632 * Reads the IDT-vectoring information field from the VMCS into the VMX
1633 * transient structure.
1634 *
1635 * @param pVmxTransient The VMX-transient structure.
1636 *
1637 * @remarks No-long-jump zone!!!
1638 */
1639DECLINLINE(void) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
1640{
1641 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_INFO))
1642 {
1643 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1644 AssertRC(rc);
1645 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_INFO;
1646 }
1647}
1648
1649
1650/**
1651 * Reads the IDT-vectoring error code from the VMCS into the VMX
1652 * transient structure.
1653 *
1654 * @param pVmxTransient The VMX-transient structure.
1655 */
1656DECLINLINE(void) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1657{
1658 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_ERROR_CODE))
1659 {
1660 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1661 AssertRC(rc);
1662 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_ERROR_CODE;
1663 }
1664}
1665
1666#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
1667/**
1668 * Reads all relevant read-only VMCS fields into the VMX transient structure.
1669 *
1670 * @param pVmxTransient The VMX-transient structure.
1671 */
1672static void hmR0VmxReadAllRoFieldsVmcs(PVMXTRANSIENT pVmxTransient)
1673{
1674 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1675 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1676 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1677 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1678 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1679 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1680 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1681 rc |= VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1682 rc |= VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1683 AssertRC(rc);
1684 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION
1685 | HMVMX_READ_EXIT_INSTR_LEN
1686 | HMVMX_READ_EXIT_INSTR_INFO
1687 | HMVMX_READ_IDT_VECTORING_INFO
1688 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1689 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1690 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1691 | HMVMX_READ_GUEST_LINEAR_ADDR
1692 | HMVMX_READ_GUEST_PHYSICAL_ADDR;
1693}
1694#endif
1695
1696/**
1697 * Enters VMX root mode operation on the current CPU.
1698 *
1699 * @returns VBox status code.
1700 * @param pHostCpu The HM physical-CPU structure.
1701 * @param pVM The cross context VM structure. Can be
1702 * NULL, after a resume.
1703 * @param HCPhysCpuPage Physical address of the VMXON region.
1704 * @param pvCpuPage Pointer to the VMXON region.
1705 */
1706static int hmR0VmxEnterRootMode(PHMPHYSCPU pHostCpu, PVMCC pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
1707{
1708 Assert(pHostCpu);
1709 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
1710 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
1711 Assert(pvCpuPage);
1712 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1713
1714 if (pVM)
1715 {
1716 /* Write the VMCS revision identifier to the VMXON region. */
1717 *(uint32_t *)pvCpuPage = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
1718 }
1719
1720 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
1721 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1722
1723 /* Enable the VMX bit in CR4 if necessary. */
1724 RTCCUINTREG const uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
1725
1726 /* Record whether VMXE was already prior to us enabling it above. */
1727 pHostCpu->fVmxeAlreadyEnabled = RT_BOOL(uOldCr4 & X86_CR4_VMXE);
1728
1729 /* Enter VMX root mode. */
1730 int rc = VMXEnable(HCPhysCpuPage);
1731 if (RT_FAILURE(rc))
1732 {
1733 /* Restore CR4.VMXE if it was not set prior to our attempt to set it above. */
1734 if (!pHostCpu->fVmxeAlreadyEnabled)
1735 SUPR0ChangeCR4(0 /* fOrMask */, ~(uint64_t)X86_CR4_VMXE);
1736
1737 if (pVM)
1738 pVM->hm.s.ForR3.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
1739 }
1740
1741 /* Restore interrupts. */
1742 ASMSetFlags(fEFlags);
1743 return rc;
1744}
1745
1746
1747/**
1748 * Exits VMX root mode operation on the current CPU.
1749 *
1750 * @returns VBox status code.
1751 * @param pHostCpu The HM physical-CPU structure.
1752 */
1753static int hmR0VmxLeaveRootMode(PHMPHYSCPU pHostCpu)
1754{
1755 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1756
1757 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
1758 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1759
1760 /* If we're for some reason not in VMX root mode, then don't leave it. */
1761 RTCCUINTREG const uHostCr4 = ASMGetCR4();
1762
1763 int rc;
1764 if (uHostCr4 & X86_CR4_VMXE)
1765 {
1766 /* Exit VMX root mode and clear the VMX bit in CR4. */
1767 VMXDisable();
1768
1769 /* Clear CR4.VMXE only if it was clear prior to use setting it. */
1770 if (!pHostCpu->fVmxeAlreadyEnabled)
1771 SUPR0ChangeCR4(0 /* fOrMask */, ~(uint64_t)X86_CR4_VMXE);
1772
1773 rc = VINF_SUCCESS;
1774 }
1775 else
1776 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
1777
1778 /* Restore interrupts. */
1779 ASMSetFlags(fEFlags);
1780 return rc;
1781}
1782
1783
1784/**
1785 * Allocates pages specified as specified by an array of VMX page allocation info
1786 * objects.
1787 *
1788 * The pages contents are zero'd after allocation.
1789 *
1790 * @returns VBox status code.
1791 * @param phMemObj Where to return the handle to the allocation.
1792 * @param paAllocInfo The pointer to the first element of the VMX
1793 * page-allocation info object array.
1794 * @param cEntries The number of elements in the @a paAllocInfo array.
1795 */
1796static int hmR0VmxPagesAllocZ(PRTR0MEMOBJ phMemObj, PVMXPAGEALLOCINFO paAllocInfo, uint32_t cEntries)
1797{
1798 *phMemObj = NIL_RTR0MEMOBJ;
1799
1800 /* Figure out how many pages to allocate. */
1801 uint32_t cPages = 0;
1802 for (uint32_t iPage = 0; iPage < cEntries; iPage++)
1803 cPages += !!paAllocInfo[iPage].fValid;
1804
1805 /* Allocate the pages. */
1806 if (cPages)
1807 {
1808 size_t const cbPages = cPages << PAGE_SHIFT;
1809 int rc = RTR0MemObjAllocPage(phMemObj, cbPages, false /* fExecutable */);
1810 if (RT_FAILURE(rc))
1811 return rc;
1812
1813 /* Zero the contents and assign each page to the corresponding VMX page-allocation entry. */
1814 void *pvFirstPage = RTR0MemObjAddress(*phMemObj);
1815 RT_BZERO(pvFirstPage, cbPages);
1816
1817 uint32_t iPage = 0;
1818 for (uint32_t i = 0; i < cEntries; i++)
1819 if (paAllocInfo[i].fValid)
1820 {
1821 RTHCPHYS const HCPhysPage = RTR0MemObjGetPagePhysAddr(*phMemObj, iPage);
1822 void *pvPage = (void *)((uintptr_t)pvFirstPage + (iPage << X86_PAGE_4K_SHIFT));
1823 Assert(HCPhysPage && HCPhysPage != NIL_RTHCPHYS);
1824 AssertPtr(pvPage);
1825
1826 Assert(paAllocInfo[iPage].pHCPhys);
1827 Assert(paAllocInfo[iPage].ppVirt);
1828 *paAllocInfo[iPage].pHCPhys = HCPhysPage;
1829 *paAllocInfo[iPage].ppVirt = pvPage;
1830
1831 /* Move to next page. */
1832 ++iPage;
1833 }
1834
1835 /* Make sure all valid (requested) pages have been assigned. */
1836 Assert(iPage == cPages);
1837 }
1838 return VINF_SUCCESS;
1839}
1840
1841
1842/**
1843 * Frees pages allocated using hmR0VmxPagesAllocZ.
1844 *
1845 * @param phMemObj Pointer to the memory object handle. Will be set to
1846 * NIL.
1847 */
1848DECL_FORCE_INLINE(void) hmR0VmxPagesFree(PRTR0MEMOBJ phMemObj)
1849{
1850 /* We can cleanup wholesale since it's all one allocation. */
1851 if (*phMemObj != NIL_RTR0MEMOBJ)
1852 {
1853 RTR0MemObjFree(*phMemObj, true /* fFreeMappings */);
1854 *phMemObj = NIL_RTR0MEMOBJ;
1855 }
1856}
1857
1858
1859/**
1860 * Initializes a VMCS info. object.
1861 *
1862 * @param pVmcsInfo The VMCS info. object.
1863 * @param pVmcsInfoShared The VMCS info. object shared with ring-3.
1864 */
1865static void hmR0VmxVmcsInfoInit(PVMXVMCSINFO pVmcsInfo, PVMXVMCSINFOSHARED pVmcsInfoShared)
1866{
1867 RT_ZERO(*pVmcsInfo);
1868 RT_ZERO(*pVmcsInfoShared);
1869
1870 pVmcsInfo->pShared = pVmcsInfoShared;
1871 Assert(pVmcsInfo->hMemObj == NIL_RTR0MEMOBJ);
1872 pVmcsInfo->HCPhysVmcs = NIL_RTHCPHYS;
1873 pVmcsInfo->HCPhysShadowVmcs = NIL_RTHCPHYS;
1874 pVmcsInfo->HCPhysMsrBitmap = NIL_RTHCPHYS;
1875 pVmcsInfo->HCPhysGuestMsrLoad = NIL_RTHCPHYS;
1876 pVmcsInfo->HCPhysGuestMsrStore = NIL_RTHCPHYS;
1877 pVmcsInfo->HCPhysHostMsrLoad = NIL_RTHCPHYS;
1878 pVmcsInfo->HCPhysVirtApic = NIL_RTHCPHYS;
1879 pVmcsInfo->HCPhysEPTP = NIL_RTHCPHYS;
1880 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
1881 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
1882 pVmcsInfo->idHostCpuExec = NIL_RTCPUID;
1883}
1884
1885
1886/**
1887 * Frees the VT-x structures for a VMCS info. object.
1888 *
1889 * @param pVmcsInfo The VMCS info. object.
1890 * @param pVmcsInfoShared The VMCS info. object shared with ring-3.
1891 */
1892static void hmR0VmxVmcsInfoFree(PVMXVMCSINFO pVmcsInfo, PVMXVMCSINFOSHARED pVmcsInfoShared)
1893{
1894 hmR0VmxPagesFree(&pVmcsInfo->hMemObj);
1895 hmR0VmxVmcsInfoInit(pVmcsInfo, pVmcsInfoShared);
1896}
1897
1898
1899/**
1900 * Allocates the VT-x structures for a VMCS info. object.
1901 *
1902 * @returns VBox status code.
1903 * @param pVCpu The cross context virtual CPU structure.
1904 * @param pVmcsInfo The VMCS info. object.
1905 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
1906 *
1907 * @remarks The caller is expected to take care of any and all allocation failures.
1908 * This function will not perform any cleanup for failures half-way
1909 * through.
1910 */
1911static int hmR0VmxAllocVmcsInfo(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
1912{
1913 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
1914
1915 bool const fMsrBitmaps = RT_BOOL(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS);
1916 bool const fShadowVmcs = !fIsNstGstVmcs ? pVM->hmr0.s.vmx.fUseVmcsShadowing : pVM->cpum.ro.GuestFeatures.fVmxVmcsShadowing;
1917 Assert(!pVM->cpum.ro.GuestFeatures.fVmxVmcsShadowing); /* VMCS shadowing is not yet exposed to the guest. */
1918 VMXPAGEALLOCINFO aAllocInfo[] =
1919 {
1920 { true, 0 /* Unused */, &pVmcsInfo->HCPhysVmcs, &pVmcsInfo->pvVmcs },
1921 { true, 0 /* Unused */, &pVmcsInfo->HCPhysGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad },
1922 { true, 0 /* Unused */, &pVmcsInfo->HCPhysHostMsrLoad, &pVmcsInfo->pvHostMsrLoad },
1923 { fMsrBitmaps, 0 /* Unused */, &pVmcsInfo->HCPhysMsrBitmap, &pVmcsInfo->pvMsrBitmap },
1924 { fShadowVmcs, 0 /* Unused */, &pVmcsInfo->HCPhysShadowVmcs, &pVmcsInfo->pvShadowVmcs },
1925 };
1926
1927 int rc = hmR0VmxPagesAllocZ(&pVmcsInfo->hMemObj, &aAllocInfo[0], RT_ELEMENTS(aAllocInfo));
1928 if (RT_FAILURE(rc))
1929 return rc;
1930
1931 /*
1932 * We use the same page for VM-entry MSR-load and VM-exit MSR store areas.
1933 * Because they contain a symmetric list of guest MSRs to load on VM-entry and store on VM-exit.
1934 */
1935 AssertCompile(RT_ELEMENTS(aAllocInfo) > 0);
1936 Assert(pVmcsInfo->HCPhysGuestMsrLoad != NIL_RTHCPHYS);
1937 pVmcsInfo->pvGuestMsrStore = pVmcsInfo->pvGuestMsrLoad;
1938 pVmcsInfo->HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrLoad;
1939
1940 /*
1941 * Get the virtual-APIC page rather than allocating them again.
1942 */
1943 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
1944 {
1945 if (!fIsNstGstVmcs)
1946 {
1947 if (PDMHasApic(pVM))
1948 {
1949 rc = APICGetApicPageForCpu(pVCpu, &pVmcsInfo->HCPhysVirtApic, (PRTR0PTR)&pVmcsInfo->pbVirtApic, NULL /*pR3Ptr*/);
1950 if (RT_FAILURE(rc))
1951 return rc;
1952 Assert(pVmcsInfo->pbVirtApic);
1953 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1954 }
1955 }
1956 else
1957 {
1958 pVmcsInfo->pbVirtApic = (uint8_t *)CPUMGetGuestVmxVirtApicPage(&pVCpu->cpum.GstCtx, &pVmcsInfo->HCPhysVirtApic);
1959 Assert(pVmcsInfo->pbVirtApic);
1960 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1961 }
1962 }
1963
1964 return VINF_SUCCESS;
1965}
1966
1967
1968/**
1969 * Free all VT-x structures for the VM.
1970 *
1971 * @returns IPRT status code.
1972 * @param pVM The cross context VM structure.
1973 */
1974static void hmR0VmxStructsFree(PVMCC pVM)
1975{
1976 hmR0VmxPagesFree(&pVM->hmr0.s.vmx.hMemObj);
1977#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1978 if (pVM->hmr0.s.vmx.fUseVmcsShadowing)
1979 {
1980 RTMemFree(pVM->hmr0.s.vmx.paShadowVmcsFields);
1981 pVM->hmr0.s.vmx.paShadowVmcsFields = NULL;
1982 RTMemFree(pVM->hmr0.s.vmx.paShadowVmcsRoFields);
1983 pVM->hmr0.s.vmx.paShadowVmcsRoFields = NULL;
1984 }
1985#endif
1986
1987 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1988 {
1989 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
1990 hmR0VmxVmcsInfoFree(&pVCpu->hmr0.s.vmx.VmcsInfo, &pVCpu->hm.s.vmx.VmcsInfo);
1991#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1992 if (pVM->cpum.ro.GuestFeatures.fVmx)
1993 hmR0VmxVmcsInfoFree(&pVCpu->hmr0.s.vmx.VmcsInfoNstGst, &pVCpu->hm.s.vmx.VmcsInfoNstGst);
1994#endif
1995 }
1996}
1997
1998
1999/**
2000 * Allocate all VT-x structures for the VM.
2001 *
2002 * @returns IPRT status code.
2003 * @param pVM The cross context VM structure.
2004 *
2005 * @remarks This functions will cleanup on memory allocation failures.
2006 */
2007static int hmR0VmxStructsAlloc(PVMCC pVM)
2008{
2009 /*
2010 * Sanity check the VMCS size reported by the CPU as we assume 4KB allocations.
2011 * The VMCS size cannot be more than 4096 bytes.
2012 *
2013 * See Intel spec. Appendix A.1 "Basic VMX Information".
2014 */
2015 uint32_t const cbVmcs = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_SIZE);
2016 if (cbVmcs <= X86_PAGE_4K_SIZE)
2017 { /* likely */ }
2018 else
2019 {
2020 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_INVALID_VMCS_SIZE;
2021 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2022 }
2023
2024 /*
2025 * Allocate per-VM VT-x structures.
2026 */
2027 bool const fVirtApicAccess = RT_BOOL(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
2028 bool const fUseVmcsShadowing = pVM->hmr0.s.vmx.fUseVmcsShadowing;
2029 VMXPAGEALLOCINFO aAllocInfo[] =
2030 {
2031 { fVirtApicAccess, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysApicAccess, (PRTR0PTR)&pVM->hmr0.s.vmx.pbApicAccess },
2032 { fUseVmcsShadowing, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysVmreadBitmap, &pVM->hmr0.s.vmx.pvVmreadBitmap },
2033 { fUseVmcsShadowing, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysVmwriteBitmap, &pVM->hmr0.s.vmx.pvVmwriteBitmap },
2034#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2035 { true, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysScratch, (PRTR0PTR)&pVM->hmr0.s.vmx.pbScratch },
2036#endif
2037 };
2038
2039 int rc = hmR0VmxPagesAllocZ(&pVM->hmr0.s.vmx.hMemObj, &aAllocInfo[0], RT_ELEMENTS(aAllocInfo));
2040 if (RT_SUCCESS(rc))
2041 {
2042#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2043 /* Allocate the shadow VMCS-fields array. */
2044 if (fUseVmcsShadowing)
2045 {
2046 Assert(!pVM->hmr0.s.vmx.cShadowVmcsFields);
2047 Assert(!pVM->hmr0.s.vmx.cShadowVmcsRoFields);
2048 pVM->hmr0.s.vmx.paShadowVmcsFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
2049 pVM->hmr0.s.vmx.paShadowVmcsRoFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
2050 if (!pVM->hmr0.s.vmx.paShadowVmcsFields || !pVM->hmr0.s.vmx.paShadowVmcsRoFields)
2051 rc = VERR_NO_MEMORY;
2052 }
2053#endif
2054
2055 /*
2056 * Allocate per-VCPU VT-x structures.
2057 */
2058 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus && RT_SUCCESS(rc); idCpu++)
2059 {
2060 /* Allocate the guest VMCS structures. */
2061 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2062 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
2063
2064#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2065 /* Allocate the nested-guest VMCS structures, when the VMX feature is exposed to the guest. */
2066 if (pVM->cpum.ro.GuestFeatures.fVmx && RT_SUCCESS(rc))
2067 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
2068#endif
2069 }
2070 if (RT_SUCCESS(rc))
2071 return VINF_SUCCESS;
2072 }
2073 hmR0VmxStructsFree(pVM);
2074 return rc;
2075}
2076
2077
2078/**
2079 * Pre-initializes non-zero fields in VMX structures that will be allocated.
2080 *
2081 * @param pVM The cross context VM structure.
2082 */
2083static void hmR0VmxStructsInit(PVMCC pVM)
2084{
2085 /* Paranoia. */
2086 Assert(pVM->hmr0.s.vmx.pbApicAccess == NULL);
2087#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2088 Assert(pVM->hmr0.s.vmx.pbScratch == NULL);
2089#endif
2090
2091 /*
2092 * Initialize members up-front so we can cleanup en masse on allocation failures.
2093 */
2094#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2095 pVM->hmr0.s.vmx.HCPhysScratch = NIL_RTHCPHYS;
2096#endif
2097 pVM->hmr0.s.vmx.HCPhysApicAccess = NIL_RTHCPHYS;
2098 pVM->hmr0.s.vmx.HCPhysVmreadBitmap = NIL_RTHCPHYS;
2099 pVM->hmr0.s.vmx.HCPhysVmwriteBitmap = NIL_RTHCPHYS;
2100 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
2101 {
2102 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2103 hmR0VmxVmcsInfoInit(&pVCpu->hmr0.s.vmx.VmcsInfo, &pVCpu->hm.s.vmx.VmcsInfo);
2104 hmR0VmxVmcsInfoInit(&pVCpu->hmr0.s.vmx.VmcsInfoNstGst, &pVCpu->hm.s.vmx.VmcsInfoNstGst);
2105 }
2106}
2107
2108#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2109/**
2110 * Returns whether an MSR at the given MSR-bitmap offset is intercepted or not.
2111 *
2112 * @returns @c true if the MSR is intercepted, @c false otherwise.
2113 * @param pvMsrBitmap The MSR bitmap.
2114 * @param offMsr The MSR byte offset.
2115 * @param iBit The bit offset from the byte offset.
2116 */
2117DECLINLINE(bool) hmR0VmxIsMsrBitSet(const void *pvMsrBitmap, uint16_t offMsr, int32_t iBit)
2118{
2119 uint8_t const * const pbMsrBitmap = (uint8_t const * const)pvMsrBitmap;
2120 Assert(pbMsrBitmap);
2121 Assert(offMsr + (iBit >> 3) <= X86_PAGE_4K_SIZE);
2122 return ASMBitTest(pbMsrBitmap + offMsr, iBit);
2123}
2124#endif
2125
2126/**
2127 * Sets the permission bits for the specified MSR in the given MSR bitmap.
2128 *
2129 * If the passed VMCS is a nested-guest VMCS, this function ensures that the
2130 * read/write intercept is cleared from the MSR bitmap used for hardware-assisted
2131 * VMX execution of the nested-guest, only if nested-guest is also not intercepting
2132 * the read/write access of this MSR.
2133 *
2134 * @param pVCpu The cross context virtual CPU structure.
2135 * @param pVmcsInfo The VMCS info. object.
2136 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2137 * @param idMsr The MSR value.
2138 * @param fMsrpm The MSR permissions (see VMXMSRPM_XXX). This must
2139 * include both a read -and- a write permission!
2140 *
2141 * @sa CPUMGetVmxMsrPermission.
2142 * @remarks Can be called with interrupts disabled.
2143 */
2144static void hmR0VmxSetMsrPermission(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs, uint32_t idMsr, uint32_t fMsrpm)
2145{
2146 uint8_t *pbMsrBitmap = (uint8_t *)pVmcsInfo->pvMsrBitmap;
2147 Assert(pbMsrBitmap);
2148 Assert(VMXMSRPM_IS_FLAG_VALID(fMsrpm));
2149
2150 /*
2151 * MSR-bitmap Layout:
2152 * Byte index MSR range Interpreted as
2153 * 0x000 - 0x3ff 0x00000000 - 0x00001fff Low MSR read bits.
2154 * 0x400 - 0x7ff 0xc0000000 - 0xc0001fff High MSR read bits.
2155 * 0x800 - 0xbff 0x00000000 - 0x00001fff Low MSR write bits.
2156 * 0xc00 - 0xfff 0xc0000000 - 0xc0001fff High MSR write bits.
2157 *
2158 * A bit corresponding to an MSR within the above range causes a VM-exit
2159 * if the bit is 1 on executions of RDMSR/WRMSR. If an MSR falls out of
2160 * the MSR range, it always cause a VM-exit.
2161 *
2162 * See Intel spec. 24.6.9 "MSR-Bitmap Address".
2163 */
2164 uint16_t const offBitmapRead = 0;
2165 uint16_t const offBitmapWrite = 0x800;
2166 uint16_t offMsr;
2167 int32_t iBit;
2168 if (idMsr <= UINT32_C(0x00001fff))
2169 {
2170 offMsr = 0;
2171 iBit = idMsr;
2172 }
2173 else if (idMsr - UINT32_C(0xc0000000) <= UINT32_C(0x00001fff))
2174 {
2175 offMsr = 0x400;
2176 iBit = idMsr - UINT32_C(0xc0000000);
2177 }
2178 else
2179 AssertMsgFailedReturnVoid(("Invalid MSR %#RX32\n", idMsr));
2180
2181 /*
2182 * Set the MSR read permission.
2183 */
2184 uint16_t const offMsrRead = offBitmapRead + offMsr;
2185 Assert(offMsrRead + (iBit >> 3) < offBitmapWrite);
2186 if (fMsrpm & VMXMSRPM_ALLOW_RD)
2187 {
2188#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2189 bool const fClear = !fIsNstGstVmcs ? true
2190 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrRead, iBit);
2191#else
2192 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2193 bool const fClear = true;
2194#endif
2195 if (fClear)
2196 ASMBitClear(pbMsrBitmap + offMsrRead, iBit);
2197 }
2198 else
2199 ASMBitSet(pbMsrBitmap + offMsrRead, iBit);
2200
2201 /*
2202 * Set the MSR write permission.
2203 */
2204 uint16_t const offMsrWrite = offBitmapWrite + offMsr;
2205 Assert(offMsrWrite + (iBit >> 3) < X86_PAGE_4K_SIZE);
2206 if (fMsrpm & VMXMSRPM_ALLOW_WR)
2207 {
2208#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2209 bool const fClear = !fIsNstGstVmcs ? true
2210 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), offMsrWrite, iBit);
2211#else
2212 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2213 bool const fClear = true;
2214#endif
2215 if (fClear)
2216 ASMBitClear(pbMsrBitmap + offMsrWrite, iBit);
2217 }
2218 else
2219 ASMBitSet(pbMsrBitmap + offMsrWrite, iBit);
2220}
2221
2222
2223/**
2224 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
2225 * area.
2226 *
2227 * @returns VBox status code.
2228 * @param pVCpu The cross context virtual CPU structure.
2229 * @param pVmcsInfo The VMCS info. object.
2230 * @param cMsrs The number of MSRs.
2231 */
2232static int hmR0VmxSetAutoLoadStoreMsrCount(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t cMsrs)
2233{
2234 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
2235 uint32_t const cMaxSupportedMsrs = VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc);
2236 if (RT_LIKELY(cMsrs < cMaxSupportedMsrs))
2237 {
2238 /* Commit the MSR counts to the VMCS and update the cache. */
2239 if (pVmcsInfo->cEntryMsrLoad != cMsrs)
2240 {
2241 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2242 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs); AssertRC(rc);
2243 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2244 pVmcsInfo->cEntryMsrLoad = cMsrs;
2245 pVmcsInfo->cExitMsrStore = cMsrs;
2246 pVmcsInfo->cExitMsrLoad = cMsrs;
2247 }
2248 return VINF_SUCCESS;
2249 }
2250
2251 LogRel(("Auto-load/store MSR count exceeded! cMsrs=%u MaxSupported=%u\n", cMsrs, cMaxSupportedMsrs));
2252 pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
2253 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2254}
2255
2256
2257/**
2258 * Adds a new (or updates the value of an existing) guest/host MSR
2259 * pair to be swapped during the world-switch as part of the
2260 * auto-load/store MSR area in the VMCS.
2261 *
2262 * @returns VBox status code.
2263 * @param pVCpu The cross context virtual CPU structure.
2264 * @param pVmxTransient The VMX-transient structure.
2265 * @param idMsr The MSR.
2266 * @param uGuestMsrValue Value of the guest MSR.
2267 * @param fSetReadWrite Whether to set the guest read/write access of this
2268 * MSR (thus not causing a VM-exit).
2269 * @param fUpdateHostMsr Whether to update the value of the host MSR if
2270 * necessary.
2271 */
2272static int hmR0VmxAddAutoLoadStoreMsr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t idMsr, uint64_t uGuestMsrValue,
2273 bool fSetReadWrite, bool fUpdateHostMsr)
2274{
2275 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2276 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2277 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2278 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2279 uint32_t i;
2280
2281 /* Paranoia. */
2282 Assert(pGuestMsrLoad);
2283
2284#ifndef DEBUG_bird
2285 LogFlowFunc(("pVCpu=%p idMsr=%#RX32 uGuestMsrValue=%#RX64\n", pVCpu, idMsr, uGuestMsrValue));
2286#endif
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#ifndef DEBUG_bird
2372 LogFlowFunc(("pVCpu=%p idMsr=%#RX32\n", pVCpu, idMsr));
2373#endif
2374
2375 for (uint32_t i = 0; i < cMsrs; i++)
2376 {
2377 /* Find the MSR. */
2378 if (pGuestMsrLoad[i].u32Msr == idMsr)
2379 {
2380 /*
2381 * If it's the last MSR, we only need to reduce the MSR count.
2382 * If it's -not- the last MSR, copy the last MSR in place of it and reduce the MSR count.
2383 */
2384 if (i < cMsrs - 1)
2385 {
2386 /* Remove it from the VM-entry MSR-load area. */
2387 pGuestMsrLoad[i].u32Msr = pGuestMsrLoad[cMsrs - 1].u32Msr;
2388 pGuestMsrLoad[i].u64Value = pGuestMsrLoad[cMsrs - 1].u64Value;
2389
2390 /* Remove it from the VM-exit MSR-store area if it's in a different page. */
2391 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2392 {
2393 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2394 Assert(pGuestMsrStore[i].u32Msr == idMsr);
2395 pGuestMsrStore[i].u32Msr = pGuestMsrStore[cMsrs - 1].u32Msr;
2396 pGuestMsrStore[i].u64Value = pGuestMsrStore[cMsrs - 1].u64Value;
2397 }
2398
2399 /* Remove it from the VM-exit MSR-load area. */
2400 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2401 Assert(pHostMsr[i].u32Msr == idMsr);
2402 pHostMsr[i].u32Msr = pHostMsr[cMsrs - 1].u32Msr;
2403 pHostMsr[i].u64Value = pHostMsr[cMsrs - 1].u64Value;
2404 }
2405
2406 /* Reduce the count to reflect the removed MSR and bail. */
2407 --cMsrs;
2408 break;
2409 }
2410 }
2411
2412 /* Update the VMCS if the count changed (meaning the MSR was found and removed). */
2413 if (cMsrs != pVmcsInfo->cEntryMsrLoad)
2414 {
2415 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2416 AssertRCReturn(rc, rc);
2417
2418 /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
2419 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2420 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR);
2421
2422 Log4Func(("Removed MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2423 return VINF_SUCCESS;
2424 }
2425
2426 return VERR_NOT_FOUND;
2427}
2428
2429
2430/**
2431 * Checks if the specified guest MSR is part of the VM-entry MSR-load area.
2432 *
2433 * @returns @c true if found, @c false otherwise.
2434 * @param pVmcsInfo The VMCS info. object.
2435 * @param idMsr The MSR to find.
2436 */
2437static bool hmR0VmxIsAutoLoadGuestMsr(PCVMXVMCSINFO pVmcsInfo, uint32_t idMsr)
2438{
2439 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2440 uint32_t const cMsrs = pVmcsInfo->cEntryMsrLoad;
2441 Assert(pMsrs);
2442 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
2443 for (uint32_t i = 0; i < cMsrs; i++)
2444 {
2445 if (pMsrs[i].u32Msr == idMsr)
2446 return true;
2447 }
2448 return false;
2449}
2450
2451
2452/**
2453 * Updates the value of all host MSRs in the VM-exit MSR-load area.
2454 *
2455 * @param pVCpu The cross context virtual CPU structure.
2456 * @param pVmcsInfo The VMCS info. object.
2457 *
2458 * @remarks No-long-jump zone!!!
2459 */
2460static void hmR0VmxUpdateAutoLoadHostMsrs(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2461{
2462 RT_NOREF(pVCpu);
2463 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2464
2465 PVMXAUTOMSR pHostMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2466 uint32_t const cMsrs = pVmcsInfo->cExitMsrLoad;
2467 Assert(pHostMsrLoad);
2468 Assert(sizeof(*pHostMsrLoad) * cMsrs <= X86_PAGE_4K_SIZE);
2469 LogFlowFunc(("pVCpu=%p cMsrs=%u\n", pVCpu, cMsrs));
2470 for (uint32_t i = 0; i < cMsrs; i++)
2471 {
2472 /*
2473 * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
2474 * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
2475 */
2476 if (pHostMsrLoad[i].u32Msr == MSR_K6_EFER)
2477 pHostMsrLoad[i].u64Value = g_uHmVmxHostMsrEfer;
2478 else
2479 pHostMsrLoad[i].u64Value = ASMRdMsr(pHostMsrLoad[i].u32Msr);
2480 }
2481}
2482
2483
2484/**
2485 * Saves a set of host MSRs to allow read/write passthru access to the guest and
2486 * perform lazy restoration of the host MSRs while leaving VT-x.
2487 *
2488 * @param pVCpu The cross context virtual CPU structure.
2489 *
2490 * @remarks No-long-jump zone!!!
2491 */
2492static void hmR0VmxLazySaveHostMsrs(PVMCPUCC pVCpu)
2493{
2494 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2495
2496 /*
2497 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap accesses in hmR0VmxSetupVmcsProcCtls().
2498 */
2499 if (!(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST))
2500 {
2501 Assert(!(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)); /* Guest MSRs better not be loaded now. */
2502 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2503 {
2504 pVCpu->hmr0.s.vmx.u64HostMsrLStar = ASMRdMsr(MSR_K8_LSTAR);
2505 pVCpu->hmr0.s.vmx.u64HostMsrStar = ASMRdMsr(MSR_K6_STAR);
2506 pVCpu->hmr0.s.vmx.u64HostMsrSfMask = ASMRdMsr(MSR_K8_SF_MASK);
2507 pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
2508 }
2509 pVCpu->hmr0.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
2510 }
2511}
2512
2513
2514/**
2515 * Checks whether the MSR belongs to the set of guest MSRs that we restore
2516 * lazily while leaving VT-x.
2517 *
2518 * @returns true if it does, false otherwise.
2519 * @param pVCpu The cross context virtual CPU structure.
2520 * @param idMsr The MSR to check.
2521 */
2522static bool hmR0VmxIsLazyGuestMsr(PCVMCPUCC pVCpu, uint32_t idMsr)
2523{
2524 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2525 {
2526 switch (idMsr)
2527 {
2528 case MSR_K8_LSTAR:
2529 case MSR_K6_STAR:
2530 case MSR_K8_SF_MASK:
2531 case MSR_K8_KERNEL_GS_BASE:
2532 return true;
2533 }
2534 }
2535 return false;
2536}
2537
2538
2539/**
2540 * Loads a set of guests MSRs to allow read/passthru to the guest.
2541 *
2542 * The name of this function is slightly confusing. This function does NOT
2543 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
2544 * common prefix for functions dealing with "lazy restoration" of the shared
2545 * MSRs.
2546 *
2547 * @param pVCpu The cross context virtual CPU structure.
2548 *
2549 * @remarks No-long-jump zone!!!
2550 */
2551static void hmR0VmxLazyLoadGuestMsrs(PVMCPUCC pVCpu)
2552{
2553 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2554 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2555
2556 Assert(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2557 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2558 {
2559 /*
2560 * If the guest MSRs are not loaded -and- if all the guest MSRs are identical
2561 * to the MSRs on the CPU (which are the saved host MSRs, see assertion above) then
2562 * we can skip a few MSR writes.
2563 *
2564 * Otherwise, it implies either 1. they're not loaded, or 2. they're loaded but the
2565 * guest MSR values in the guest-CPU context might be different to what's currently
2566 * loaded in the CPU. In either case, we need to write the new guest MSR values to the
2567 * CPU, see @bugref{8728}.
2568 */
2569 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2570 if ( !(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2571 && pCtx->msrKERNELGSBASE == pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase
2572 && pCtx->msrLSTAR == pVCpu->hmr0.s.vmx.u64HostMsrLStar
2573 && pCtx->msrSTAR == pVCpu->hmr0.s.vmx.u64HostMsrStar
2574 && pCtx->msrSFMASK == pVCpu->hmr0.s.vmx.u64HostMsrSfMask)
2575 {
2576#ifdef VBOX_STRICT
2577 Assert(ASMRdMsr(MSR_K8_KERNEL_GS_BASE) == pCtx->msrKERNELGSBASE);
2578 Assert(ASMRdMsr(MSR_K8_LSTAR) == pCtx->msrLSTAR);
2579 Assert(ASMRdMsr(MSR_K6_STAR) == pCtx->msrSTAR);
2580 Assert(ASMRdMsr(MSR_K8_SF_MASK) == pCtx->msrSFMASK);
2581#endif
2582 }
2583 else
2584 {
2585 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pCtx->msrKERNELGSBASE);
2586 ASMWrMsr(MSR_K8_LSTAR, pCtx->msrLSTAR);
2587 ASMWrMsr(MSR_K6_STAR, pCtx->msrSTAR);
2588 /* The system call flag mask register isn't as benign and accepting of all
2589 values as the above, so mask it to avoid #GP'ing on corrupted input. */
2590 Assert(!(pCtx->msrSFMASK & ~(uint64_t)UINT32_MAX));
2591 ASMWrMsr(MSR_K8_SF_MASK, pCtx->msrSFMASK & UINT32_MAX);
2592 }
2593 }
2594 pVCpu->hmr0.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
2595}
2596
2597
2598/**
2599 * Performs lazy restoration of the set of host MSRs if they were previously
2600 * loaded with guest MSR values.
2601 *
2602 * @param pVCpu The cross context virtual CPU structure.
2603 *
2604 * @remarks No-long-jump zone!!!
2605 * @remarks The guest MSRs should have been saved back into the guest-CPU
2606 * context by hmR0VmxImportGuestState()!!!
2607 */
2608static void hmR0VmxLazyRestoreHostMsrs(PVMCPUCC pVCpu)
2609{
2610 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2611 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2612
2613 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2614 {
2615 Assert(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2616 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2617 {
2618 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hmr0.s.vmx.u64HostMsrLStar);
2619 ASMWrMsr(MSR_K6_STAR, pVCpu->hmr0.s.vmx.u64HostMsrStar);
2620 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hmr0.s.vmx.u64HostMsrSfMask);
2621 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase);
2622 }
2623 }
2624 pVCpu->hmr0.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
2625}
2626
2627
2628/**
2629 * Verifies that our cached values of the VMCS fields are all consistent with
2630 * what's actually present in the VMCS.
2631 *
2632 * @returns VBox status code.
2633 * @retval VINF_SUCCESS if all our caches match their respective VMCS fields.
2634 * @retval VERR_VMX_VMCS_FIELD_CACHE_INVALID if a cache field doesn't match the
2635 * VMCS content. HMCPU error-field is
2636 * updated, see VMX_VCI_XXX.
2637 * @param pVCpu The cross context virtual CPU structure.
2638 * @param pVmcsInfo The VMCS info. object.
2639 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2640 */
2641static int hmR0VmxCheckCachedVmcsCtls(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2642{
2643 const char * const pcszVmcs = fIsNstGstVmcs ? "Nested-guest VMCS" : "VMCS";
2644
2645 uint32_t u32Val;
2646 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
2647 AssertRC(rc);
2648 AssertMsgReturnStmt(pVmcsInfo->u32EntryCtls == u32Val,
2649 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32EntryCtls, u32Val),
2650 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_ENTRY,
2651 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2652
2653 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
2654 AssertRC(rc);
2655 AssertMsgReturnStmt(pVmcsInfo->u32ExitCtls == u32Val,
2656 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ExitCtls, u32Val),
2657 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_EXIT,
2658 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2659
2660 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
2661 AssertRC(rc);
2662 AssertMsgReturnStmt(pVmcsInfo->u32PinCtls == u32Val,
2663 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32PinCtls, u32Val),
2664 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PIN_EXEC,
2665 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2666
2667 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
2668 AssertRC(rc);
2669 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls == u32Val,
2670 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls, u32Val),
2671 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC,
2672 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2673
2674 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2675 {
2676 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
2677 AssertRC(rc);
2678 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls2 == u32Val,
2679 ("%s controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls2, u32Val),
2680 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC2,
2681 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2682 }
2683
2684 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val);
2685 AssertRC(rc);
2686 AssertMsgReturnStmt(pVmcsInfo->u32XcptBitmap == u32Val,
2687 ("%s exception bitmap mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32XcptBitmap, u32Val),
2688 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_XCPT_BITMAP,
2689 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2690
2691 uint64_t u64Val;
2692 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, &u64Val);
2693 AssertRC(rc);
2694 AssertMsgReturnStmt(pVmcsInfo->u64TscOffset == u64Val,
2695 ("%s TSC offset mismatch: Cache=%#RX64 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64TscOffset, u64Val),
2696 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_TSC_OFFSET,
2697 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2698
2699 NOREF(pcszVmcs);
2700 return VINF_SUCCESS;
2701}
2702
2703#ifdef VBOX_STRICT
2704
2705/**
2706 * Verifies that our cached host EFER MSR value has not changed since we cached it.
2707 *
2708 * @param pVmcsInfo The VMCS info. object.
2709 */
2710static void hmR0VmxCheckHostEferMsr(PCVMXVMCSINFO pVmcsInfo)
2711{
2712 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2713
2714 if (pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
2715 {
2716 uint64_t const uHostEferMsr = ASMRdMsr(MSR_K6_EFER);
2717 uint64_t const uHostEferMsrCache = g_uHmVmxHostMsrEfer;
2718 uint64_t uVmcsEferMsrVmcs;
2719 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &uVmcsEferMsrVmcs);
2720 AssertRC(rc);
2721
2722 AssertMsgReturnVoid(uHostEferMsr == uVmcsEferMsrVmcs,
2723 ("EFER Host/VMCS mismatch! host=%#RX64 vmcs=%#RX64\n", uHostEferMsr, uVmcsEferMsrVmcs));
2724 AssertMsgReturnVoid(uHostEferMsr == uHostEferMsrCache,
2725 ("EFER Host/Cache mismatch! host=%#RX64 cache=%#RX64\n", uHostEferMsr, uHostEferMsrCache));
2726 }
2727}
2728
2729
2730/**
2731 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
2732 * VMCS are correct.
2733 *
2734 * @param pVCpu The cross context virtual CPU structure.
2735 * @param pVmcsInfo The VMCS info. object.
2736 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2737 */
2738static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2739{
2740 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2741
2742 /* Read the various MSR-area counts from the VMCS. */
2743 uint32_t cEntryLoadMsrs;
2744 uint32_t cExitStoreMsrs;
2745 uint32_t cExitLoadMsrs;
2746 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cEntryLoadMsrs); AssertRC(rc);
2747 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cExitStoreMsrs); AssertRC(rc);
2748 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cExitLoadMsrs); AssertRC(rc);
2749
2750 /* Verify all the MSR counts are the same. */
2751 Assert(cEntryLoadMsrs == cExitStoreMsrs);
2752 Assert(cExitStoreMsrs == cExitLoadMsrs);
2753 uint32_t const cMsrs = cExitLoadMsrs;
2754
2755 /* Verify the MSR counts do not exceed the maximum count supported by the hardware. */
2756 Assert(cMsrs < VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc));
2757
2758 /* Verify the MSR counts are within the allocated page size. */
2759 Assert(sizeof(VMXAUTOMSR) * cMsrs <= X86_PAGE_4K_SIZE);
2760
2761 /* Verify the relevant contents of the MSR areas match. */
2762 PCVMXAUTOMSR pGuestMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2763 PCVMXAUTOMSR pGuestMsrStore = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2764 PCVMXAUTOMSR pHostMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2765 bool const fSeparateExitMsrStorePage = hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo);
2766 for (uint32_t i = 0; i < cMsrs; i++)
2767 {
2768 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
2769 if (fSeparateExitMsrStorePage)
2770 {
2771 AssertMsgReturnVoid(pGuestMsrLoad->u32Msr == pGuestMsrStore->u32Msr,
2772 ("GuestMsrLoad=%#RX32 GuestMsrStore=%#RX32 cMsrs=%u\n",
2773 pGuestMsrLoad->u32Msr, pGuestMsrStore->u32Msr, cMsrs));
2774 }
2775
2776 AssertMsgReturnVoid(pHostMsrLoad->u32Msr == pGuestMsrLoad->u32Msr,
2777 ("HostMsrLoad=%#RX32 GuestMsrLoad=%#RX32 cMsrs=%u\n",
2778 pHostMsrLoad->u32Msr, pGuestMsrLoad->u32Msr, cMsrs));
2779
2780 uint64_t const u64HostMsr = ASMRdMsr(pHostMsrLoad->u32Msr);
2781 AssertMsgReturnVoid(pHostMsrLoad->u64Value == u64HostMsr,
2782 ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2783 pHostMsrLoad->u32Msr, pHostMsrLoad->u64Value, u64HostMsr, cMsrs));
2784
2785 /* Verify that cached host EFER MSR matches what's loaded on the CPU. */
2786 bool const fIsEferMsr = RT_BOOL(pHostMsrLoad->u32Msr == MSR_K6_EFER);
2787 AssertMsgReturnVoid(!fIsEferMsr || u64HostMsr == g_uHmVmxHostMsrEfer,
2788 ("Cached=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n", g_uHmVmxHostMsrEfer, u64HostMsr, cMsrs));
2789
2790 /* Verify that the accesses are as expected in the MSR bitmap for auto-load/store MSRs. */
2791 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2792 {
2793 uint32_t const fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, pGuestMsrLoad->u32Msr);
2794 if (fIsEferMsr)
2795 {
2796 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_RD), ("Passthru read for EFER MSR!?\n"));
2797 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_WR), ("Passthru write for EFER MSR!?\n"));
2798 }
2799 else
2800 {
2801 /* Verify LBR MSRs (used only for debugging) are intercepted. We don't passthru these MSRs to the guest yet. */
2802 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
2803 if ( pVM->hmr0.s.vmx.fLbr
2804 && ( hmR0VmxIsLbrBranchFromMsr(pVM, pGuestMsrLoad->u32Msr, NULL /* pidxMsr */)
2805 || hmR0VmxIsLbrBranchToMsr(pVM, pGuestMsrLoad->u32Msr, NULL /* pidxMsr */)
2806 || pGuestMsrLoad->u32Msr == pVM->hmr0.s.vmx.idLbrTosMsr))
2807 {
2808 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_MASK) == VMXMSRPM_EXIT_RD_WR,
2809 ("u32Msr=%#RX32 cMsrs=%u Passthru read/write for LBR MSRs!\n",
2810 pGuestMsrLoad->u32Msr, cMsrs));
2811 }
2812 else if (!fIsNstGstVmcs)
2813 {
2814 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_MASK) == VMXMSRPM_ALLOW_RD_WR,
2815 ("u32Msr=%#RX32 cMsrs=%u No passthru read/write!\n", pGuestMsrLoad->u32Msr, cMsrs));
2816 }
2817 else
2818 {
2819 /*
2820 * A nested-guest VMCS must -also- allow read/write passthrough for the MSR for us to
2821 * execute a nested-guest with MSR passthrough.
2822 *
2823 * Check if the nested-guest MSR bitmap allows passthrough, and if so, assert that we
2824 * allow passthrough too.
2825 */
2826 void const *pvMsrBitmapNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
2827 Assert(pvMsrBitmapNstGst);
2828 uint32_t const fMsrpmNstGst = CPUMGetVmxMsrPermission(pvMsrBitmapNstGst, pGuestMsrLoad->u32Msr);
2829 AssertMsgReturnVoid(fMsrpm == fMsrpmNstGst,
2830 ("u32Msr=%#RX32 cMsrs=%u Permission mismatch fMsrpm=%#x fMsrpmNstGst=%#x!\n",
2831 pGuestMsrLoad->u32Msr, cMsrs, fMsrpm, fMsrpmNstGst));
2832 }
2833 }
2834 }
2835
2836 /* Move to the next MSR. */
2837 pHostMsrLoad++;
2838 pGuestMsrLoad++;
2839 pGuestMsrStore++;
2840 }
2841}
2842
2843#endif /* VBOX_STRICT */
2844
2845/**
2846 * Flushes the TLB using EPT.
2847 *
2848 * @returns VBox status code.
2849 * @param pVCpu The cross context virtual CPU structure of the calling
2850 * EMT. Can be NULL depending on @a enmTlbFlush.
2851 * @param pVmcsInfo The VMCS info. object. Can be NULL depending on @a
2852 * enmTlbFlush.
2853 * @param enmTlbFlush Type of flush.
2854 *
2855 * @remarks Caller is responsible for making sure this function is called only
2856 * when NestedPaging is supported and providing @a enmTlbFlush that is
2857 * supported by the CPU.
2858 * @remarks Can be called with interrupts disabled.
2859 */
2860static void hmR0VmxFlushEpt(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, VMXTLBFLUSHEPT enmTlbFlush)
2861{
2862 uint64_t au64Descriptor[2];
2863 if (enmTlbFlush == VMXTLBFLUSHEPT_ALL_CONTEXTS)
2864 au64Descriptor[0] = 0;
2865 else
2866 {
2867 Assert(pVCpu);
2868 Assert(pVmcsInfo);
2869 au64Descriptor[0] = pVmcsInfo->HCPhysEPTP;
2870 }
2871 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
2872
2873 int rc = VMXR0InvEPT(enmTlbFlush, &au64Descriptor[0]);
2874 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %#RHp failed. rc=%Rrc\n", enmTlbFlush, au64Descriptor[0], rc));
2875
2876 if ( RT_SUCCESS(rc)
2877 && pVCpu)
2878 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
2879}
2880
2881
2882/**
2883 * Flushes the TLB using VPID.
2884 *
2885 * @returns VBox status code.
2886 * @param pVCpu The cross context virtual CPU structure of the calling
2887 * EMT. Can be NULL depending on @a enmTlbFlush.
2888 * @param enmTlbFlush Type of flush.
2889 * @param GCPtr Virtual address of the page to flush (can be 0 depending
2890 * on @a enmTlbFlush).
2891 *
2892 * @remarks Can be called with interrupts disabled.
2893 */
2894static void hmR0VmxFlushVpid(PVMCPUCC pVCpu, VMXTLBFLUSHVPID enmTlbFlush, RTGCPTR GCPtr)
2895{
2896 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid);
2897
2898 uint64_t au64Descriptor[2];
2899 if (enmTlbFlush == VMXTLBFLUSHVPID_ALL_CONTEXTS)
2900 {
2901 au64Descriptor[0] = 0;
2902 au64Descriptor[1] = 0;
2903 }
2904 else
2905 {
2906 AssertPtr(pVCpu);
2907 AssertMsg(pVCpu->hmr0.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hmr0.s.uCurrentAsid));
2908 AssertMsg(pVCpu->hmr0.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hmr0.s.uCurrentAsid));
2909 au64Descriptor[0] = pVCpu->hmr0.s.uCurrentAsid;
2910 au64Descriptor[1] = GCPtr;
2911 }
2912
2913 int rc = VMXR0InvVPID(enmTlbFlush, &au64Descriptor[0]);
2914 AssertMsg(rc == VINF_SUCCESS,
2915 ("VMXR0InvVPID %#x %u %RGv failed with %Rrc\n", enmTlbFlush, pVCpu ? pVCpu->hmr0.s.uCurrentAsid : 0, GCPtr, rc));
2916
2917 if ( RT_SUCCESS(rc)
2918 && pVCpu)
2919 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
2920 NOREF(rc);
2921}
2922
2923
2924/**
2925 * Invalidates a guest page by guest virtual address. Only relevant for EPT/VPID,
2926 * otherwise there is nothing really to invalidate.
2927 *
2928 * @returns VBox status code.
2929 * @param pVCpu The cross context virtual CPU structure.
2930 * @param GCVirt Guest virtual address of the page to invalidate.
2931 */
2932VMMR0DECL(int) VMXR0InvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt)
2933{
2934 AssertPtr(pVCpu);
2935 LogFlowFunc(("pVCpu=%p GCVirt=%RGv\n", pVCpu, GCVirt));
2936
2937 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TLB_FLUSH))
2938 {
2939 /*
2940 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for
2941 * the EPT case. See @bugref{6043} and @bugref{6177}.
2942 *
2943 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*()
2944 * as this function maybe called in a loop with individual addresses.
2945 */
2946 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2947 if (pVM->hmr0.s.vmx.fVpid)
2948 {
2949 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
2950 {
2951 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_INDIV_ADDR, GCVirt);
2952 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
2953 }
2954 else
2955 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2956 }
2957 else if (pVM->hmr0.s.fNestedPaging)
2958 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2959 }
2960
2961 return VINF_SUCCESS;
2962}
2963
2964
2965/**
2966 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
2967 * case where neither EPT nor VPID is supported by the CPU.
2968 *
2969 * @param pHostCpu The HM physical-CPU structure.
2970 * @param pVCpu The cross context virtual CPU structure.
2971 *
2972 * @remarks Called with interrupts disabled.
2973 */
2974static void hmR0VmxFlushTaggedTlbNone(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
2975{
2976 AssertPtr(pVCpu);
2977 AssertPtr(pHostCpu);
2978
2979 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2980
2981 Assert(pHostCpu->idCpu != NIL_RTCPUID);
2982 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
2983 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
2984 pVCpu->hmr0.s.fForceTLBFlush = false;
2985 return;
2986}
2987
2988
2989/**
2990 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
2991 *
2992 * @param pHostCpu The HM physical-CPU structure.
2993 * @param pVCpu The cross context virtual CPU structure.
2994 * @param pVmcsInfo The VMCS info. object.
2995 *
2996 * @remarks All references to "ASID" in this function pertains to "VPID" in Intel's
2997 * nomenclature. The reason is, to avoid confusion in compare statements
2998 * since the host-CPU copies are named "ASID".
2999 *
3000 * @remarks Called with interrupts disabled.
3001 */
3002static void hmR0VmxFlushTaggedTlbBoth(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3003{
3004#ifdef VBOX_WITH_STATISTICS
3005 bool fTlbFlushed = false;
3006# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
3007# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
3008 if (!fTlbFlushed) \
3009 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
3010 } while (0)
3011#else
3012# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
3013# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
3014#endif
3015
3016 AssertPtr(pVCpu);
3017 AssertPtr(pHostCpu);
3018 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3019
3020 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3021 AssertMsg(pVM->hmr0.s.fNestedPaging && pVM->hmr0.s.vmx.fVpid,
3022 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
3023 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hmr0.s.fNestedPaging, pVM->hmr0.s.vmx.fVpid));
3024
3025 /*
3026 * Force a TLB flush for the first world-switch if the current CPU differs from the one we
3027 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3028 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3029 * cannot reuse the current ASID anymore.
3030 */
3031 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3032 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3033 {
3034 ++pHostCpu->uCurrentAsid;
3035 if (pHostCpu->uCurrentAsid >= g_uHmMaxAsid)
3036 {
3037 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
3038 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3039 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3040 }
3041
3042 pVCpu->hmr0.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3043 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3044 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3045
3046 /*
3047 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
3048 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
3049 */
3050 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3051 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3052 HMVMX_SET_TAGGED_TLB_FLUSHED();
3053 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
3054 }
3055 else if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH)) /* Check for explicit TLB flushes. */
3056 {
3057 /*
3058 * Changes to the EPT paging structure by VMM requires flushing-by-EPT as the CPU
3059 * creates guest-physical (ie. only EPT-tagged) mappings while traversing the EPT
3060 * tables when EPT is in use. Flushing-by-VPID will only flush linear (only
3061 * VPID-tagged) and combined (EPT+VPID tagged) mappings but not guest-physical
3062 * mappings, see @bugref{6568}.
3063 *
3064 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information".
3065 */
3066 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3067 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3068 HMVMX_SET_TAGGED_TLB_FLUSHED();
3069 }
3070 else if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3071 {
3072 /*
3073 * The nested-guest specifies its own guest-physical address to use as the APIC-access
3074 * address which requires flushing the TLB of EPT cached structures.
3075 *
3076 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
3077 */
3078 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3079 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3080 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3081 HMVMX_SET_TAGGED_TLB_FLUSHED();
3082 }
3083
3084
3085 pVCpu->hmr0.s.fForceTLBFlush = false;
3086 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
3087
3088 Assert(pVCpu->hmr0.s.idLastCpu == pHostCpu->idCpu);
3089 Assert(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes);
3090 AssertMsg(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3091 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hmr0.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3092 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < g_uHmMaxAsid,
3093 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3094 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hmr0.s.idLastCpu, pVCpu->hmr0.s.cTlbFlushes));
3095 AssertMsg(pVCpu->hmr0.s.uCurrentAsid >= 1 && pVCpu->hmr0.s.uCurrentAsid < g_uHmMaxAsid,
3096 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hmr0.s.uCurrentAsid));
3097
3098 /* Update VMCS with the VPID. */
3099 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hmr0.s.uCurrentAsid);
3100 AssertRC(rc);
3101
3102#undef HMVMX_SET_TAGGED_TLB_FLUSHED
3103}
3104
3105
3106/**
3107 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
3108 *
3109 * @param pHostCpu The HM physical-CPU structure.
3110 * @param pVCpu The cross context virtual CPU structure.
3111 * @param pVmcsInfo The VMCS info. object.
3112 *
3113 * @remarks Called with interrupts disabled.
3114 */
3115static void hmR0VmxFlushTaggedTlbEpt(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3116{
3117 AssertPtr(pVCpu);
3118 AssertPtr(pHostCpu);
3119 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3120 AssertMsg(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked without NestedPaging."));
3121 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID."));
3122
3123 /*
3124 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
3125 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
3126 */
3127 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3128 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3129 {
3130 pVCpu->hmr0.s.fForceTLBFlush = true;
3131 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3132 }
3133
3134 /* Check for explicit TLB flushes. */
3135 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3136 {
3137 pVCpu->hmr0.s.fForceTLBFlush = true;
3138 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3139 }
3140
3141 /* Check for TLB flushes while switching to/from a nested-guest. */
3142 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3143 {
3144 pVCpu->hmr0.s.fForceTLBFlush = true;
3145 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3146 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3147 }
3148
3149 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3150 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3151
3152 if (pVCpu->hmr0.s.fForceTLBFlush)
3153 {
3154 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.enmTlbFlushEpt);
3155 pVCpu->hmr0.s.fForceTLBFlush = false;
3156 }
3157}
3158
3159
3160/**
3161 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
3162 *
3163 * @param pHostCpu The HM physical-CPU structure.
3164 * @param pVCpu The cross context virtual CPU structure.
3165 *
3166 * @remarks Called with interrupts disabled.
3167 */
3168static void hmR0VmxFlushTaggedTlbVpid(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
3169{
3170 AssertPtr(pVCpu);
3171 AssertPtr(pHostCpu);
3172 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3173 AssertMsg(pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked without VPID."));
3174 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging"));
3175
3176 /*
3177 * Force a TLB flush for the first world switch if the current CPU differs from the one we
3178 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3179 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3180 * cannot reuse the current ASID anymore.
3181 */
3182 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3183 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3184 {
3185 pVCpu->hmr0.s.fForceTLBFlush = true;
3186 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3187 }
3188
3189 /* Check for explicit TLB flushes. */
3190 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3191 {
3192 /*
3193 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see
3194 * hmR0VmxSetupTaggedTlb()) we would need to explicitly flush in this case (add an
3195 * fExplicitFlush = true here and change the pHostCpu->fFlushAsidBeforeUse check below to
3196 * include fExplicitFlush's too) - an obscure corner case.
3197 */
3198 pVCpu->hmr0.s.fForceTLBFlush = true;
3199 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3200 }
3201
3202 /* Check for TLB flushes while switching to/from a nested-guest. */
3203 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3204 {
3205 pVCpu->hmr0.s.fForceTLBFlush = true;
3206 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3207 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3208 }
3209
3210 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3211 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3212 if (pVCpu->hmr0.s.fForceTLBFlush)
3213 {
3214 ++pHostCpu->uCurrentAsid;
3215 if (pHostCpu->uCurrentAsid >= g_uHmMaxAsid)
3216 {
3217 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
3218 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3219 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3220 }
3221
3222 pVCpu->hmr0.s.fForceTLBFlush = false;
3223 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3224 pVCpu->hmr0.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3225 if (pHostCpu->fFlushAsidBeforeUse)
3226 {
3227 if (pVM->hmr0.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_SINGLE_CONTEXT)
3228 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
3229 else if (pVM->hmr0.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_ALL_CONTEXTS)
3230 {
3231 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
3232 pHostCpu->fFlushAsidBeforeUse = false;
3233 }
3234 else
3235 {
3236 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
3237 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
3238 }
3239 }
3240 }
3241
3242 AssertMsg(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3243 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hmr0.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3244 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < g_uHmMaxAsid,
3245 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3246 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hmr0.s.idLastCpu, pVCpu->hmr0.s.cTlbFlushes));
3247 AssertMsg(pVCpu->hmr0.s.uCurrentAsid >= 1 && pVCpu->hmr0.s.uCurrentAsid < g_uHmMaxAsid,
3248 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hmr0.s.uCurrentAsid));
3249
3250 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hmr0.s.uCurrentAsid);
3251 AssertRC(rc);
3252}
3253
3254
3255/**
3256 * Flushes the guest TLB entry based on CPU capabilities.
3257 *
3258 * @param pHostCpu The HM physical-CPU structure.
3259 * @param pVCpu The cross context virtual CPU structure.
3260 * @param pVmcsInfo The VMCS info. object.
3261 *
3262 * @remarks Called with interrupts disabled.
3263 */
3264static void hmR0VmxFlushTaggedTlb(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3265{
3266#ifdef HMVMX_ALWAYS_FLUSH_TLB
3267 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
3268#endif
3269 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3270 switch (pVM->hmr0.s.vmx.enmTlbFlushType)
3271 {
3272 case VMXTLBFLUSHTYPE_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pHostCpu, pVCpu, pVmcsInfo); break;
3273 case VMXTLBFLUSHTYPE_EPT: hmR0VmxFlushTaggedTlbEpt(pHostCpu, pVCpu, pVmcsInfo); break;
3274 case VMXTLBFLUSHTYPE_VPID: hmR0VmxFlushTaggedTlbVpid(pHostCpu, pVCpu); break;
3275 case VMXTLBFLUSHTYPE_NONE: hmR0VmxFlushTaggedTlbNone(pHostCpu, pVCpu); break;
3276 default:
3277 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
3278 break;
3279 }
3280 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
3281}
3282
3283
3284/**
3285 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
3286 * TLB entries from the host TLB before VM-entry.
3287 *
3288 * @returns VBox status code.
3289 * @param pVM The cross context VM structure.
3290 */
3291static int hmR0VmxSetupTaggedTlb(PVMCC pVM)
3292{
3293 /*
3294 * Determine optimal flush type for nested paging.
3295 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup
3296 * unrestricted guest execution (see hmR3InitFinalizeR0()).
3297 */
3298 if (pVM->hmr0.s.fNestedPaging)
3299 {
3300 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
3301 {
3302 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
3303 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_SINGLE_CONTEXT;
3304 else if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
3305 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_ALL_CONTEXTS;
3306 else
3307 {
3308 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
3309 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3310 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
3311 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3312 }
3313
3314 /* Make sure the write-back cacheable memory type for EPT is supported. */
3315 if (RT_UNLIKELY(!(g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EMT_WB)))
3316 {
3317 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3318 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
3319 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3320 }
3321
3322 /* EPT requires a page-walk length of 4. */
3323 if (RT_UNLIKELY(!(g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
3324 {
3325 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3326 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
3327 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3328 }
3329 }
3330 else
3331 {
3332 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
3333 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3334 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
3335 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3336 }
3337 }
3338
3339 /*
3340 * Determine optimal flush type for VPID.
3341 */
3342 if (pVM->hmr0.s.vmx.fVpid)
3343 {
3344 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
3345 {
3346 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
3347 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_SINGLE_CONTEXT;
3348 else if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
3349 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_ALL_CONTEXTS;
3350 else
3351 {
3352 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
3353 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
3354 LogRelFunc(("Only INDIV_ADDR supported. Ignoring VPID.\n"));
3355 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
3356 LogRelFunc(("Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
3357 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3358 pVM->hmr0.s.vmx.fVpid = false;
3359 }
3360 }
3361 else
3362 {
3363 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
3364 Log4Func(("VPID supported without INVEPT support. Ignoring VPID.\n"));
3365 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3366 pVM->hmr0.s.vmx.fVpid = false;
3367 }
3368 }
3369
3370 /*
3371 * Setup the handler for flushing tagged-TLBs.
3372 */
3373 if (pVM->hmr0.s.fNestedPaging && pVM->hmr0.s.vmx.fVpid)
3374 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT_VPID;
3375 else if (pVM->hmr0.s.fNestedPaging)
3376 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT;
3377 else if (pVM->hmr0.s.vmx.fVpid)
3378 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_VPID;
3379 else
3380 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_NONE;
3381
3382
3383 /*
3384 * Copy out the result to ring-3.
3385 */
3386 pVM->hm.s.ForR3.vmx.fVpid = pVM->hmr0.s.vmx.fVpid;
3387 pVM->hm.s.ForR3.vmx.enmTlbFlushType = pVM->hmr0.s.vmx.enmTlbFlushType;
3388 pVM->hm.s.ForR3.vmx.enmTlbFlushEpt = pVM->hmr0.s.vmx.enmTlbFlushEpt;
3389 pVM->hm.s.ForR3.vmx.enmTlbFlushVpid = pVM->hmr0.s.vmx.enmTlbFlushVpid;
3390 return VINF_SUCCESS;
3391}
3392
3393
3394/**
3395 * Sets up the LBR MSR ranges based on the host CPU.
3396 *
3397 * @returns VBox status code.
3398 * @param pVM The cross context VM structure.
3399 */
3400static int hmR0VmxSetupLbrMsrRange(PVMCC pVM)
3401{
3402 Assert(pVM->hmr0.s.vmx.fLbr);
3403 uint32_t idLbrFromIpMsrFirst;
3404 uint32_t idLbrFromIpMsrLast;
3405 uint32_t idLbrToIpMsrFirst;
3406 uint32_t idLbrToIpMsrLast;
3407 uint32_t idLbrTosMsr;
3408
3409 /*
3410 * Determine the LBR MSRs supported for this host CPU family and model.
3411 *
3412 * See Intel spec. 17.4.8 "LBR Stack".
3413 * See Intel "Model-Specific Registers" spec.
3414 */
3415 uint32_t const uFamilyModel = (pVM->cpum.ro.HostFeatures.uFamily << 8)
3416 | pVM->cpum.ro.HostFeatures.uModel;
3417 switch (uFamilyModel)
3418 {
3419 case 0x0f01: case 0x0f02:
3420 idLbrFromIpMsrFirst = MSR_P4_LASTBRANCH_0;
3421 idLbrFromIpMsrLast = MSR_P4_LASTBRANCH_3;
3422 idLbrToIpMsrFirst = 0x0;
3423 idLbrToIpMsrLast = 0x0;
3424 idLbrTosMsr = MSR_P4_LASTBRANCH_TOS;
3425 break;
3426
3427 case 0x065c: case 0x065f: case 0x064e: case 0x065e: case 0x068e:
3428 case 0x069e: case 0x0655: case 0x0666: case 0x067a: case 0x0667:
3429 case 0x066a: case 0x066c: case 0x067d: case 0x067e:
3430 idLbrFromIpMsrFirst = MSR_LASTBRANCH_0_FROM_IP;
3431 idLbrFromIpMsrLast = MSR_LASTBRANCH_31_FROM_IP;
3432 idLbrToIpMsrFirst = MSR_LASTBRANCH_0_TO_IP;
3433 idLbrToIpMsrLast = MSR_LASTBRANCH_31_TO_IP;
3434 idLbrTosMsr = MSR_LASTBRANCH_TOS;
3435 break;
3436
3437 case 0x063d: case 0x0647: case 0x064f: case 0x0656: case 0x063c:
3438 case 0x0645: case 0x0646: case 0x063f: case 0x062a: case 0x062d:
3439 case 0x063a: case 0x063e: case 0x061a: case 0x061e: case 0x061f:
3440 case 0x062e: case 0x0625: case 0x062c: case 0x062f:
3441 idLbrFromIpMsrFirst = MSR_LASTBRANCH_0_FROM_IP;
3442 idLbrFromIpMsrLast = MSR_LASTBRANCH_15_FROM_IP;
3443 idLbrToIpMsrFirst = MSR_LASTBRANCH_0_TO_IP;
3444 idLbrToIpMsrLast = MSR_LASTBRANCH_15_TO_IP;
3445 idLbrTosMsr = MSR_LASTBRANCH_TOS;
3446 break;
3447
3448 case 0x0617: case 0x061d: case 0x060f:
3449 idLbrFromIpMsrFirst = MSR_CORE2_LASTBRANCH_0_FROM_IP;
3450 idLbrFromIpMsrLast = MSR_CORE2_LASTBRANCH_3_FROM_IP;
3451 idLbrToIpMsrFirst = MSR_CORE2_LASTBRANCH_0_TO_IP;
3452 idLbrToIpMsrLast = MSR_CORE2_LASTBRANCH_3_TO_IP;
3453 idLbrTosMsr = MSR_CORE2_LASTBRANCH_TOS;
3454 break;
3455
3456 /* Atom and related microarchitectures we don't care about:
3457 case 0x0637: case 0x064a: case 0x064c: case 0x064d: case 0x065a:
3458 case 0x065d: case 0x061c: case 0x0626: case 0x0627: case 0x0635:
3459 case 0x0636: */
3460 /* All other CPUs: */
3461 default:
3462 {
3463 LogRelFunc(("Could not determine LBR stack size for the CPU model %#x\n", uFamilyModel));
3464 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_LBR_STACK_SIZE_UNKNOWN;
3465 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3466 }
3467 }
3468
3469 /*
3470 * Validate.
3471 */
3472 uint32_t const cLbrStack = idLbrFromIpMsrLast - idLbrFromIpMsrFirst + 1;
3473 PCVMCPU pVCpu0 = VMCC_GET_CPU_0(pVM);
3474 AssertCompile( RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrFromIpMsr)
3475 == RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrToIpMsr));
3476 if (cLbrStack > RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrFromIpMsr))
3477 {
3478 LogRelFunc(("LBR stack size of the CPU (%u) exceeds our buffer size\n", cLbrStack));
3479 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_LBR_STACK_SIZE_OVERFLOW;
3480 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3481 }
3482 NOREF(pVCpu0);
3483
3484 /*
3485 * Update the LBR info. to the VM struct. for use later.
3486 */
3487 pVM->hmr0.s.vmx.idLbrTosMsr = idLbrTosMsr;
3488
3489 pVM->hm.s.ForR3.vmx.idLbrFromIpMsrFirst = pVM->hmr0.s.vmx.idLbrFromIpMsrFirst = idLbrFromIpMsrFirst;
3490 pVM->hm.s.ForR3.vmx.idLbrFromIpMsrLast = pVM->hmr0.s.vmx.idLbrFromIpMsrLast = idLbrFromIpMsrLast;
3491
3492 pVM->hm.s.ForR3.vmx.idLbrToIpMsrFirst = pVM->hmr0.s.vmx.idLbrToIpMsrFirst = idLbrToIpMsrFirst;
3493 pVM->hm.s.ForR3.vmx.idLbrToIpMsrLast = pVM->hmr0.s.vmx.idLbrToIpMsrLast = idLbrToIpMsrLast;
3494 return VINF_SUCCESS;
3495}
3496
3497
3498#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3499/**
3500 * Sets up the shadow VMCS fields arrays.
3501 *
3502 * This function builds arrays of VMCS fields to sync the shadow VMCS later while
3503 * executing the guest.
3504 *
3505 * @returns VBox status code.
3506 * @param pVM The cross context VM structure.
3507 */
3508static int hmR0VmxSetupShadowVmcsFieldsArrays(PVMCC pVM)
3509{
3510 /*
3511 * Paranoia. Ensure we haven't exposed the VMWRITE-All VMX feature to the guest
3512 * when the host does not support it.
3513 */
3514 bool const fGstVmwriteAll = pVM->cpum.ro.GuestFeatures.fVmxVmwriteAll;
3515 if ( !fGstVmwriteAll
3516 || (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL))
3517 { /* likely. */ }
3518 else
3519 {
3520 LogRelFunc(("VMX VMWRITE-All feature exposed to the guest but host CPU does not support it!\n"));
3521 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_GST_HOST_VMWRITE_ALL;
3522 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3523 }
3524
3525 uint32_t const cVmcsFields = RT_ELEMENTS(g_aVmcsFields);
3526 uint32_t cRwFields = 0;
3527 uint32_t cRoFields = 0;
3528 for (uint32_t i = 0; i < cVmcsFields; i++)
3529 {
3530 VMXVMCSFIELD VmcsField;
3531 VmcsField.u = g_aVmcsFields[i];
3532
3533 /*
3534 * We will be writing "FULL" (64-bit) fields while syncing the shadow VMCS.
3535 * Therefore, "HIGH" (32-bit portion of 64-bit) fields must not be included
3536 * in the shadow VMCS fields array as they would be redundant.
3537 *
3538 * If the VMCS field depends on a CPU feature that is not exposed to the guest,
3539 * we must not include it in the shadow VMCS fields array. Guests attempting to
3540 * VMREAD/VMWRITE such VMCS fields would cause a VM-exit and we shall emulate
3541 * the required behavior.
3542 */
3543 if ( VmcsField.n.fAccessType == VMX_VMCSFIELD_ACCESS_FULL
3544 && CPUMIsGuestVmxVmcsFieldValid(pVM, VmcsField.u))
3545 {
3546 /*
3547 * Read-only fields are placed in a separate array so that while syncing shadow
3548 * VMCS fields later (which is more performance critical) we can avoid branches.
3549 *
3550 * However, if the guest can write to all fields (including read-only fields),
3551 * we treat it a as read/write field. Otherwise, writing to these fields would
3552 * cause a VMWRITE instruction error while syncing the shadow VMCS.
3553 */
3554 if ( fGstVmwriteAll
3555 || !VMXIsVmcsFieldReadOnly(VmcsField.u))
3556 pVM->hmr0.s.vmx.paShadowVmcsFields[cRwFields++] = VmcsField.u;
3557 else
3558 pVM->hmr0.s.vmx.paShadowVmcsRoFields[cRoFields++] = VmcsField.u;
3559 }
3560 }
3561
3562 /* Update the counts. */
3563 pVM->hmr0.s.vmx.cShadowVmcsFields = cRwFields;
3564 pVM->hmr0.s.vmx.cShadowVmcsRoFields = cRoFields;
3565 return VINF_SUCCESS;
3566}
3567
3568
3569/**
3570 * Sets up the VMREAD and VMWRITE bitmaps.
3571 *
3572 * @param pVM The cross context VM structure.
3573 */
3574static void hmR0VmxSetupVmreadVmwriteBitmaps(PVMCC pVM)
3575{
3576 /*
3577 * By default, ensure guest attempts to access any VMCS fields cause VM-exits.
3578 */
3579 uint32_t const cbBitmap = X86_PAGE_4K_SIZE;
3580 uint8_t *pbVmreadBitmap = (uint8_t *)pVM->hmr0.s.vmx.pvVmreadBitmap;
3581 uint8_t *pbVmwriteBitmap = (uint8_t *)pVM->hmr0.s.vmx.pvVmwriteBitmap;
3582 ASMMemFill32(pbVmreadBitmap, cbBitmap, UINT32_C(0xffffffff));
3583 ASMMemFill32(pbVmwriteBitmap, cbBitmap, UINT32_C(0xffffffff));
3584
3585 /*
3586 * Skip intercepting VMREAD/VMWRITE to guest read/write fields in the
3587 * VMREAD and VMWRITE bitmaps.
3588 */
3589 {
3590 uint32_t const *paShadowVmcsFields = pVM->hmr0.s.vmx.paShadowVmcsFields;
3591 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
3592 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
3593 {
3594 uint32_t const uVmcsField = paShadowVmcsFields[i];
3595 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3596 Assert(uVmcsField >> 3 < cbBitmap);
3597 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3598 ASMBitClear(pbVmwriteBitmap + (uVmcsField >> 3), uVmcsField & 7);
3599 }
3600 }
3601
3602 /*
3603 * Skip intercepting VMREAD for guest read-only fields in the VMREAD bitmap
3604 * if the host supports VMWRITE to all supported VMCS fields.
3605 */
3606 if (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL)
3607 {
3608 uint32_t const *paShadowVmcsRoFields = pVM->hmr0.s.vmx.paShadowVmcsRoFields;
3609 uint32_t const cShadowVmcsRoFields = pVM->hmr0.s.vmx.cShadowVmcsRoFields;
3610 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
3611 {
3612 uint32_t const uVmcsField = paShadowVmcsRoFields[i];
3613 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3614 Assert(uVmcsField >> 3 < cbBitmap);
3615 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3616 }
3617 }
3618}
3619#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
3620
3621
3622/**
3623 * Sets up the virtual-APIC page address for the VMCS.
3624 *
3625 * @param pVmcsInfo The VMCS info. object.
3626 */
3627DECLINLINE(void) hmR0VmxSetupVmcsVirtApicAddr(PCVMXVMCSINFO pVmcsInfo)
3628{
3629 RTHCPHYS const HCPhysVirtApic = pVmcsInfo->HCPhysVirtApic;
3630 Assert(HCPhysVirtApic != NIL_RTHCPHYS);
3631 Assert(!(HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
3632 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
3633 AssertRC(rc);
3634}
3635
3636
3637/**
3638 * Sets up the MSR-bitmap address for the VMCS.
3639 *
3640 * @param pVmcsInfo The VMCS info. object.
3641 */
3642DECLINLINE(void) hmR0VmxSetupVmcsMsrBitmapAddr(PCVMXVMCSINFO pVmcsInfo)
3643{
3644 RTHCPHYS const HCPhysMsrBitmap = pVmcsInfo->HCPhysMsrBitmap;
3645 Assert(HCPhysMsrBitmap != NIL_RTHCPHYS);
3646 Assert(!(HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3647 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, HCPhysMsrBitmap);
3648 AssertRC(rc);
3649}
3650
3651
3652/**
3653 * Sets up the APIC-access page address for the VMCS.
3654 *
3655 * @param pVCpu The cross context virtual CPU structure.
3656 */
3657DECLINLINE(void) hmR0VmxSetupVmcsApicAccessAddr(PVMCPUCC pVCpu)
3658{
3659 RTHCPHYS const HCPhysApicAccess = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysApicAccess;
3660 Assert(HCPhysApicAccess != NIL_RTHCPHYS);
3661 Assert(!(HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
3662 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
3663 AssertRC(rc);
3664}
3665
3666#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3667
3668/**
3669 * Sets up the VMREAD bitmap address for the VMCS.
3670 *
3671 * @param pVCpu The cross context virtual CPU structure.
3672 */
3673DECLINLINE(void) hmR0VmxSetupVmcsVmreadBitmapAddr(PVMCPUCC pVCpu)
3674{
3675 RTHCPHYS const HCPhysVmreadBitmap = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysVmreadBitmap;
3676 Assert(HCPhysVmreadBitmap != NIL_RTHCPHYS);
3677 Assert(!(HCPhysVmreadBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3678 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL, HCPhysVmreadBitmap);
3679 AssertRC(rc);
3680}
3681
3682
3683/**
3684 * Sets up the VMWRITE bitmap address for the VMCS.
3685 *
3686 * @param pVCpu The cross context virtual CPU structure.
3687 */
3688DECLINLINE(void) hmR0VmxSetupVmcsVmwriteBitmapAddr(PVMCPUCC pVCpu)
3689{
3690 RTHCPHYS const HCPhysVmwriteBitmap = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysVmwriteBitmap;
3691 Assert(HCPhysVmwriteBitmap != NIL_RTHCPHYS);
3692 Assert(!(HCPhysVmwriteBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3693 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL, HCPhysVmwriteBitmap);
3694 AssertRC(rc);
3695}
3696
3697#endif
3698
3699/**
3700 * Sets up the VM-entry MSR load, VM-exit MSR-store and VM-exit MSR-load addresses
3701 * in the VMCS.
3702 *
3703 * @returns VBox status code.
3704 * @param pVmcsInfo The VMCS info. object.
3705 */
3706DECLINLINE(int) hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(PVMXVMCSINFO pVmcsInfo)
3707{
3708 RTHCPHYS const HCPhysGuestMsrLoad = pVmcsInfo->HCPhysGuestMsrLoad;
3709 Assert(HCPhysGuestMsrLoad != NIL_RTHCPHYS);
3710 Assert(!(HCPhysGuestMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3711
3712 RTHCPHYS const HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrStore;
3713 Assert(HCPhysGuestMsrStore != NIL_RTHCPHYS);
3714 Assert(!(HCPhysGuestMsrStore & 0xf)); /* Bits 3:0 MBZ. */
3715
3716 RTHCPHYS const HCPhysHostMsrLoad = pVmcsInfo->HCPhysHostMsrLoad;
3717 Assert(HCPhysHostMsrLoad != NIL_RTHCPHYS);
3718 Assert(!(HCPhysHostMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3719
3720 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, HCPhysGuestMsrLoad); AssertRC(rc);
3721 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, HCPhysGuestMsrStore); AssertRC(rc);
3722 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, HCPhysHostMsrLoad); AssertRC(rc);
3723 return VINF_SUCCESS;
3724}
3725
3726
3727/**
3728 * Sets up MSR permissions in the MSR bitmap of a VMCS info. object.
3729 *
3730 * @param pVCpu The cross context virtual CPU structure.
3731 * @param pVmcsInfo The VMCS info. object.
3732 */
3733static void hmR0VmxSetupVmcsMsrPermissions(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3734{
3735 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS);
3736
3737 /*
3738 * By default, ensure guest attempts to access any MSR cause VM-exits.
3739 * This shall later be relaxed for specific MSRs as necessary.
3740 *
3741 * Note: For nested-guests, the entire bitmap will be merged prior to
3742 * executing the nested-guest using hardware-assisted VMX and hence there
3743 * is no need to perform this operation. See hmR0VmxMergeMsrBitmapNested.
3744 */
3745 Assert(pVmcsInfo->pvMsrBitmap);
3746 ASMMemFill32(pVmcsInfo->pvMsrBitmap, X86_PAGE_4K_SIZE, UINT32_C(0xffffffff));
3747
3748 /*
3749 * The guest can access the following MSRs (read, write) without causing
3750 * VM-exits; they are loaded/stored automatically using fields in the VMCS.
3751 */
3752 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3753 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_CS, VMXMSRPM_ALLOW_RD_WR);
3754 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_ESP, VMXMSRPM_ALLOW_RD_WR);
3755 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_EIP, VMXMSRPM_ALLOW_RD_WR);
3756 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3757 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_FS_BASE, VMXMSRPM_ALLOW_RD_WR);
3758
3759 /*
3760 * The IA32_PRED_CMD and IA32_FLUSH_CMD MSRs are write-only and has no state
3761 * associated with then. We never need to intercept access (writes need to be
3762 * executed without causing a VM-exit, reads will #GP fault anyway).
3763 *
3764 * The IA32_SPEC_CTRL MSR is read/write and has state. We allow the guest to
3765 * read/write them. We swap the guest/host MSR value using the
3766 * auto-load/store MSR area.
3767 */
3768 if (pVM->cpum.ro.GuestFeatures.fIbpb)
3769 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_PRED_CMD, VMXMSRPM_ALLOW_RD_WR);
3770 if (pVM->cpum.ro.GuestFeatures.fFlushCmd)
3771 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_FLUSH_CMD, VMXMSRPM_ALLOW_RD_WR);
3772 if (pVM->cpum.ro.GuestFeatures.fIbrs)
3773 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SPEC_CTRL, VMXMSRPM_ALLOW_RD_WR);
3774
3775 /*
3776 * Allow full read/write access for the following MSRs (mandatory for VT-x)
3777 * required for 64-bit guests.
3778 */
3779 if (pVM->hmr0.s.fAllow64BitGuests)
3780 {
3781 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_LSTAR, VMXMSRPM_ALLOW_RD_WR);
3782 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K6_STAR, VMXMSRPM_ALLOW_RD_WR);
3783 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_SF_MASK, VMXMSRPM_ALLOW_RD_WR);
3784 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_KERNEL_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3785 }
3786
3787 /*
3788 * IA32_EFER MSR is always intercepted, see @bugref{9180#c37}.
3789 */
3790#ifdef VBOX_STRICT
3791 Assert(pVmcsInfo->pvMsrBitmap);
3792 uint32_t const fMsrpmEfer = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, MSR_K6_EFER);
3793 Assert(fMsrpmEfer == VMXMSRPM_EXIT_RD_WR);
3794#endif
3795}
3796
3797
3798/**
3799 * Sets up pin-based VM-execution controls in the VMCS.
3800 *
3801 * @returns VBox status code.
3802 * @param pVCpu The cross context virtual CPU structure.
3803 * @param pVmcsInfo The VMCS info. object.
3804 */
3805static int hmR0VmxSetupVmcsPinCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3806{
3807 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3808 uint32_t fVal = g_HmMsrs.u.vmx.PinCtls.n.allowed0; /* Bits set here must always be set. */
3809 uint32_t const fZap = g_HmMsrs.u.vmx.PinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
3810
3811 fVal |= VMX_PIN_CTLS_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
3812 | VMX_PIN_CTLS_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
3813
3814 if (g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_VIRT_NMI)
3815 fVal |= VMX_PIN_CTLS_VIRT_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
3816
3817 /* Enable the VMX-preemption timer. */
3818 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
3819 {
3820 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_PREEMPT_TIMER);
3821 fVal |= VMX_PIN_CTLS_PREEMPT_TIMER;
3822 }
3823
3824#if 0
3825 /* Enable posted-interrupt processing. */
3826 if (pVM->hm.s.fPostedIntrs)
3827 {
3828 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_POSTED_INT);
3829 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT);
3830 fVal |= VMX_PIN_CTLS_POSTED_INT;
3831 }
3832#endif
3833
3834 if ((fVal & fZap) != fVal)
3835 {
3836 LogRelFunc(("Invalid pin-based VM-execution controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3837 g_HmMsrs.u.vmx.PinCtls.n.allowed0, fVal, fZap));
3838 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
3839 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3840 }
3841
3842 /* Commit it to the VMCS and update our cache. */
3843 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, fVal);
3844 AssertRC(rc);
3845 pVmcsInfo->u32PinCtls = fVal;
3846
3847 return VINF_SUCCESS;
3848}
3849
3850
3851/**
3852 * Sets up secondary processor-based VM-execution controls in the VMCS.
3853 *
3854 * @returns VBox status code.
3855 * @param pVCpu The cross context virtual CPU structure.
3856 * @param pVmcsInfo The VMCS info. object.
3857 */
3858static int hmR0VmxSetupVmcsProcCtls2(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3859{
3860 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3861 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls2.n.allowed0; /* Bits set here must be set in the VMCS. */
3862 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3863
3864 /* WBINVD causes a VM-exit. */
3865 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_WBINVD_EXIT)
3866 fVal |= VMX_PROC_CTLS2_WBINVD_EXIT;
3867
3868 /* Enable EPT (aka nested-paging). */
3869 if (pVM->hmr0.s.fNestedPaging)
3870 fVal |= VMX_PROC_CTLS2_EPT;
3871
3872 /* Enable the INVPCID instruction if we expose it to the guest and is supported
3873 by the hardware. Without this, guest executing INVPCID would cause a #UD. */
3874 if ( pVM->cpum.ro.GuestFeatures.fInvpcid
3875 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_INVPCID))
3876 fVal |= VMX_PROC_CTLS2_INVPCID;
3877
3878 /* Enable VPID. */
3879 if (pVM->hmr0.s.vmx.fVpid)
3880 fVal |= VMX_PROC_CTLS2_VPID;
3881
3882 /* Enable unrestricted guest execution. */
3883 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
3884 fVal |= VMX_PROC_CTLS2_UNRESTRICTED_GUEST;
3885
3886#if 0
3887 if (pVM->hm.s.fVirtApicRegs)
3888 {
3889 /* Enable APIC-register virtualization. */
3890 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT);
3891 fVal |= VMX_PROC_CTLS2_APIC_REG_VIRT;
3892
3893 /* Enable virtual-interrupt delivery. */
3894 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY);
3895 fVal |= VMX_PROC_CTLS2_VIRT_INTR_DELIVERY;
3896 }
3897#endif
3898
3899 /* Virtualize-APIC accesses if supported by the CPU. The virtual-APIC page is
3900 where the TPR shadow resides. */
3901 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
3902 * done dynamically. */
3903 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
3904 {
3905 fVal |= VMX_PROC_CTLS2_VIRT_APIC_ACCESS;
3906 hmR0VmxSetupVmcsApicAccessAddr(pVCpu);
3907 }
3908
3909 /* Enable the RDTSCP instruction if we expose it to the guest and is supported
3910 by the hardware. Without this, guest executing RDTSCP would cause a #UD. */
3911 if ( pVM->cpum.ro.GuestFeatures.fRdTscP
3912 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_RDTSCP))
3913 fVal |= VMX_PROC_CTLS2_RDTSCP;
3914
3915 /* Enable Pause-Loop exiting. */
3916 if ( (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
3917 && pVM->hm.s.vmx.cPleGapTicks
3918 && pVM->hm.s.vmx.cPleWindowTicks)
3919 {
3920 fVal |= VMX_PROC_CTLS2_PAUSE_LOOP_EXIT;
3921
3922 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks); AssertRC(rc);
3923 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks); AssertRC(rc);
3924 }
3925
3926 if ((fVal & fZap) != fVal)
3927 {
3928 LogRelFunc(("Invalid secondary processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3929 g_HmMsrs.u.vmx.ProcCtls2.n.allowed0, fVal, fZap));
3930 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
3931 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3932 }
3933
3934 /* Commit it to the VMCS and update our cache. */
3935 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, fVal);
3936 AssertRC(rc);
3937 pVmcsInfo->u32ProcCtls2 = fVal;
3938
3939 return VINF_SUCCESS;
3940}
3941
3942
3943/**
3944 * Sets up processor-based VM-execution controls in the VMCS.
3945 *
3946 * @returns VBox status code.
3947 * @param pVCpu The cross context virtual CPU structure.
3948 * @param pVmcsInfo The VMCS info. object.
3949 */
3950static int hmR0VmxSetupVmcsProcCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3951{
3952 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3953 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
3954 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3955
3956 fVal |= VMX_PROC_CTLS_HLT_EXIT /* HLT causes a VM-exit. */
3957 | VMX_PROC_CTLS_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
3958 | VMX_PROC_CTLS_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
3959 | VMX_PROC_CTLS_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
3960 | VMX_PROC_CTLS_RDPMC_EXIT /* RDPMC causes a VM-exit. */
3961 | VMX_PROC_CTLS_MONITOR_EXIT /* MONITOR causes a VM-exit. */
3962 | VMX_PROC_CTLS_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
3963
3964 /* We toggle VMX_PROC_CTLS_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
3965 if ( !(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MOV_DR_EXIT)
3966 || (g_HmMsrs.u.vmx.ProcCtls.n.allowed0 & VMX_PROC_CTLS_MOV_DR_EXIT))
3967 {
3968 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
3969 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3970 }
3971
3972 /* Without nested paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
3973 if (!pVM->hmr0.s.fNestedPaging)
3974 {
3975 Assert(!pVM->hmr0.s.vmx.fUnrestrictedGuest);
3976 fVal |= VMX_PROC_CTLS_INVLPG_EXIT
3977 | VMX_PROC_CTLS_CR3_LOAD_EXIT
3978 | VMX_PROC_CTLS_CR3_STORE_EXIT;
3979 }
3980
3981 /* Use TPR shadowing if supported by the CPU. */
3982 if ( PDMHasApic(pVM)
3983 && (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
3984 {
3985 fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
3986 /* CR8 writes cause a VM-exit based on TPR threshold. */
3987 Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
3988 Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
3989 hmR0VmxSetupVmcsVirtApicAddr(pVmcsInfo);
3990 }
3991 else
3992 {
3993 /* Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is
3994 invalid on 32-bit Intel CPUs. Set this control only for 64-bit guests. */
3995 if (pVM->hmr0.s.fAllow64BitGuests)
3996 fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
3997 | VMX_PROC_CTLS_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
3998 }
3999
4000 /* Use MSR-bitmaps if supported by the CPU. */
4001 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4002 {
4003 fVal |= VMX_PROC_CTLS_USE_MSR_BITMAPS;
4004 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
4005 }
4006
4007 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
4008 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
4009 fVal |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
4010
4011 if ((fVal & fZap) != fVal)
4012 {
4013 LogRelFunc(("Invalid processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
4014 g_HmMsrs.u.vmx.ProcCtls.n.allowed0, fVal, fZap));
4015 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
4016 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4017 }
4018
4019 /* Commit it to the VMCS and update our cache. */
4020 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, fVal);
4021 AssertRC(rc);
4022 pVmcsInfo->u32ProcCtls = fVal;
4023
4024 /* Set up MSR permissions that don't change through the lifetime of the VM. */
4025 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4026 hmR0VmxSetupVmcsMsrPermissions(pVCpu, pVmcsInfo);
4027
4028 /* Set up secondary processor-based VM-execution controls if the CPU supports it. */
4029 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
4030 return hmR0VmxSetupVmcsProcCtls2(pVCpu, pVmcsInfo);
4031
4032 /* Sanity check, should not really happen. */
4033 if (RT_LIKELY(!pVM->hmr0.s.vmx.fUnrestrictedGuest))
4034 { /* likely */ }
4035 else
4036 {
4037 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
4038 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4039 }
4040
4041 /* Old CPUs without secondary processor-based VM-execution controls would end up here. */
4042 return VINF_SUCCESS;
4043}
4044
4045
4046/**
4047 * Sets up miscellaneous (everything other than Pin, Processor and secondary
4048 * Processor-based VM-execution) control fields in the VMCS.
4049 *
4050 * @returns VBox status code.
4051 * @param pVCpu The cross context virtual CPU structure.
4052 * @param pVmcsInfo The VMCS info. object.
4053 */
4054static int hmR0VmxSetupVmcsMiscCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4055{
4056#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4057 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUseVmcsShadowing)
4058 {
4059 hmR0VmxSetupVmcsVmreadBitmapAddr(pVCpu);
4060 hmR0VmxSetupVmcsVmwriteBitmapAddr(pVCpu);
4061 }
4062#endif
4063
4064 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
4065 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
4066 AssertRC(rc);
4067
4068 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
4069 if (RT_SUCCESS(rc))
4070 {
4071 uint64_t const u64Cr0Mask = hmR0VmxGetFixedCr0Mask(pVCpu);
4072 uint64_t const u64Cr4Mask = hmR0VmxGetFixedCr4Mask(pVCpu);
4073
4074 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask); AssertRC(rc);
4075 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask); AssertRC(rc);
4076
4077 pVmcsInfo->u64Cr0Mask = u64Cr0Mask;
4078 pVmcsInfo->u64Cr4Mask = u64Cr4Mask;
4079
4080 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fLbr)
4081 {
4082 rc = VMXWriteVmcsNw(VMX_VMCS64_GUEST_DEBUGCTL_FULL, MSR_IA32_DEBUGCTL_LBR);
4083 AssertRC(rc);
4084 }
4085 return VINF_SUCCESS;
4086 }
4087 else
4088 LogRelFunc(("Failed to initialize VMCS auto-load/store MSR addresses. rc=%Rrc\n", rc));
4089 return rc;
4090}
4091
4092
4093/**
4094 * Sets up the initial exception bitmap in the VMCS based on static conditions.
4095 *
4096 * We shall setup those exception intercepts that don't change during the
4097 * lifetime of the VM here. The rest are done dynamically while loading the
4098 * guest state.
4099 *
4100 * @param pVCpu The cross context virtual CPU structure.
4101 * @param pVmcsInfo The VMCS info. object.
4102 */
4103static void hmR0VmxSetupVmcsXcptBitmap(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4104{
4105 /*
4106 * The following exceptions are always intercepted:
4107 *
4108 * #AC - To prevent the guest from hanging the CPU.
4109 * #DB - To maintain the DR6 state even when intercepting DRx reads/writes and
4110 * recursive #DBs can cause a CPU hang.
4111 * #PF - To sync our shadow page tables when nested-paging is not used.
4112 */
4113 bool const fNestedPaging = pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging;
4114 uint32_t const uXcptBitmap = RT_BIT(X86_XCPT_AC)
4115 | RT_BIT(X86_XCPT_DB)
4116 | (fNestedPaging ? 0 : RT_BIT(X86_XCPT_PF));
4117
4118 /* Commit it to the VMCS. */
4119 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
4120 AssertRC(rc);
4121
4122 /* Update our cache of the exception bitmap. */
4123 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
4124}
4125
4126
4127#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4128/**
4129 * Sets up the VMCS for executing a nested-guest using hardware-assisted VMX.
4130 *
4131 * @returns VBox status code.
4132 * @param pVmcsInfo The VMCS info. object.
4133 */
4134static int hmR0VmxSetupVmcsCtlsNested(PVMXVMCSINFO pVmcsInfo)
4135{
4136 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
4137 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
4138 AssertRC(rc);
4139
4140 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
4141 if (RT_SUCCESS(rc))
4142 {
4143 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4144 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
4145
4146 /* Paranoia - We've not yet initialized these, they shall be done while merging the VMCS. */
4147 Assert(!pVmcsInfo->u64Cr0Mask);
4148 Assert(!pVmcsInfo->u64Cr4Mask);
4149 return VINF_SUCCESS;
4150 }
4151 LogRelFunc(("Failed to set up the VMCS link pointer in the nested-guest VMCS. rc=%Rrc\n", rc));
4152 return rc;
4153}
4154#endif
4155
4156
4157/**
4158 * Sets pfnStartVm to the best suited variant.
4159 *
4160 * This must be called whenever anything changes relative to the hmR0VmXStartVm
4161 * variant selection:
4162 * - pVCpu->hm.s.fLoadSaveGuestXcr0
4163 * - HM_WSF_IBPB_ENTRY in pVCpu->hmr0.s.fWorldSwitcher
4164 * - HM_WSF_IBPB_EXIT in pVCpu->hmr0.s.fWorldSwitcher
4165 * - Perhaps: CPUMIsGuestFPUStateActive() (windows only)
4166 * - Perhaps: CPUMCTX.fXStateMask (windows only)
4167 *
4168 * We currently ASSUME that neither HM_WSF_IBPB_ENTRY nor HM_WSF_IBPB_EXIT
4169 * cannot be changed at runtime.
4170 */
4171static void hmR0VmxUpdateStartVmFunction(PVMCPUCC pVCpu)
4172{
4173 static const struct CLANGWORKAROUND { PFNHMVMXSTARTVM pfn; } s_aHmR0VmxStartVmFunctions[] =
4174 {
4175 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4176 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4177 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4178 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4179 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4180 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4181 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4182 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4183 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4184 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4185 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4186 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4187 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4188 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4189 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4190 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4191 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4192 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4193 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4194 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4195 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4196 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4197 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4198 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4199 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4200 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4201 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4202 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4203 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4204 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4205 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4206 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4207 };
4208 uintptr_t const idx = (pVCpu->hmr0.s.fLoadSaveGuestXcr0 ? 1 : 0)
4209 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_IBPB_ENTRY ? 2 : 0)
4210 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_L1D_ENTRY ? 4 : 0)
4211 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_MDS_ENTRY ? 8 : 0)
4212 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_IBPB_EXIT ? 16 : 0);
4213 PFNHMVMXSTARTVM const pfnStartVm = s_aHmR0VmxStartVmFunctions[idx].pfn;
4214 if (pVCpu->hmr0.s.vmx.pfnStartVm != pfnStartVm)
4215 pVCpu->hmr0.s.vmx.pfnStartVm = pfnStartVm;
4216}
4217
4218
4219/**
4220 * Selector FNHMSVMVMRUN implementation.
4221 */
4222static DECLCALLBACK(int) hmR0VmxStartVmSelector(PVMXVMCSINFO pVmcsInfo, PVMCPUCC pVCpu, bool fResume)
4223{
4224 hmR0VmxUpdateStartVmFunction(pVCpu);
4225 return pVCpu->hmr0.s.vmx.pfnStartVm(pVmcsInfo, pVCpu, fResume);
4226}
4227
4228
4229/**
4230 * Sets up the VMCS for executing a guest (or nested-guest) using hardware-assisted
4231 * VMX.
4232 *
4233 * @returns VBox status code.
4234 * @param pVCpu The cross context virtual CPU structure.
4235 * @param pVmcsInfo The VMCS info. object.
4236 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
4237 */
4238static int hmR0VmxSetupVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
4239{
4240 Assert(pVmcsInfo->pvVmcs);
4241 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4242
4243 /* Set the CPU specified revision identifier at the beginning of the VMCS structure. */
4244 *(uint32_t *)pVmcsInfo->pvVmcs = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
4245 const char * const pszVmcs = fIsNstGstVmcs ? "nested-guest VMCS" : "guest VMCS";
4246
4247 LogFlowFunc(("\n"));
4248
4249 /*
4250 * Initialize the VMCS using VMCLEAR before loading the VMCS.
4251 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
4252 */
4253 int rc = hmR0VmxClearVmcs(pVmcsInfo);
4254 if (RT_SUCCESS(rc))
4255 {
4256 rc = hmR0VmxLoadVmcs(pVmcsInfo);
4257 if (RT_SUCCESS(rc))
4258 {
4259 /*
4260 * Initialize the hardware-assisted VMX execution handler for guest and nested-guest VMCS.
4261 * The host is always 64-bit since we no longer support 32-bit hosts.
4262 * Currently we have just a single handler for all guest modes as well, see @bugref{6208#c73}.
4263 */
4264 if (!fIsNstGstVmcs)
4265 {
4266 rc = hmR0VmxSetupVmcsPinCtls(pVCpu, pVmcsInfo);
4267 if (RT_SUCCESS(rc))
4268 {
4269 rc = hmR0VmxSetupVmcsProcCtls(pVCpu, pVmcsInfo);
4270 if (RT_SUCCESS(rc))
4271 {
4272 rc = hmR0VmxSetupVmcsMiscCtls(pVCpu, pVmcsInfo);
4273 if (RT_SUCCESS(rc))
4274 {
4275 hmR0VmxSetupVmcsXcptBitmap(pVCpu, pVmcsInfo);
4276#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4277 /*
4278 * If a shadow VMCS is allocated for the VMCS info. object, initialize the
4279 * VMCS revision ID and shadow VMCS indicator bit. Also, clear the VMCS
4280 * making it fit for use when VMCS shadowing is later enabled.
4281 */
4282 if (pVmcsInfo->pvShadowVmcs)
4283 {
4284 VMXVMCSREVID VmcsRevId;
4285 VmcsRevId.u = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
4286 VmcsRevId.n.fIsShadowVmcs = 1;
4287 *(uint32_t *)pVmcsInfo->pvShadowVmcs = VmcsRevId.u;
4288 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
4289 if (RT_SUCCESS(rc))
4290 { /* likely */ }
4291 else
4292 LogRelFunc(("Failed to initialize shadow VMCS. rc=%Rrc\n", rc));
4293 }
4294#endif
4295 }
4296 else
4297 LogRelFunc(("Failed to setup miscellaneous controls. rc=%Rrc\n", rc));
4298 }
4299 else
4300 LogRelFunc(("Failed to setup processor-based VM-execution controls. rc=%Rrc\n", rc));
4301 }
4302 else
4303 LogRelFunc(("Failed to setup pin-based controls. rc=%Rrc\n", rc));
4304 }
4305 else
4306 {
4307#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4308 rc = hmR0VmxSetupVmcsCtlsNested(pVmcsInfo);
4309 if (RT_SUCCESS(rc))
4310 { /* likely */ }
4311 else
4312 LogRelFunc(("Failed to initialize nested-guest VMCS. rc=%Rrc\n", rc));
4313#else
4314 AssertFailed();
4315#endif
4316 }
4317 }
4318 else
4319 LogRelFunc(("Failed to load the %s. rc=%Rrc\n", rc, pszVmcs));
4320 }
4321 else
4322 LogRelFunc(("Failed to clear the %s. rc=%Rrc\n", rc, pszVmcs));
4323
4324 /* Sync any CPU internal VMCS data back into our VMCS in memory. */
4325 if (RT_SUCCESS(rc))
4326 {
4327 rc = hmR0VmxClearVmcs(pVmcsInfo);
4328 if (RT_SUCCESS(rc))
4329 { /* likely */ }
4330 else
4331 LogRelFunc(("Failed to clear the %s post setup. rc=%Rrc\n", rc, pszVmcs));
4332 }
4333
4334 /*
4335 * Update the last-error record both for failures and success, so we
4336 * can propagate the status code back to ring-3 for diagnostics.
4337 */
4338 hmR0VmxUpdateErrorRecord(pVCpu, rc);
4339 NOREF(pszVmcs);
4340 return rc;
4341}
4342
4343
4344/**
4345 * Does global VT-x initialization (called during module initialization).
4346 *
4347 * @returns VBox status code.
4348 */
4349VMMR0DECL(int) VMXR0GlobalInit(void)
4350{
4351#ifdef HMVMX_USE_FUNCTION_TABLE
4352 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_aVMExitHandlers));
4353# ifdef VBOX_STRICT
4354 for (unsigned i = 0; i < RT_ELEMENTS(g_aVMExitHandlers); i++)
4355 Assert(g_aVMExitHandlers[i].pfn);
4356# endif
4357#endif
4358 return VINF_SUCCESS;
4359}
4360
4361
4362/**
4363 * Does global VT-x termination (called during module termination).
4364 */
4365VMMR0DECL(void) VMXR0GlobalTerm()
4366{
4367 /* Nothing to do currently. */
4368}
4369
4370
4371/**
4372 * Sets up and activates VT-x on the current CPU.
4373 *
4374 * @returns VBox status code.
4375 * @param pHostCpu The HM physical-CPU structure.
4376 * @param pVM The cross context VM structure. Can be
4377 * NULL after a host resume operation.
4378 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
4379 * fEnabledByHost is @c true).
4380 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
4381 * @a fEnabledByHost is @c true).
4382 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
4383 * enable VT-x on the host.
4384 * @param pHwvirtMsrs Pointer to the hardware-virtualization MSRs.
4385 */
4386VMMR0DECL(int) VMXR0EnableCpu(PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
4387 PCSUPHWVIRTMSRS pHwvirtMsrs)
4388{
4389 AssertPtr(pHostCpu);
4390 AssertPtr(pHwvirtMsrs);
4391 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4392
4393 /* Enable VT-x if it's not already enabled by the host. */
4394 if (!fEnabledByHost)
4395 {
4396 int rc = hmR0VmxEnterRootMode(pHostCpu, pVM, HCPhysCpuPage, pvCpuPage);
4397 if (RT_FAILURE(rc))
4398 return rc;
4399 }
4400
4401 /*
4402 * Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been
4403 * using EPTPs) so we don't retain any stale guest-physical mappings which won't get
4404 * invalidated when flushing by VPID.
4405 */
4406 if (pHwvirtMsrs->u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
4407 {
4408 hmR0VmxFlushEpt(NULL /* pVCpu */, NULL /* pVmcsInfo */, VMXTLBFLUSHEPT_ALL_CONTEXTS);
4409 pHostCpu->fFlushAsidBeforeUse = false;
4410 }
4411 else
4412 pHostCpu->fFlushAsidBeforeUse = true;
4413
4414 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
4415 ++pHostCpu->cTlbFlushes;
4416
4417 return VINF_SUCCESS;
4418}
4419
4420
4421/**
4422 * Deactivates VT-x on the current CPU.
4423 *
4424 * @returns VBox status code.
4425 * @param pHostCpu The HM physical-CPU structure.
4426 * @param pvCpuPage Pointer to the VMXON region.
4427 * @param HCPhysCpuPage Physical address of the VMXON region.
4428 *
4429 * @remarks This function should never be called when SUPR0EnableVTx() or
4430 * similar was used to enable VT-x on the host.
4431 */
4432VMMR0DECL(int) VMXR0DisableCpu(PHMPHYSCPU pHostCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
4433{
4434 RT_NOREF2(pvCpuPage, HCPhysCpuPage);
4435
4436 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4437 return hmR0VmxLeaveRootMode(pHostCpu);
4438}
4439
4440
4441/**
4442 * Does per-VM VT-x initialization.
4443 *
4444 * @returns VBox status code.
4445 * @param pVM The cross context VM structure.
4446 */
4447VMMR0DECL(int) VMXR0InitVM(PVMCC pVM)
4448{
4449 AssertPtr(pVM);
4450 LogFlowFunc(("pVM=%p\n", pVM));
4451
4452 hmR0VmxStructsInit(pVM);
4453 int rc = hmR0VmxStructsAlloc(pVM);
4454 if (RT_FAILURE(rc))
4455 {
4456 LogRelFunc(("Failed to allocated VMX structures. rc=%Rrc\n", rc));
4457 return rc;
4458 }
4459
4460 /* Setup the crash dump page. */
4461#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4462 strcpy((char *)pVM->hmr0.s.vmx.pbScratch, "SCRATCH Magic");
4463 *(uint64_t *)(pVM->hmr0.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
4464#endif
4465 return VINF_SUCCESS;
4466}
4467
4468
4469/**
4470 * Does per-VM VT-x termination.
4471 *
4472 * @returns VBox status code.
4473 * @param pVM The cross context VM structure.
4474 */
4475VMMR0DECL(int) VMXR0TermVM(PVMCC pVM)
4476{
4477 AssertPtr(pVM);
4478 LogFlowFunc(("pVM=%p\n", pVM));
4479
4480#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4481 if (pVM->hmr0.s.vmx.pbScratch)
4482 RT_BZERO(pVM->hmr0.s.vmx.pbScratch, X86_PAGE_4K_SIZE);
4483#endif
4484 hmR0VmxStructsFree(pVM);
4485 return VINF_SUCCESS;
4486}
4487
4488
4489/**
4490 * Sets up the VM for execution using hardware-assisted VMX.
4491 * This function is only called once per-VM during initialization.
4492 *
4493 * @returns VBox status code.
4494 * @param pVM The cross context VM structure.
4495 */
4496VMMR0DECL(int) VMXR0SetupVM(PVMCC pVM)
4497{
4498 AssertPtr(pVM);
4499 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4500
4501 LogFlowFunc(("pVM=%p\n", pVM));
4502
4503 /*
4504 * At least verify if VMX is enabled, since we can't check if we're in VMX root mode or not
4505 * without causing a #GP.
4506 */
4507 RTCCUINTREG const uHostCr4 = ASMGetCR4();
4508 if (RT_LIKELY(uHostCr4 & X86_CR4_VMXE))
4509 { /* likely */ }
4510 else
4511 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
4512
4513 /*
4514 * Check that nested paging is supported if enabled and copy over the flag to the
4515 * ring-0 only structure.
4516 */
4517 bool const fNestedPaging = pVM->hm.s.fNestedPagingCfg;
4518 AssertReturn( !fNestedPaging
4519 || (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_EPT), /** @todo use a ring-0 copy of ProcCtls2.n.allowed1 */
4520 VERR_INCOMPATIBLE_CONFIG);
4521 pVM->hmr0.s.fNestedPaging = fNestedPaging;
4522 pVM->hmr0.s.fAllow64BitGuests = pVM->hm.s.fAllow64BitGuestsCfg;
4523
4524 /*
4525 * Without unrestricted guest execution, pRealModeTSS and pNonPagingModeEPTPageTable *must*
4526 * always be allocated. We no longer support the highly unlikely case of unrestricted guest
4527 * without pRealModeTSS, see hmR3InitFinalizeR0Intel().
4528 */
4529 bool const fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuestCfg;
4530 AssertReturn( !fUnrestrictedGuest
4531 || ( (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST)
4532 && fNestedPaging),
4533 VERR_INCOMPATIBLE_CONFIG);
4534 if ( !fUnrestrictedGuest
4535 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
4536 || !pVM->hm.s.vmx.pRealModeTSS))
4537 {
4538 LogRelFunc(("Invalid real-on-v86 state.\n"));
4539 return VERR_INTERNAL_ERROR;
4540 }
4541 pVM->hmr0.s.vmx.fUnrestrictedGuest = fUnrestrictedGuest;
4542
4543 /* Initialize these always, see hmR3InitFinalizeR0().*/
4544 pVM->hm.s.ForR3.vmx.enmTlbFlushEpt = pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NONE;
4545 pVM->hm.s.ForR3.vmx.enmTlbFlushVpid = pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NONE;
4546
4547 /* Setup the tagged-TLB flush handlers. */
4548 int rc = hmR0VmxSetupTaggedTlb(pVM);
4549 if (RT_FAILURE(rc))
4550 {
4551 LogRelFunc(("Failed to setup tagged TLB. rc=%Rrc\n", rc));
4552 return rc;
4553 }
4554
4555 /* Determine LBR capabilities. */
4556 pVM->hmr0.s.vmx.fLbr = pVM->hm.s.vmx.fLbrCfg;
4557 if (pVM->hmr0.s.vmx.fLbr)
4558 {
4559 rc = hmR0VmxSetupLbrMsrRange(pVM);
4560 if (RT_FAILURE(rc))
4561 {
4562 LogRelFunc(("Failed to setup LBR MSR range. rc=%Rrc\n", rc));
4563 return rc;
4564 }
4565 }
4566
4567#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4568 /* Setup the shadow VMCS fields array and VMREAD/VMWRITE bitmaps. */
4569 if (pVM->hmr0.s.vmx.fUseVmcsShadowing)
4570 {
4571 rc = hmR0VmxSetupShadowVmcsFieldsArrays(pVM);
4572 if (RT_SUCCESS(rc))
4573 hmR0VmxSetupVmreadVmwriteBitmaps(pVM);
4574 else
4575 {
4576 LogRelFunc(("Failed to setup shadow VMCS fields arrays. rc=%Rrc\n", rc));
4577 return rc;
4578 }
4579 }
4580#endif
4581
4582 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
4583 {
4584 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
4585 Log4Func(("pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
4586
4587 pVCpu->hmr0.s.vmx.pfnStartVm = hmR0VmxStartVmSelector;
4588
4589 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
4590 if (RT_SUCCESS(rc))
4591 {
4592#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4593 if (pVM->cpum.ro.GuestFeatures.fVmx)
4594 {
4595 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
4596 if (RT_SUCCESS(rc))
4597 { /* likely */ }
4598 else
4599 {
4600 LogRelFunc(("Nested-guest VMCS setup failed. rc=%Rrc\n", rc));
4601 return rc;
4602 }
4603 }
4604#endif
4605 }
4606 else
4607 {
4608 LogRelFunc(("VMCS setup failed. rc=%Rrc\n", rc));
4609 return rc;
4610 }
4611 }
4612
4613 return VINF_SUCCESS;
4614}
4615
4616
4617/**
4618 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
4619 * the VMCS.
4620 * @returns CR4 for passing along to hmR0VmxExportHostSegmentRegs.
4621 */
4622static uint64_t hmR0VmxExportHostControlRegs(void)
4623{
4624 int rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR0, ASMGetCR0()); AssertRC(rc);
4625 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR3, ASMGetCR3()); AssertRC(rc);
4626 uint64_t uHostCr4 = ASMGetCR4();
4627 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR4, uHostCr4); AssertRC(rc);
4628 return uHostCr4;
4629}
4630
4631
4632/**
4633 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
4634 * the host-state area in the VMCS.
4635 *
4636 * @returns VBox status code.
4637 * @param pVCpu The cross context virtual CPU structure.
4638 * @param uHostCr4 The host CR4 value.
4639 */
4640static int hmR0VmxExportHostSegmentRegs(PVMCPUCC pVCpu, uint64_t uHostCr4)
4641{
4642 /*
4643 * If we've executed guest code using hardware-assisted VMX, the host-state bits
4644 * will be messed up. We should -not- save the messed up state without restoring
4645 * the original host-state, see @bugref{7240}.
4646 *
4647 * This apparently can happen (most likely the FPU changes), deal with it rather than
4648 * asserting. Was observed booting Solaris 10u10 32-bit guest.
4649 */
4650 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
4651 {
4652 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hmr0.s.vmx.fRestoreHostFlags,
4653 pVCpu->idCpu));
4654 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
4655 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
4656 }
4657
4658 /*
4659 * Get all the host info.
4660 * ASSUME it is safe to use rdfsbase and friends if the CR4.FSGSBASE bit is set
4661 * without also checking the cpuid bit.
4662 */
4663 uint32_t fRestoreHostFlags;
4664#if RT_INLINE_ASM_EXTERNAL
4665 if (uHostCr4 & X86_CR4_FSGSBASE)
4666 {
4667 hmR0VmxExportHostSegmentRegsAsmHlp(&pVCpu->hmr0.s.vmx.RestoreHost, true /*fHaveFsGsBase*/);
4668 fRestoreHostFlags = VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE;
4669 }
4670 else
4671 {
4672 hmR0VmxExportHostSegmentRegsAsmHlp(&pVCpu->hmr0.s.vmx.RestoreHost, false /*fHaveFsGsBase*/);
4673 fRestoreHostFlags = 0;
4674 }
4675 RTSEL uSelES = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelES;
4676 RTSEL uSelDS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelDS;
4677 RTSEL uSelFS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelFS;
4678 RTSEL uSelGS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelGS;
4679#else
4680 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR = ASMGetTR();
4681 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS = ASMGetSS();
4682 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS = ASMGetCS();
4683 ASMGetGDTR((PRTGDTR)&pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr);
4684 ASMGetIDTR((PRTIDTR)&pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr);
4685 if (uHostCr4 & X86_CR4_FSGSBASE)
4686 {
4687 pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase = ASMGetFSBase();
4688 pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase = ASMGetGSBase();
4689 fRestoreHostFlags = VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE;
4690 }
4691 else
4692 {
4693 pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase = ASMRdMsr(MSR_K8_FS_BASE);
4694 pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase = ASMRdMsr(MSR_K8_GS_BASE);
4695 fRestoreHostFlags = 0;
4696 }
4697 RTSEL uSelES, uSelDS, uSelFS, uSelGS;
4698 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelDS = uSelDS = ASMGetDS();
4699 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelES = uSelES = ASMGetES();
4700 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelFS = uSelFS = ASMGetFS();
4701 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelGS = uSelGS = ASMGetGS();
4702#endif
4703
4704 /*
4705 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to
4706 * gain VM-entry and restore them before we get preempted.
4707 *
4708 * See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
4709 */
4710 RTSEL const uSelAll = uSelFS | uSelGS | uSelES | uSelDS;
4711 if (uSelAll & (X86_SEL_RPL | X86_SEL_LDT))
4712 {
4713 if (!(uSelAll & X86_SEL_LDT))
4714 {
4715#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_uVmcsVar) \
4716 do { \
4717 (a_uVmcsVar) = pVCpu->hmr0.s.vmx.RestoreHost.uHostSel##a_Seg; \
4718 if ((a_uVmcsVar) & X86_SEL_RPL) \
4719 { \
4720 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4721 (a_uVmcsVar) = 0; \
4722 } \
4723 } while (0)
4724 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4725 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4726 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4727 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4728#undef VMXLOCAL_ADJUST_HOST_SEG
4729 }
4730 else
4731 {
4732#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_uVmcsVar) \
4733 do { \
4734 (a_uVmcsVar) = pVCpu->hmr0.s.vmx.RestoreHost.uHostSel##a_Seg; \
4735 if ((a_uVmcsVar) & (X86_SEL_RPL | X86_SEL_LDT)) \
4736 { \
4737 if (!((a_uVmcsVar) & X86_SEL_LDT)) \
4738 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4739 else \
4740 { \
4741 uint32_t const fAttr = ASMGetSegAttr(a_uVmcsVar); \
4742 if ((fAttr & X86_DESC_P) && fAttr != UINT32_MAX) \
4743 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4744 } \
4745 (a_uVmcsVar) = 0; \
4746 } \
4747 } while (0)
4748 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4749 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4750 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4751 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4752#undef VMXLOCAL_ADJUST_HOST_SEG
4753 }
4754 }
4755
4756 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
4757 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);
4758 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);
4759 Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS & X86_SEL_RPL)); Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS & X86_SEL_LDT));
4760 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
4761 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
4762 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
4763 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
4764
4765 /*
4766 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps
4767 * them to the maximum limit (0xffff) on every VM-exit.
4768 */
4769 if (pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb != 0xffff)
4770 fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
4771
4772 /*
4773 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT" and
4774 * Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit
4775 * as 0xfff, VT-x bloating the limit to 0xffff shouldn't cause any different CPU behavior.
4776 * However, several hosts either insists on 0xfff being the limit (Windows Patch Guard) or
4777 * uses the limit for other purposes (darwin puts the CPU ID in there but botches sidt
4778 * alignment in at least one consumer). So, we're only allowing the IDTR.LIMIT to be left
4779 * at 0xffff on hosts where we are sure it won't cause trouble.
4780 */
4781#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
4782 if (pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.cb < 0x0fff)
4783#else
4784 if (pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.cb != 0xffff)
4785#endif
4786 fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
4787
4788 /*
4789 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI
4790 * and RPL bits is effectively what the CPU does for "scaling by 8". TI is always 0 and
4791 * RPL should be too in most cases.
4792 */
4793 RTSEL const uSelTR = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR;
4794 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb,
4795 ("TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb),
4796 VERR_VMX_INVALID_HOST_STATE);
4797
4798 PCX86DESCHC pDesc = (PCX86DESCHC)(pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.uAddr + (uSelTR & X86_SEL_MASK));
4799 uintptr_t const uTRBase = X86DESC64_BASE(pDesc);
4800
4801 /*
4802 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on
4803 * all VM-exits. The type is the same for 64-bit busy TSS[1]. The limit needs manual
4804 * restoration if the host has something else. Task switching is not supported in 64-bit
4805 * mode[2], but the limit still matters as IOPM is supported in 64-bit mode. Restoring the
4806 * limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
4807 *
4808 * [1] See Intel spec. 3.5 "System Descriptor Types".
4809 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
4810 */
4811 Assert(pDesc->System.u4Type == 11);
4812 if ( pDesc->System.u16LimitLow != 0x67
4813 || pDesc->System.u4LimitHigh)
4814 {
4815 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
4816
4817 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
4818 if (g_fHmHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
4819 fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
4820 if (g_fHmHostKernelFeatures & SUPKERNELFEATURES_GDT_NEED_WRITABLE)
4821 {
4822 /* The GDT is read-only but the writable GDT is available. */
4823 fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_NEED_WRITABLE;
4824 pVCpu->hmr0.s.vmx.RestoreHost.HostGdtrRw.cb = pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb;
4825 int rc = SUPR0GetCurrentGdtRw(&pVCpu->hmr0.s.vmx.RestoreHost.HostGdtrRw.uAddr);
4826 AssertRCReturn(rc, rc);
4827 }
4828 }
4829
4830 pVCpu->hmr0.s.vmx.fRestoreHostFlags = fRestoreHostFlags;
4831
4832 /*
4833 * Do all the VMCS updates in one block to assist nested virtualization.
4834 */
4835 int rc;
4836 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_CS_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS); AssertRC(rc);
4837 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_SS_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS); AssertRC(rc);
4838 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_DS_SEL, uSelDS); AssertRC(rc);
4839 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_ES_SEL, uSelES); AssertRC(rc);
4840 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_FS_SEL, uSelFS); AssertRC(rc);
4841 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_GS_SEL, uSelGS); AssertRC(rc);
4842 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_TR_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR); AssertRC(rc);
4843 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GDTR_BASE, pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.uAddr); AssertRC(rc);
4844 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_IDTR_BASE, pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.uAddr); AssertRC(rc);
4845 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_TR_BASE, uTRBase); AssertRC(rc);
4846 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_FS_BASE, pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase); AssertRC(rc);
4847 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GS_BASE, pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase); AssertRC(rc);
4848
4849 return VINF_SUCCESS;
4850}
4851
4852
4853/**
4854 * Exports certain host MSRs in the VM-exit MSR-load area and some in the
4855 * host-state area of the VMCS.
4856 *
4857 * These MSRs will be automatically restored on the host after every successful
4858 * VM-exit.
4859 *
4860 * @param pVCpu The cross context virtual CPU structure.
4861 *
4862 * @remarks No-long-jump zone!!!
4863 */
4864static void hmR0VmxExportHostMsrs(PVMCPUCC pVCpu)
4865{
4866 AssertPtr(pVCpu);
4867
4868 /*
4869 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
4870 * rather than swapping them on every VM-entry.
4871 */
4872 hmR0VmxLazySaveHostMsrs(pVCpu);
4873
4874 /*
4875 * Host Sysenter MSRs.
4876 */
4877 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS)); AssertRC(rc);
4878 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP)); AssertRC(rc);
4879 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP)); AssertRC(rc);
4880
4881 /*
4882 * Host EFER MSR.
4883 *
4884 * If the CPU supports the newer VMCS controls for managing EFER, use it. Otherwise it's
4885 * done as part of auto-load/store MSR area in the VMCS, see hmR0VmxExportGuestMsrs().
4886 */
4887 if (g_fHmVmxSupportsVmcsEfer)
4888 {
4889 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, g_uHmVmxHostMsrEfer);
4890 AssertRC(rc);
4891 }
4892
4893 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
4894 * hmR0VmxExportGuestEntryExitCtls(). */
4895}
4896
4897
4898/**
4899 * Figures out if we need to swap the EFER MSR which is particularly expensive.
4900 *
4901 * We check all relevant bits. For now, that's everything besides LMA/LME, as
4902 * these two bits are handled by VM-entry, see hmR0VMxExportGuestEntryExitCtls().
4903 *
4904 * @returns true if we need to load guest EFER, false otherwise.
4905 * @param pVCpu The cross context virtual CPU structure.
4906 * @param pVmxTransient The VMX-transient structure.
4907 *
4908 * @remarks Requires EFER, CR4.
4909 * @remarks No-long-jump zone!!!
4910 */
4911static bool hmR0VmxShouldSwapEferMsr(PCVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
4912{
4913#ifdef HMVMX_ALWAYS_SWAP_EFER
4914 RT_NOREF2(pVCpu, pVmxTransient);
4915 return true;
4916#else
4917 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4918 uint64_t const u64HostEfer = g_uHmVmxHostMsrEfer;
4919 uint64_t const u64GuestEfer = pCtx->msrEFER;
4920
4921# ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4922 /*
4923 * For nested-guests, we shall honor swapping the EFER MSR when requested by
4924 * the nested-guest.
4925 */
4926 if ( pVmxTransient->fIsNestedGuest
4927 && ( CPUMIsGuestVmxEntryCtlsSet(pCtx, VMX_ENTRY_CTLS_LOAD_EFER_MSR)
4928 || CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_SAVE_EFER_MSR)
4929 || CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_LOAD_EFER_MSR)))
4930 return true;
4931# else
4932 RT_NOREF(pVmxTransient);
4933#endif
4934
4935 /*
4936 * For 64-bit guests, if EFER.SCE bit differs, we need to swap the EFER MSR
4937 * to ensure that the guest's SYSCALL behaviour isn't broken, see @bugref{7386}.
4938 */
4939 if ( CPUMIsGuestInLongModeEx(pCtx)
4940 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
4941 return true;
4942
4943 /*
4944 * If the guest uses PAE and EFER.NXE bit differs, we need to swap the EFER MSR
4945 * as it affects guest paging. 64-bit paging implies CR4.PAE as well.
4946 *
4947 * See Intel spec. 4.5 "IA-32e Paging".
4948 * See Intel spec. 4.1.1 "Three Paging Modes".
4949 *
4950 * Verify that we always intercept CR4.PAE and CR0.PG bits, so we don't need to
4951 * import CR4 and CR0 from the VMCS here as those bits are always up to date.
4952 */
4953 Assert(hmR0VmxGetFixedCr4Mask(pVCpu) & X86_CR4_PAE);
4954 Assert(hmR0VmxGetFixedCr0Mask(pVCpu) & X86_CR0_PG);
4955 if ( (pCtx->cr4 & X86_CR4_PAE)
4956 && (pCtx->cr0 & X86_CR0_PG))
4957 {
4958 /*
4959 * If nested paging is not used, verify that the guest paging mode matches the
4960 * shadow paging mode which is/will be placed in the VMCS (which is what will
4961 * actually be used while executing the guest and not the CR4 shadow value).
4962 */
4963 AssertMsg( pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging
4964 || pVCpu->hm.s.enmShadowMode == PGMMODE_PAE
4965 || pVCpu->hm.s.enmShadowMode == PGMMODE_PAE_NX
4966 || pVCpu->hm.s.enmShadowMode == PGMMODE_AMD64
4967 || pVCpu->hm.s.enmShadowMode == PGMMODE_AMD64_NX,
4968 ("enmShadowMode=%u\n", pVCpu->hm.s.enmShadowMode));
4969 if ((u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
4970 {
4971 /* Verify that the host is NX capable. */
4972 Assert(pVCpu->CTX_SUFF(pVM)->cpum.ro.HostFeatures.fNoExecute);
4973 return true;
4974 }
4975 }
4976
4977 return false;
4978#endif
4979}
4980
4981
4982/**
4983 * Exports the guest state with appropriate VM-entry and VM-exit controls in the
4984 * VMCS.
4985 *
4986 * This is typically required when the guest changes paging mode.
4987 *
4988 * @returns VBox status code.
4989 * @param pVCpu The cross context virtual CPU structure.
4990 * @param pVmxTransient The VMX-transient structure.
4991 *
4992 * @remarks Requires EFER.
4993 * @remarks No-long-jump zone!!!
4994 */
4995static int hmR0VmxExportGuestEntryExitCtls(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
4996{
4997 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS)
4998 {
4999 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5000 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5001
5002 /*
5003 * VM-entry controls.
5004 */
5005 {
5006 uint32_t fVal = g_HmMsrs.u.vmx.EntryCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
5007 uint32_t const fZap = g_HmMsrs.u.vmx.EntryCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
5008
5009 /*
5010 * Load the guest debug controls (DR7 and IA32_DEBUGCTL MSR) on VM-entry.
5011 * The first VT-x capable CPUs only supported the 1-setting of this bit.
5012 *
5013 * For nested-guests, this is a mandatory VM-entry control. It's also
5014 * required because we do not want to leak host bits to the nested-guest.
5015 */
5016 fVal |= VMX_ENTRY_CTLS_LOAD_DEBUG;
5017
5018 /*
5019 * Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry.
5020 *
5021 * For nested-guests, the "IA-32e mode guest" control we initialize with what is
5022 * required to get the nested-guest working with hardware-assisted VMX execution.
5023 * It depends on the nested-guest's IA32_EFER.LMA bit. Remember, a nested hypervisor
5024 * can skip intercepting changes to the EFER MSR. This is why it needs to be done
5025 * here rather than while merging the guest VMCS controls.
5026 */
5027 if (CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
5028 {
5029 Assert(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LME);
5030 fVal |= VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
5031 }
5032 else
5033 Assert(!(fVal & VMX_ENTRY_CTLS_IA32E_MODE_GUEST));
5034
5035 /*
5036 * If the CPU supports the newer VMCS controls for managing guest/host EFER, use it.
5037 *
5038 * For nested-guests, we use the "load IA32_EFER" if the hardware supports it,
5039 * regardless of whether the nested-guest VMCS specifies it because we are free to
5040 * load whatever MSRs we require and we do not need to modify the guest visible copy
5041 * of the VM-entry MSR load area.
5042 */
5043 if ( g_fHmVmxSupportsVmcsEfer
5044 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
5045 fVal |= VMX_ENTRY_CTLS_LOAD_EFER_MSR;
5046 else
5047 Assert(!(fVal & VMX_ENTRY_CTLS_LOAD_EFER_MSR));
5048
5049 /*
5050 * The following should -not- be set (since we're not in SMM mode):
5051 * - VMX_ENTRY_CTLS_ENTRY_TO_SMM
5052 * - VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON
5053 */
5054
5055 /** @todo VMX_ENTRY_CTLS_LOAD_PERF_MSR,
5056 * VMX_ENTRY_CTLS_LOAD_PAT_MSR. */
5057
5058 if ((fVal & fZap) == fVal)
5059 { /* likely */ }
5060 else
5061 {
5062 Log4Func(("Invalid VM-entry controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
5063 g_HmMsrs.u.vmx.EntryCtls.n.allowed0, fVal, fZap));
5064 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
5065 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
5066 }
5067
5068 /* Commit it to the VMCS. */
5069 if (pVmcsInfo->u32EntryCtls != fVal)
5070 {
5071 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, fVal);
5072 AssertRC(rc);
5073 pVmcsInfo->u32EntryCtls = fVal;
5074 }
5075 }
5076
5077 /*
5078 * VM-exit controls.
5079 */
5080 {
5081 uint32_t fVal = g_HmMsrs.u.vmx.ExitCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
5082 uint32_t const fZap = g_HmMsrs.u.vmx.ExitCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
5083
5084 /*
5085 * Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only
5086 * supported the 1-setting of this bit.
5087 *
5088 * For nested-guests, we set the "save debug controls" as the converse
5089 * "load debug controls" is mandatory for nested-guests anyway.
5090 */
5091 fVal |= VMX_EXIT_CTLS_SAVE_DEBUG;
5092
5093 /*
5094 * Set the host long mode active (EFER.LMA) bit (which Intel calls
5095 * "Host address-space size") if necessary. On VM-exit, VT-x sets both the
5096 * host EFER.LMA and EFER.LME bit to this value. See assertion in
5097 * hmR0VmxExportHostMsrs().
5098 *
5099 * For nested-guests, we always set this bit as we do not support 32-bit
5100 * hosts.
5101 */
5102 fVal |= VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE;
5103
5104 /*
5105 * If the VMCS EFER MSR fields are supported by the hardware, we use it.
5106 *
5107 * For nested-guests, we should use the "save IA32_EFER" control if we also
5108 * used the "load IA32_EFER" control while exporting VM-entry controls.
5109 */
5110 if ( g_fHmVmxSupportsVmcsEfer
5111 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
5112 {
5113 fVal |= VMX_EXIT_CTLS_SAVE_EFER_MSR
5114 | VMX_EXIT_CTLS_LOAD_EFER_MSR;
5115 }
5116
5117 /*
5118 * Enable saving of the VMX-preemption timer value on VM-exit.
5119 * For nested-guests, currently not exposed/used.
5120 */
5121 /** @todo r=bird: Measure performance hit because of this vs. always rewriting
5122 * the timer value. */
5123 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
5124 {
5125 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER);
5126 fVal |= VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER;
5127 }
5128
5129 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
5130 Assert(!(fVal & VMX_EXIT_CTLS_ACK_EXT_INT));
5131
5132 /** @todo VMX_EXIT_CTLS_LOAD_PERF_MSR,
5133 * VMX_EXIT_CTLS_SAVE_PAT_MSR,
5134 * VMX_EXIT_CTLS_LOAD_PAT_MSR. */
5135
5136 if ((fVal & fZap) == fVal)
5137 { /* likely */ }
5138 else
5139 {
5140 Log4Func(("Invalid VM-exit controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%R#X32\n",
5141 g_HmMsrs.u.vmx.ExitCtls.n.allowed0, fVal, fZap));
5142 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
5143 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
5144 }
5145
5146 /* Commit it to the VMCS. */
5147 if (pVmcsInfo->u32ExitCtls != fVal)
5148 {
5149 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, fVal);
5150 AssertRC(rc);
5151 pVmcsInfo->u32ExitCtls = fVal;
5152 }
5153 }
5154
5155 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
5156 }
5157 return VINF_SUCCESS;
5158}
5159
5160
5161/**
5162 * Sets the TPR threshold in the VMCS.
5163 *
5164 * @param pVmcsInfo The VMCS info. object.
5165 * @param u32TprThreshold The TPR threshold (task-priority class only).
5166 */
5167DECLINLINE(void) hmR0VmxApicSetTprThreshold(PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
5168{
5169 Assert(!(u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)); /* Bits 31:4 MBZ. */
5170 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
5171 RT_NOREF(pVmcsInfo);
5172 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
5173 AssertRC(rc);
5174}
5175
5176
5177/**
5178 * Exports the guest APIC TPR state into the VMCS.
5179 *
5180 * @param pVCpu The cross context virtual CPU structure.
5181 * @param pVmxTransient The VMX-transient structure.
5182 *
5183 * @remarks No-long-jump zone!!!
5184 */
5185static void hmR0VmxExportGuestApicTpr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5186{
5187 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_APIC_TPR)
5188 {
5189 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
5190
5191 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5192 if (!pVmxTransient->fIsNestedGuest)
5193 {
5194 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
5195 && APICIsEnabled(pVCpu))
5196 {
5197 /*
5198 * Setup TPR shadowing.
5199 */
5200 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
5201 {
5202 bool fPendingIntr = false;
5203 uint8_t u8Tpr = 0;
5204 uint8_t u8PendingIntr = 0;
5205 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
5206 AssertRC(rc);
5207
5208 /*
5209 * If there are interrupts pending but masked by the TPR, instruct VT-x to
5210 * cause a TPR-below-threshold VM-exit when the guest lowers its TPR below the
5211 * priority of the pending interrupt so we can deliver the interrupt. If there
5212 * are no interrupts pending, set threshold to 0 to not cause any
5213 * TPR-below-threshold VM-exits.
5214 */
5215 uint32_t u32TprThreshold = 0;
5216 if (fPendingIntr)
5217 {
5218 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR
5219 (which is the Task-Priority Class). */
5220 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
5221 const uint8_t u8TprPriority = u8Tpr >> 4;
5222 if (u8PendingPriority <= u8TprPriority)
5223 u32TprThreshold = u8PendingPriority;
5224 }
5225
5226 hmR0VmxApicSetTprThreshold(pVmcsInfo, u32TprThreshold);
5227 }
5228 }
5229 }
5230 /* else: the TPR threshold has already been updated while merging the nested-guest VMCS. */
5231 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
5232 }
5233}
5234
5235
5236/**
5237 * Gets the guest interruptibility-state and updates related force-flags.
5238 *
5239 * @returns Guest's interruptibility-state.
5240 * @param pVCpu The cross context virtual CPU structure.
5241 *
5242 * @remarks No-long-jump zone!!!
5243 */
5244static uint32_t hmR0VmxGetGuestIntrStateAndUpdateFFs(PVMCPUCC pVCpu)
5245{
5246 /*
5247 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
5248 */
5249 uint32_t fIntrState = 0;
5250 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
5251 {
5252 /* If inhibition is active, RIP and RFLAGS should've been imported from the VMCS already. */
5253 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
5254
5255 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5256 if (pCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
5257 {
5258 if (pCtx->eflags.Bits.u1IF)
5259 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
5260 else
5261 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS;
5262 }
5263 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
5264 {
5265 /*
5266 * We can clear the inhibit force flag as even if we go back to the recompiler
5267 * without executing guest code in VT-x, the flag's condition to be cleared is
5268 * met and thus the cleared state is correct.
5269 */
5270 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
5271 }
5272 }
5273
5274 /*
5275 * Check if we should inhibit NMI delivery.
5276 */
5277 if (CPUMIsGuestNmiBlocking(pVCpu))
5278 fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
5279
5280 /*
5281 * Validate.
5282 */
5283#ifdef VBOX_STRICT
5284 /* We don't support block-by-SMI yet.*/
5285 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI));
5286
5287 /* Block-by-STI must not be set when interrupts are disabled. */
5288 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
5289 {
5290 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
5291 Assert(pVCpu->cpum.GstCtx.eflags.u & X86_EFL_IF);
5292 }
5293#endif
5294
5295 return fIntrState;
5296}
5297
5298
5299/**
5300 * Exports the exception intercepts required for guest execution in the VMCS.
5301 *
5302 * @param pVCpu The cross context virtual CPU structure.
5303 * @param pVmxTransient The VMX-transient structure.
5304 *
5305 * @remarks No-long-jump zone!!!
5306 */
5307static void hmR0VmxExportGuestXcptIntercepts(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5308{
5309 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_XCPT_INTERCEPTS)
5310 {
5311 /* When executing a nested-guest, we do not need to trap GIM hypercalls by intercepting #UD. */
5312 if ( !pVmxTransient->fIsNestedGuest
5313 && pVCpu->hm.s.fGIMTrapXcptUD)
5314 hmR0VmxAddXcptIntercept(pVmxTransient, X86_XCPT_UD);
5315 else
5316 hmR0VmxRemoveXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
5317
5318 /* Other exception intercepts are handled elsewhere, e.g. while exporting guest CR0. */
5319 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_XCPT_INTERCEPTS);
5320 }
5321}
5322
5323
5324/**
5325 * Exports the guest's RIP into the guest-state area in the VMCS.
5326 *
5327 * @param pVCpu The cross context virtual CPU structure.
5328 *
5329 * @remarks No-long-jump zone!!!
5330 */
5331static void hmR0VmxExportGuestRip(PVMCPUCC pVCpu)
5332{
5333 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RIP)
5334 {
5335 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
5336
5337 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RIP, pVCpu->cpum.GstCtx.rip);
5338 AssertRC(rc);
5339
5340 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RIP);
5341 Log4Func(("rip=%#RX64\n", pVCpu->cpum.GstCtx.rip));
5342 }
5343}
5344
5345
5346/**
5347 * Exports the guest's RSP into the guest-state area in the VMCS.
5348 *
5349 * @param pVCpu The cross context virtual CPU structure.
5350 *
5351 * @remarks No-long-jump zone!!!
5352 */
5353static void hmR0VmxExportGuestRsp(PVMCPUCC pVCpu)
5354{
5355 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RSP)
5356 {
5357 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RSP);
5358
5359 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RSP, pVCpu->cpum.GstCtx.rsp);
5360 AssertRC(rc);
5361
5362 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RSP);
5363 Log4Func(("rsp=%#RX64\n", pVCpu->cpum.GstCtx.rsp));
5364 }
5365}
5366
5367
5368/**
5369 * Exports the guest's RFLAGS into the guest-state area in the VMCS.
5370 *
5371 * @param pVCpu The cross context virtual CPU structure.
5372 * @param pVmxTransient The VMX-transient structure.
5373 *
5374 * @remarks No-long-jump zone!!!
5375 */
5376static void hmR0VmxExportGuestRflags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5377{
5378 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RFLAGS)
5379 {
5380 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
5381
5382 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
5383 Let us assert it as such and use 32-bit VMWRITE. */
5384 Assert(!RT_HI_U32(pVCpu->cpum.GstCtx.rflags.u64));
5385 X86EFLAGS fEFlags = pVCpu->cpum.GstCtx.eflags;
5386 Assert(fEFlags.u32 & X86_EFL_RA1_MASK);
5387 Assert(!(fEFlags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
5388
5389 /*
5390 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so
5391 * we can restore them on VM-exit. Modify the real-mode guest's eflags so that VT-x
5392 * can run the real-mode guest code under Virtual 8086 mode.
5393 */
5394 PVMXVMCSINFOSHARED pVmcsInfo = pVmxTransient->pVmcsInfo->pShared;
5395 if (pVmcsInfo->RealMode.fRealOnV86Active)
5396 {
5397 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
5398 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
5399 Assert(!pVmxTransient->fIsNestedGuest);
5400 pVmcsInfo->RealMode.Eflags.u32 = fEFlags.u32; /* Save the original eflags of the real-mode guest. */
5401 fEFlags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
5402 fEFlags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
5403 }
5404
5405 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RFLAGS, fEFlags.u32);
5406 AssertRC(rc);
5407
5408 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
5409 Log4Func(("eflags=%#RX32\n", fEFlags.u32));
5410 }
5411}
5412
5413
5414#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5415/**
5416 * Copies the nested-guest VMCS to the shadow VMCS.
5417 *
5418 * @returns VBox status code.
5419 * @param pVCpu The cross context virtual CPU structure.
5420 * @param pVmcsInfo The VMCS info. object.
5421 *
5422 * @remarks No-long-jump zone!!!
5423 */
5424static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5425{
5426 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5427 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5428
5429 /*
5430 * Disable interrupts so we don't get preempted while the shadow VMCS is the
5431 * current VMCS, as we may try saving guest lazy MSRs.
5432 *
5433 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
5434 * calling the import VMCS code which is currently performing the guest MSR reads
5435 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
5436 * and the rest of the VMX leave session machinery.
5437 */
5438 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
5439
5440 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5441 if (RT_SUCCESS(rc))
5442 {
5443 /*
5444 * Copy all guest read/write VMCS fields.
5445 *
5446 * We don't check for VMWRITE failures here for performance reasons and
5447 * because they are not expected to fail, barring irrecoverable conditions
5448 * like hardware errors.
5449 */
5450 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
5451 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5452 {
5453 uint64_t u64Val;
5454 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsFields[i];
5455 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5456 VMXWriteVmcs64(uVmcsField, u64Val);
5457 }
5458
5459 /*
5460 * If the host CPU supports writing all VMCS fields, copy the guest read-only
5461 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
5462 */
5463 if (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL)
5464 {
5465 uint32_t const cShadowVmcsRoFields = pVM->hmr0.s.vmx.cShadowVmcsRoFields;
5466 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
5467 {
5468 uint64_t u64Val;
5469 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsRoFields[i];
5470 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5471 VMXWriteVmcs64(uVmcsField, u64Val);
5472 }
5473 }
5474
5475 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5476 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5477 }
5478
5479 ASMSetFlags(fEFlags);
5480 return rc;
5481}
5482
5483
5484/**
5485 * Copies the shadow VMCS to the nested-guest VMCS.
5486 *
5487 * @returns VBox status code.
5488 * @param pVCpu The cross context virtual CPU structure.
5489 * @param pVmcsInfo The VMCS info. object.
5490 *
5491 * @remarks Called with interrupts disabled.
5492 */
5493static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5494{
5495 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5496 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5497 PVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
5498
5499 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5500 if (RT_SUCCESS(rc))
5501 {
5502 /*
5503 * Copy guest read/write fields from the shadow VMCS.
5504 * Guest read-only fields cannot be modified, so no need to copy them.
5505 *
5506 * We don't check for VMREAD failures here for performance reasons and
5507 * because they are not expected to fail, barring irrecoverable conditions
5508 * like hardware errors.
5509 */
5510 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
5511 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5512 {
5513 uint64_t u64Val;
5514 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsFields[i];
5515 VMXReadVmcs64(uVmcsField, &u64Val);
5516 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
5517 }
5518
5519 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5520 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5521 }
5522 return rc;
5523}
5524
5525
5526/**
5527 * Enables VMCS shadowing for the given VMCS info. object.
5528 *
5529 * @param pVmcsInfo The VMCS info. object.
5530 *
5531 * @remarks No-long-jump zone!!!
5532 */
5533static void hmR0VmxEnableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5534{
5535 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5536 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
5537 {
5538 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
5539 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
5540 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5541 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
5542 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5543 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
5544 Log4Func(("Enabled\n"));
5545 }
5546}
5547
5548
5549/**
5550 * Disables VMCS shadowing for the given VMCS info. object.
5551 *
5552 * @param pVmcsInfo The VMCS info. object.
5553 *
5554 * @remarks No-long-jump zone!!!
5555 */
5556static void hmR0VmxDisableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5557{
5558 /*
5559 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
5560 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
5561 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
5562 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
5563 *
5564 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
5565 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5566 */
5567 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5568 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
5569 {
5570 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
5571 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5572 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
5573 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5574 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
5575 Log4Func(("Disabled\n"));
5576 }
5577}
5578#endif
5579
5580
5581/**
5582 * Exports the guest hardware-virtualization state.
5583 *
5584 * @returns VBox status code.
5585 * @param pVCpu The cross context virtual CPU structure.
5586 * @param pVmxTransient The VMX-transient structure.
5587 *
5588 * @remarks No-long-jump zone!!!
5589 */
5590static int hmR0VmxExportGuestHwvirtState(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5591{
5592 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
5593 {
5594#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5595 /*
5596 * Check if the VMX feature is exposed to the guest and if the host CPU supports
5597 * VMCS shadowing.
5598 */
5599 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUseVmcsShadowing)
5600 {
5601 /*
5602 * If the nested hypervisor has loaded a current VMCS and is in VMX root mode,
5603 * copy the nested hypervisor's current VMCS into the shadow VMCS and enable
5604 * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
5605 *
5606 * We check for VMX root mode here in case the guest executes VMXOFF without
5607 * clearing the current VMCS pointer and our VMXOFF instruction emulation does
5608 * not clear the current VMCS pointer.
5609 */
5610 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5611 if ( CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
5612 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
5613 && CPUMIsGuestVmxCurrentVmcsValid(&pVCpu->cpum.GstCtx))
5614 {
5615 /* Paranoia. */
5616 Assert(!pVmxTransient->fIsNestedGuest);
5617
5618 /*
5619 * For performance reasons, also check if the nested hypervisor's current VMCS
5620 * was newly loaded or modified before copying it to the shadow VMCS.
5621 */
5622 if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
5623 {
5624 int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
5625 AssertRCReturn(rc, rc);
5626 pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
5627 }
5628 hmR0VmxEnableVmcsShadowing(pVmcsInfo);
5629 }
5630 else
5631 hmR0VmxDisableVmcsShadowing(pVmcsInfo);
5632 }
5633#else
5634 NOREF(pVmxTransient);
5635#endif
5636 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
5637 }
5638 return VINF_SUCCESS;
5639}
5640
5641
5642/**
5643 * Exports the guest CR0 control register into the guest-state area in the VMCS.
5644 *
5645 * The guest FPU state is always pre-loaded hence we don't need to bother about
5646 * sharing FPU related CR0 bits between the guest and host.
5647 *
5648 * @returns VBox status code.
5649 * @param pVCpu The cross context virtual CPU structure.
5650 * @param pVmxTransient The VMX-transient structure.
5651 *
5652 * @remarks No-long-jump zone!!!
5653 */
5654static int hmR0VmxExportGuestCR0(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5655{
5656 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR0)
5657 {
5658 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5659 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5660
5661 uint64_t fSetCr0 = g_HmMsrs.u.vmx.u64Cr0Fixed0;
5662 uint64_t const fZapCr0 = g_HmMsrs.u.vmx.u64Cr0Fixed1;
5663 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
5664 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5665 else
5666 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
5667
5668 if (!pVmxTransient->fIsNestedGuest)
5669 {
5670 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5671 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5672 uint64_t const u64ShadowCr0 = u64GuestCr0;
5673 Assert(!RT_HI_U32(u64GuestCr0));
5674
5675 /*
5676 * Setup VT-x's view of the guest CR0.
5677 */
5678 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5679 if (pVM->hmr0.s.fNestedPaging)
5680 {
5681 if (CPUMIsGuestPagingEnabled(pVCpu))
5682 {
5683 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
5684 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
5685 | VMX_PROC_CTLS_CR3_STORE_EXIT);
5686 }
5687 else
5688 {
5689 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
5690 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
5691 | VMX_PROC_CTLS_CR3_STORE_EXIT;
5692 }
5693
5694 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
5695 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
5696 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
5697 }
5698 else
5699 {
5700 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
5701 u64GuestCr0 |= X86_CR0_WP;
5702 }
5703
5704 /*
5705 * Guest FPU bits.
5706 *
5707 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
5708 * using CR0.TS.
5709 *
5710 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
5711 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
5712 */
5713 u64GuestCr0 |= X86_CR0_NE;
5714
5715 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
5716 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
5717
5718 /*
5719 * Update exception intercepts.
5720 */
5721 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
5722 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
5723 {
5724 Assert(PDMVmmDevHeapIsEnabled(pVM));
5725 Assert(pVM->hm.s.vmx.pRealModeTSS);
5726 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
5727 }
5728 else
5729 {
5730 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
5731 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
5732 if (fInterceptMF)
5733 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
5734 }
5735
5736 /* Additional intercepts for debugging, define these yourself explicitly. */
5737#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
5738 uXcptBitmap |= 0
5739 | RT_BIT(X86_XCPT_BP)
5740 | RT_BIT(X86_XCPT_DE)
5741 | RT_BIT(X86_XCPT_NM)
5742 | RT_BIT(X86_XCPT_TS)
5743 | RT_BIT(X86_XCPT_UD)
5744 | RT_BIT(X86_XCPT_NP)
5745 | RT_BIT(X86_XCPT_SS)
5746 | RT_BIT(X86_XCPT_GP)
5747 | RT_BIT(X86_XCPT_PF)
5748 | RT_BIT(X86_XCPT_MF)
5749 ;
5750#elif defined(HMVMX_ALWAYS_TRAP_PF)
5751 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
5752#endif
5753 if (pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv)
5754 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
5755 Assert(pVM->hmr0.s.fNestedPaging || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
5756
5757 /* Apply the hardware specified CR0 fixed bits and enable caching. */
5758 u64GuestCr0 |= fSetCr0;
5759 u64GuestCr0 &= fZapCr0;
5760 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5761
5762 /* Commit the CR0 and related fields to the guest VMCS. */
5763 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5764 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5765 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5766 {
5767 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5768 AssertRC(rc);
5769 }
5770 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
5771 {
5772 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
5773 AssertRC(rc);
5774 }
5775
5776 /* Update our caches. */
5777 pVmcsInfo->u32ProcCtls = uProcCtls;
5778 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
5779
5780 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5781 }
5782 else
5783 {
5784 /*
5785 * With nested-guests, we may have extended the guest/host mask here since we
5786 * merged in the outer guest's mask. Thus, the merged mask can include more bits
5787 * (to read from the nested-guest CR0 read-shadow) than the nested hypervisor
5788 * originally supplied. We must copy those bits from the nested-guest CR0 into
5789 * the nested-guest CR0 read-shadow.
5790 */
5791 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5792 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5793 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(&pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
5794 Assert(!RT_HI_U32(u64GuestCr0));
5795 Assert(u64GuestCr0 & X86_CR0_NE);
5796
5797 /* Apply the hardware specified CR0 fixed bits and enable caching. */
5798 u64GuestCr0 |= fSetCr0;
5799 u64GuestCr0 &= fZapCr0;
5800 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5801
5802 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
5803 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5804 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5805
5806 Log4Func(("cr0=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5807 }
5808
5809 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR0);
5810 }
5811
5812 return VINF_SUCCESS;
5813}
5814
5815
5816/**
5817 * Exports the guest control registers (CR3, CR4) into the guest-state area
5818 * in the VMCS.
5819 *
5820 * @returns VBox strict status code.
5821 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
5822 * without unrestricted guest access and the VMMDev is not presently
5823 * mapped (e.g. EFI32).
5824 *
5825 * @param pVCpu The cross context virtual CPU structure.
5826 * @param pVmxTransient The VMX-transient structure.
5827 *
5828 * @remarks No-long-jump zone!!!
5829 */
5830static VBOXSTRICTRC hmR0VmxExportGuestCR3AndCR4(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5831{
5832 int rc = VINF_SUCCESS;
5833 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5834
5835 /*
5836 * Guest CR2.
5837 * It's always loaded in the assembler code. Nothing to do here.
5838 */
5839
5840 /*
5841 * Guest CR3.
5842 */
5843 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR3)
5844 {
5845 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5846
5847 if (pVM->hmr0.s.fNestedPaging)
5848 {
5849 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5850 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
5851
5852 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
5853 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
5854 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
5855 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
5856
5857 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
5858 pVmcsInfo->HCPhysEPTP |= VMX_EPT_MEMTYPE_WB
5859 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
5860
5861 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
5862 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
5863 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
5864 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
5865 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
5866 || (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_EPT_ACCESS_DIRTY),
5867 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
5868
5869 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
5870 AssertRC(rc);
5871
5872 uint64_t u64GuestCr3;
5873 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5874 if ( pVM->hmr0.s.vmx.fUnrestrictedGuest
5875 || CPUMIsGuestPagingEnabledEx(pCtx))
5876 {
5877 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
5878 if (CPUMIsGuestInPAEModeEx(pCtx))
5879 {
5880 rc = PGMGstGetPaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
5881 AssertRC(rc);
5882 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
5883 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
5884 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
5885 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
5886 }
5887
5888 /*
5889 * The guest's view of its CR3 is unblemished with nested paging when the
5890 * guest is using paging or we have unrestricted guest execution to handle
5891 * the guest when it's not using paging.
5892 */
5893 u64GuestCr3 = pCtx->cr3;
5894 }
5895 else
5896 {
5897 /*
5898 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
5899 * thinks it accesses physical memory directly, we use our identity-mapped
5900 * page table to map guest-linear to guest-physical addresses. EPT takes care
5901 * of translating it to host-physical addresses.
5902 */
5903 RTGCPHYS GCPhys;
5904 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
5905
5906 /* We obtain it here every time as the guest could have relocated this PCI region. */
5907 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
5908 if (RT_SUCCESS(rc))
5909 { /* likely */ }
5910 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
5911 {
5912 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
5913 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
5914 }
5915 else
5916 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
5917
5918 u64GuestCr3 = GCPhys;
5919 }
5920
5921 Log4Func(("guest_cr3=%#RX64 (GstN)\n", u64GuestCr3));
5922 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, u64GuestCr3);
5923 AssertRC(rc);
5924 }
5925 else
5926 {
5927 Assert(!pVmxTransient->fIsNestedGuest);
5928 /* Non-nested paging case, just use the hypervisor's CR3. */
5929 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
5930
5931 Log4Func(("guest_cr3=%#RX64 (HstN)\n", HCPhysGuestCr3));
5932 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
5933 AssertRC(rc);
5934 }
5935
5936 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR3);
5937 }
5938
5939 /*
5940 * Guest CR4.
5941 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
5942 */
5943 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR4)
5944 {
5945 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5946 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5947
5948 uint64_t const fSetCr4 = g_HmMsrs.u.vmx.u64Cr4Fixed0;
5949 uint64_t const fZapCr4 = g_HmMsrs.u.vmx.u64Cr4Fixed1;
5950
5951 /*
5952 * With nested-guests, we may have extended the guest/host mask here (since we
5953 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
5954 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
5955 * the nested hypervisor originally supplied. Thus, we should, in essence, copy
5956 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
5957 */
5958 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5959 uint64_t u64GuestCr4 = pCtx->cr4;
5960 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
5961 ? pCtx->cr4
5962 : CPUMGetGuestVmxMaskedCr4(pCtx, pVmcsInfo->u64Cr4Mask);
5963 Assert(!RT_HI_U32(u64GuestCr4));
5964
5965 /*
5966 * Setup VT-x's view of the guest CR4.
5967 *
5968 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
5969 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
5970 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
5971 *
5972 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
5973 */
5974 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
5975 {
5976 Assert(pVM->hm.s.vmx.pRealModeTSS);
5977 Assert(PDMVmmDevHeapIsEnabled(pVM));
5978 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
5979 }
5980
5981 if (pVM->hmr0.s.fNestedPaging)
5982 {
5983 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
5984 && !pVM->hmr0.s.vmx.fUnrestrictedGuest)
5985 {
5986 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
5987 u64GuestCr4 |= X86_CR4_PSE;
5988 /* Our identity mapping is a 32-bit page directory. */
5989 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
5990 }
5991 /* else use guest CR4.*/
5992 }
5993 else
5994 {
5995 Assert(!pVmxTransient->fIsNestedGuest);
5996
5997 /*
5998 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
5999 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
6000 */
6001 switch (pVCpu->hm.s.enmShadowMode)
6002 {
6003 case PGMMODE_REAL: /* Real-mode. */
6004 case PGMMODE_PROTECTED: /* Protected mode without paging. */
6005 case PGMMODE_32_BIT: /* 32-bit paging. */
6006 {
6007 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
6008 break;
6009 }
6010
6011 case PGMMODE_PAE: /* PAE paging. */
6012 case PGMMODE_PAE_NX: /* PAE paging with NX. */
6013 {
6014 u64GuestCr4 |= X86_CR4_PAE;
6015 break;
6016 }
6017
6018 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
6019 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
6020 {
6021#ifdef VBOX_WITH_64_BITS_GUESTS
6022 /* For our assumption in hmR0VmxShouldSwapEferMsr. */
6023 Assert(u64GuestCr4 & X86_CR4_PAE);
6024 break;
6025#endif
6026 }
6027 default:
6028 AssertFailed();
6029 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
6030 }
6031 }
6032
6033 /* Apply the hardware specified CR4 fixed bits (mainly CR4.VMXE). */
6034 u64GuestCr4 |= fSetCr4;
6035 u64GuestCr4 &= fZapCr4;
6036
6037 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
6038 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
6039 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
6040
6041 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
6042 bool const fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
6043 if (fLoadSaveGuestXcr0 != pVCpu->hmr0.s.fLoadSaveGuestXcr0)
6044 {
6045 pVCpu->hmr0.s.fLoadSaveGuestXcr0 = fLoadSaveGuestXcr0;
6046 hmR0VmxUpdateStartVmFunction(pVCpu);
6047 }
6048
6049 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR4);
6050
6051 Log4Func(("cr4=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
6052 }
6053 return rc;
6054}
6055
6056
6057/**
6058 * Exports the guest debug registers into the guest-state area in the VMCS.
6059 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
6060 *
6061 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
6062 *
6063 * @returns VBox status code.
6064 * @param pVCpu The cross context virtual CPU structure.
6065 * @param pVmxTransient The VMX-transient structure.
6066 *
6067 * @remarks No-long-jump zone!!!
6068 */
6069static int hmR0VmxExportSharedDebugState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6070{
6071 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
6072
6073 /** @todo NSTVMX: Figure out what we want to do with nested-guest instruction
6074 * stepping. */
6075 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6076 if (pVmxTransient->fIsNestedGuest)
6077 {
6078 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, CPUMGetGuestDR7(pVCpu));
6079 AssertRC(rc);
6080
6081 /* Always intercept Mov DRx accesses for the nested-guest for now. */
6082 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
6083 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
6084 AssertRC(rc);
6085 return VINF_SUCCESS;
6086 }
6087
6088#ifdef VBOX_STRICT
6089 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
6090 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
6091 {
6092 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
6093 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
6094 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
6095 }
6096#endif
6097
6098 bool fSteppingDB = false;
6099 bool fInterceptMovDRx = false;
6100 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
6101 if (pVCpu->hm.s.fSingleInstruction)
6102 {
6103 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
6104 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
6105 {
6106 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
6107 Assert(fSteppingDB == false);
6108 }
6109 else
6110 {
6111 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
6112 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
6113 pVCpu->hmr0.s.fClearTrapFlag = true;
6114 fSteppingDB = true;
6115 }
6116 }
6117
6118 uint64_t u64GuestDr7;
6119 if ( fSteppingDB
6120 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
6121 {
6122 /*
6123 * Use the combined guest and host DRx values found in the hypervisor register set
6124 * because the hypervisor debugger has breakpoints active or someone is single stepping
6125 * on the host side without a monitor trap flag.
6126 *
6127 * Note! DBGF expects a clean DR6 state before executing guest code.
6128 */
6129 if (!CPUMIsHyperDebugStateActive(pVCpu))
6130 {
6131 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
6132 Assert(CPUMIsHyperDebugStateActive(pVCpu));
6133 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
6134 }
6135
6136 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
6137 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
6138 pVCpu->hmr0.s.fUsingHyperDR7 = true;
6139 fInterceptMovDRx = true;
6140 }
6141 else
6142 {
6143 /*
6144 * If the guest has enabled debug registers, we need to load them prior to
6145 * executing guest code so they'll trigger at the right time.
6146 */
6147 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
6148 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
6149 {
6150 if (!CPUMIsGuestDebugStateActive(pVCpu))
6151 {
6152 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
6153 Assert(CPUMIsGuestDebugStateActive(pVCpu));
6154 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
6155 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
6156 }
6157 Assert(!fInterceptMovDRx);
6158 }
6159 else if (!CPUMIsGuestDebugStateActive(pVCpu))
6160 {
6161 /*
6162 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
6163 * must intercept #DB in order to maintain a correct DR6 guest value, and
6164 * because we need to intercept it to prevent nested #DBs from hanging the
6165 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
6166 */
6167 fInterceptMovDRx = true;
6168 }
6169
6170 /* Update DR7 with the actual guest value. */
6171 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
6172 pVCpu->hmr0.s.fUsingHyperDR7 = false;
6173 }
6174
6175 if (fInterceptMovDRx)
6176 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
6177 else
6178 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
6179
6180 /*
6181 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
6182 * monitor-trap flag and update our cache.
6183 */
6184 if (uProcCtls != pVmcsInfo->u32ProcCtls)
6185 {
6186 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
6187 AssertRC(rc);
6188 pVmcsInfo->u32ProcCtls = uProcCtls;
6189 }
6190
6191 /*
6192 * Update guest DR7.
6193 */
6194 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, u64GuestDr7);
6195 AssertRC(rc);
6196
6197 /*
6198 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
6199 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
6200 *
6201 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
6202 */
6203 if (fSteppingDB)
6204 {
6205 Assert(pVCpu->hm.s.fSingleInstruction);
6206 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
6207
6208 uint32_t fIntrState = 0;
6209 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
6210 AssertRC(rc);
6211
6212 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
6213 {
6214 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
6215 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
6216 AssertRC(rc);
6217 }
6218 }
6219
6220 return VINF_SUCCESS;
6221}
6222
6223
6224#ifdef VBOX_STRICT
6225/**
6226 * Strict function to validate segment registers.
6227 *
6228 * @param pVCpu The cross context virtual CPU structure.
6229 * @param pVmcsInfo The VMCS info. object.
6230 *
6231 * @remarks Will import guest CR0 on strict builds during validation of
6232 * segments.
6233 */
6234static void hmR0VmxValidateSegmentRegs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
6235{
6236 /*
6237 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
6238 *
6239 * The reason we check for attribute value 0 in this function and not just the unusable bit is
6240 * because hmR0VmxExportGuestSegReg() only updates the VMCS' copy of the value with the
6241 * unusable bit and doesn't change the guest-context value.
6242 */
6243 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6244 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6245 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
6246 if ( !pVM->hmr0.s.vmx.fUnrestrictedGuest
6247 && ( !CPUMIsGuestInRealModeEx(pCtx)
6248 && !CPUMIsGuestInV86ModeEx(pCtx)))
6249 {
6250 /* Protected mode checks */
6251 /* CS */
6252 Assert(pCtx->cs.Attr.n.u1Present);
6253 Assert(!(pCtx->cs.Attr.u & 0xf00));
6254 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
6255 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
6256 || !(pCtx->cs.Attr.n.u1Granularity));
6257 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
6258 || (pCtx->cs.Attr.n.u1Granularity));
6259 /* CS cannot be loaded with NULL in protected mode. */
6260 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
6261 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
6262 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
6263 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
6264 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
6265 else
6266 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
6267 /* SS */
6268 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
6269 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
6270 if ( !(pCtx->cr0 & X86_CR0_PE)
6271 || pCtx->cs.Attr.n.u4Type == 3)
6272 {
6273 Assert(!pCtx->ss.Attr.n.u2Dpl);
6274 }
6275 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
6276 {
6277 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
6278 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
6279 Assert(pCtx->ss.Attr.n.u1Present);
6280 Assert(!(pCtx->ss.Attr.u & 0xf00));
6281 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
6282 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
6283 || !(pCtx->ss.Attr.n.u1Granularity));
6284 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
6285 || (pCtx->ss.Attr.n.u1Granularity));
6286 }
6287 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSegReg(). */
6288 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
6289 {
6290 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6291 Assert(pCtx->ds.Attr.n.u1Present);
6292 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
6293 Assert(!(pCtx->ds.Attr.u & 0xf00));
6294 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
6295 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
6296 || !(pCtx->ds.Attr.n.u1Granularity));
6297 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
6298 || (pCtx->ds.Attr.n.u1Granularity));
6299 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6300 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
6301 }
6302 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
6303 {
6304 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6305 Assert(pCtx->es.Attr.n.u1Present);
6306 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
6307 Assert(!(pCtx->es.Attr.u & 0xf00));
6308 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
6309 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
6310 || !(pCtx->es.Attr.n.u1Granularity));
6311 Assert( !(pCtx->es.u32Limit & 0xfff00000)
6312 || (pCtx->es.Attr.n.u1Granularity));
6313 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6314 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
6315 }
6316 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
6317 {
6318 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6319 Assert(pCtx->fs.Attr.n.u1Present);
6320 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
6321 Assert(!(pCtx->fs.Attr.u & 0xf00));
6322 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
6323 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
6324 || !(pCtx->fs.Attr.n.u1Granularity));
6325 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
6326 || (pCtx->fs.Attr.n.u1Granularity));
6327 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6328 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
6329 }
6330 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
6331 {
6332 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6333 Assert(pCtx->gs.Attr.n.u1Present);
6334 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
6335 Assert(!(pCtx->gs.Attr.u & 0xf00));
6336 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
6337 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
6338 || !(pCtx->gs.Attr.n.u1Granularity));
6339 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
6340 || (pCtx->gs.Attr.n.u1Granularity));
6341 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6342 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
6343 }
6344 /* 64-bit capable CPUs. */
6345 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6346 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
6347 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
6348 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
6349 }
6350 else if ( CPUMIsGuestInV86ModeEx(pCtx)
6351 || ( CPUMIsGuestInRealModeEx(pCtx)
6352 && !pVM->hmr0.s.vmx.fUnrestrictedGuest))
6353 {
6354 /* Real and v86 mode checks. */
6355 /* hmR0VmxExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
6356 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
6357 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
6358 {
6359 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
6360 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
6361 }
6362 else
6363 {
6364 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
6365 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
6366 }
6367
6368 /* CS */
6369 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
6370 Assert(pCtx->cs.u32Limit == 0xffff);
6371 Assert(u32CSAttr == 0xf3);
6372 /* SS */
6373 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
6374 Assert(pCtx->ss.u32Limit == 0xffff);
6375 Assert(u32SSAttr == 0xf3);
6376 /* DS */
6377 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
6378 Assert(pCtx->ds.u32Limit == 0xffff);
6379 Assert(u32DSAttr == 0xf3);
6380 /* ES */
6381 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
6382 Assert(pCtx->es.u32Limit == 0xffff);
6383 Assert(u32ESAttr == 0xf3);
6384 /* FS */
6385 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
6386 Assert(pCtx->fs.u32Limit == 0xffff);
6387 Assert(u32FSAttr == 0xf3);
6388 /* GS */
6389 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
6390 Assert(pCtx->gs.u32Limit == 0xffff);
6391 Assert(u32GSAttr == 0xf3);
6392 /* 64-bit capable CPUs. */
6393 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6394 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
6395 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
6396 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
6397 }
6398}
6399#endif /* VBOX_STRICT */
6400
6401
6402/**
6403 * Exports a guest segment register into the guest-state area in the VMCS.
6404 *
6405 * @returns VBox status code.
6406 * @param pVCpu The cross context virtual CPU structure.
6407 * @param pVmcsInfo The VMCS info. object.
6408 * @param iSegReg The segment register number (X86_SREG_XXX).
6409 * @param pSelReg Pointer to the segment selector.
6410 *
6411 * @remarks No-long-jump zone!!!
6412 */
6413static int hmR0VmxExportGuestSegReg(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, uint32_t iSegReg, PCCPUMSELREG pSelReg)
6414{
6415 Assert(iSegReg < X86_SREG_COUNT);
6416
6417 uint32_t u32Access = pSelReg->Attr.u;
6418 if (!pVmcsInfo->pShared->RealMode.fRealOnV86Active)
6419 {
6420 /*
6421 * The way to differentiate between whether this is really a null selector or was just
6422 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
6423 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
6424 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
6425 * NULL selectors loaded in protected-mode have their attribute as 0.
6426 */
6427 if (u32Access)
6428 { }
6429 else
6430 u32Access = X86DESCATTR_UNUSABLE;
6431 }
6432 else
6433 {
6434 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
6435 u32Access = 0xf3;
6436 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6437 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
6438 RT_NOREF_PV(pVCpu);
6439 }
6440
6441 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
6442 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
6443 ("Access bit not set for usable segment. %.2s sel=%#x attr %#x\n", "ESCSSSDSFSGS" + iSegReg * 2, pSelReg, pSelReg->Attr.u));
6444
6445 /*
6446 * Commit it to the VMCS.
6447 */
6448 Assert((uint32_t)VMX_VMCS16_GUEST_SEG_SEL(iSegReg) == g_aVmcsSegSel[iSegReg]);
6449 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg) == g_aVmcsSegLimit[iSegReg]);
6450 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg) == g_aVmcsSegAttr[iSegReg]);
6451 Assert((uint32_t)VMX_VMCS_GUEST_SEG_BASE(iSegReg) == g_aVmcsSegBase[iSegReg]);
6452 int rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_SEG_SEL(iSegReg), pSelReg->Sel); AssertRC(rc);
6453 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg), pSelReg->u32Limit); AssertRC(rc);
6454 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SEG_BASE(iSegReg), pSelReg->u64Base); AssertRC(rc);
6455 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg), u32Access); AssertRC(rc);
6456 return VINF_SUCCESS;
6457}
6458
6459
6460/**
6461 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
6462 * area in the VMCS.
6463 *
6464 * @returns VBox status code.
6465 * @param pVCpu The cross context virtual CPU structure.
6466 * @param pVmxTransient The VMX-transient structure.
6467 *
6468 * @remarks Will import guest CR0 on strict builds during validation of
6469 * segments.
6470 * @remarks No-long-jump zone!!!
6471 */
6472static int hmR0VmxExportGuestSegRegsXdtr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6473{
6474 int rc = VERR_INTERNAL_ERROR_5;
6475 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6476 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6477 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6478 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
6479
6480 /*
6481 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
6482 */
6483 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
6484 {
6485 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CS)
6486 {
6487 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
6488 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6489 pVmcsInfoShared->RealMode.AttrCS.u = pCtx->cs.Attr.u;
6490 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
6491 AssertRC(rc);
6492 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CS);
6493 }
6494
6495 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SS)
6496 {
6497 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
6498 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6499 pVmcsInfoShared->RealMode.AttrSS.u = pCtx->ss.Attr.u;
6500 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
6501 AssertRC(rc);
6502 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SS);
6503 }
6504
6505 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_DS)
6506 {
6507 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
6508 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6509 pVmcsInfoShared->RealMode.AttrDS.u = pCtx->ds.Attr.u;
6510 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
6511 AssertRC(rc);
6512 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_DS);
6513 }
6514
6515 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_ES)
6516 {
6517 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
6518 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6519 pVmcsInfoShared->RealMode.AttrES.u = pCtx->es.Attr.u;
6520 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
6521 AssertRC(rc);
6522 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_ES);
6523 }
6524
6525 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_FS)
6526 {
6527 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
6528 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6529 pVmcsInfoShared->RealMode.AttrFS.u = pCtx->fs.Attr.u;
6530 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
6531 AssertRC(rc);
6532 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_FS);
6533 }
6534
6535 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GS)
6536 {
6537 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
6538 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6539 pVmcsInfoShared->RealMode.AttrGS.u = pCtx->gs.Attr.u;
6540 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
6541 AssertRC(rc);
6542 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GS);
6543 }
6544
6545#ifdef VBOX_STRICT
6546 hmR0VmxValidateSegmentRegs(pVCpu, pVmcsInfo);
6547#endif
6548 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
6549 pCtx->cs.Attr.u));
6550 }
6551
6552 /*
6553 * Guest TR.
6554 */
6555 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_TR)
6556 {
6557 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
6558
6559 /*
6560 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
6561 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
6562 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
6563 */
6564 uint16_t u16Sel;
6565 uint32_t u32Limit;
6566 uint64_t u64Base;
6567 uint32_t u32AccessRights;
6568 if (!pVmcsInfoShared->RealMode.fRealOnV86Active)
6569 {
6570 u16Sel = pCtx->tr.Sel;
6571 u32Limit = pCtx->tr.u32Limit;
6572 u64Base = pCtx->tr.u64Base;
6573 u32AccessRights = pCtx->tr.Attr.u;
6574 }
6575 else
6576 {
6577 Assert(!pVmxTransient->fIsNestedGuest);
6578 Assert(pVM->hm.s.vmx.pRealModeTSS);
6579 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
6580
6581 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
6582 RTGCPHYS GCPhys;
6583 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
6584 AssertRCReturn(rc, rc);
6585
6586 X86DESCATTR DescAttr;
6587 DescAttr.u = 0;
6588 DescAttr.n.u1Present = 1;
6589 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
6590
6591 u16Sel = 0;
6592 u32Limit = HM_VTX_TSS_SIZE;
6593 u64Base = GCPhys;
6594 u32AccessRights = DescAttr.u;
6595 }
6596
6597 /* Validate. */
6598 Assert(!(u16Sel & RT_BIT(2)));
6599 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
6600 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
6601 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
6602 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
6603 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
6604 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
6605 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
6606 Assert( (u32Limit & 0xfff) == 0xfff
6607 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
6608 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
6609 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
6610
6611 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
6612 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
6613 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
6614 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
6615
6616 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_TR);
6617 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
6618 }
6619
6620 /*
6621 * Guest GDTR.
6622 */
6623 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GDTR)
6624 {
6625 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
6626
6627 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
6628 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
6629
6630 /* Validate. */
6631 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6632
6633 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
6634 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
6635 }
6636
6637 /*
6638 * Guest LDTR.
6639 */
6640 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_LDTR)
6641 {
6642 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
6643
6644 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
6645 uint32_t u32Access;
6646 if ( !pVmxTransient->fIsNestedGuest
6647 && !pCtx->ldtr.Attr.u)
6648 u32Access = X86DESCATTR_UNUSABLE;
6649 else
6650 u32Access = pCtx->ldtr.Attr.u;
6651
6652 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
6653 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
6654 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
6655 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
6656
6657 /* Validate. */
6658 if (!(u32Access & X86DESCATTR_UNUSABLE))
6659 {
6660 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
6661 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
6662 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
6663 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
6664 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
6665 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
6666 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
6667 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
6668 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
6669 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
6670 }
6671
6672 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
6673 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
6674 }
6675
6676 /*
6677 * Guest IDTR.
6678 */
6679 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_IDTR)
6680 {
6681 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
6682
6683 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
6684 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
6685
6686 /* Validate. */
6687 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6688
6689 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
6690 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
6691 }
6692
6693 return VINF_SUCCESS;
6694}
6695
6696
6697/**
6698 * Exports certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
6699 * areas.
6700 *
6701 * These MSRs will automatically be loaded to the host CPU on every successful
6702 * VM-entry and stored from the host CPU on every successful VM-exit.
6703 *
6704 * We creates/updates MSR slots for the host MSRs in the VM-exit MSR-load area. The
6705 * actual host MSR values are not- updated here for performance reasons. See
6706 * hmR0VmxExportHostMsrs().
6707 *
6708 * We also exports the guest sysenter MSRs into the guest-state area in the VMCS.
6709 *
6710 * @returns VBox status code.
6711 * @param pVCpu The cross context virtual CPU structure.
6712 * @param pVmxTransient The VMX-transient structure.
6713 *
6714 * @remarks No-long-jump zone!!!
6715 */
6716static int hmR0VmxExportGuestMsrs(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6717{
6718 AssertPtr(pVCpu);
6719 AssertPtr(pVmxTransient);
6720
6721 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6722 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6723
6724 /*
6725 * MSRs that we use the auto-load/store MSR area in the VMCS.
6726 * For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(),
6727 * nothing to do here. The host MSR values are updated when it's safe in
6728 * hmR0VmxLazySaveHostMsrs().
6729 *
6730 * For nested-guests, the guests MSRs from the VM-entry MSR-load area are already
6731 * loaded (into the guest-CPU context) by the VMLAUNCH/VMRESUME instruction
6732 * emulation. The merged MSR permission bitmap will ensure that we get VM-exits
6733 * for any MSR that are not part of the lazy MSRs so we do not need to place
6734 * those MSRs into the auto-load/store MSR area. Nothing to do here.
6735 */
6736 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
6737 {
6738 /* No auto-load/store MSRs currently. */
6739 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_GUEST_AUTO_MSRS);
6740 }
6741
6742 /*
6743 * Guest Sysenter MSRs.
6744 */
6745 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_MSR_MASK)
6746 {
6747 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
6748
6749 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
6750 {
6751 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
6752 AssertRC(rc);
6753 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_CS_MSR);
6754 }
6755
6756 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
6757 {
6758 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
6759 AssertRC(rc);
6760 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
6761 }
6762
6763 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
6764 {
6765 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
6766 AssertRC(rc);
6767 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
6768 }
6769 }
6770
6771 /*
6772 * Guest/host EFER MSR.
6773 */
6774 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_EFER_MSR)
6775 {
6776 /* Whether we are using the VMCS to swap the EFER MSR must have been
6777 determined earlier while exporting VM-entry/VM-exit controls. */
6778 Assert(!(ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS));
6779 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6780
6781 if (hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
6782 {
6783 /*
6784 * EFER.LME is written by software, while EFER.LMA is set by the CPU to (CR0.PG & EFER.LME).
6785 * This means a guest can set EFER.LME=1 while CR0.PG=0 and EFER.LMA can remain 0.
6786 * VT-x requires that "IA-32e mode guest" VM-entry control must be identical to EFER.LMA
6787 * and to CR0.PG. Without unrestricted execution, CR0.PG (used for VT-x, not the shadow)
6788 * must always be 1. This forces us to effectively clear both EFER.LMA and EFER.LME until
6789 * the guest has also set CR0.PG=1. Otherwise, we would run into an invalid-guest state
6790 * during VM-entry.
6791 */
6792 uint64_t uGuestEferMsr = pCtx->msrEFER;
6793 if (!pVM->hmr0.s.vmx.fUnrestrictedGuest)
6794 {
6795 if (!(pCtx->msrEFER & MSR_K6_EFER_LMA))
6796 uGuestEferMsr &= ~MSR_K6_EFER_LME;
6797 else
6798 Assert((pCtx->msrEFER & (MSR_K6_EFER_LMA | MSR_K6_EFER_LME)) == (MSR_K6_EFER_LMA | MSR_K6_EFER_LME));
6799 }
6800
6801 /*
6802 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
6803 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
6804 */
6805 if (g_fHmVmxSupportsVmcsEfer)
6806 {
6807 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, uGuestEferMsr);
6808 AssertRC(rc);
6809 }
6810 else
6811 {
6812 /*
6813 * We shall use the auto-load/store MSR area only for loading the EFER MSR but we must
6814 * continue to intercept guest read and write accesses to it, see @bugref{7386#c16}.
6815 */
6816 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER, uGuestEferMsr,
6817 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6818 AssertRCReturn(rc, rc);
6819 }
6820
6821 Log4Func(("efer=%#RX64 shadow=%#RX64\n", uGuestEferMsr, pCtx->msrEFER));
6822 }
6823 else if (!g_fHmVmxSupportsVmcsEfer)
6824 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER);
6825
6826 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
6827 }
6828
6829 /*
6830 * Other MSRs.
6831 */
6832 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_OTHER_MSRS)
6833 {
6834 /* Speculation Control (R/W). */
6835 HMVMX_CPUMCTX_ASSERT(pVCpu, HM_CHANGED_GUEST_OTHER_MSRS);
6836 if (pVM->cpum.ro.GuestFeatures.fIbrs)
6837 {
6838 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_IA32_SPEC_CTRL, CPUMGetGuestSpecCtrl(pVCpu),
6839 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6840 AssertRCReturn(rc, rc);
6841 }
6842
6843 /* Last Branch Record. */
6844 if (pVM->hmr0.s.vmx.fLbr)
6845 {
6846 PVMXVMCSINFOSHARED const pVmcsInfoShared = pVmxTransient->pVmcsInfo->pShared;
6847 uint32_t const idFromIpMsrStart = pVM->hmr0.s.vmx.idLbrFromIpMsrFirst;
6848 uint32_t const idToIpMsrStart = pVM->hmr0.s.vmx.idLbrToIpMsrFirst;
6849 uint32_t const cLbrStack = pVM->hmr0.s.vmx.idLbrFromIpMsrLast - pVM->hmr0.s.vmx.idLbrFromIpMsrFirst + 1;
6850 Assert(cLbrStack <= 32);
6851 for (uint32_t i = 0; i < cLbrStack; i++)
6852 {
6853 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, idFromIpMsrStart + i,
6854 pVmcsInfoShared->au64LbrFromIpMsr[i],
6855 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6856 AssertRCReturn(rc, rc);
6857
6858 /* Some CPUs don't have a Branch-To-IP MSR (P4 and related Xeons). */
6859 if (idToIpMsrStart != 0)
6860 {
6861 rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, idToIpMsrStart + i,
6862 pVmcsInfoShared->au64LbrToIpMsr[i],
6863 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6864 AssertRCReturn(rc, rc);
6865 }
6866 }
6867
6868 /* Add LBR top-of-stack MSR (which contains the index to the most recent record). */
6869 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, pVM->hmr0.s.vmx.idLbrTosMsr,
6870 pVmcsInfoShared->u64LbrTosMsr, false /* fSetReadWrite */,
6871 false /* fUpdateHostMsr */);
6872 AssertRCReturn(rc, rc);
6873 }
6874
6875 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
6876 }
6877
6878 return VINF_SUCCESS;
6879}
6880
6881
6882/**
6883 * Wrapper for running the guest code in VT-x.
6884 *
6885 * @returns VBox status code, no informational status codes.
6886 * @param pVCpu The cross context virtual CPU structure.
6887 * @param pVmxTransient The VMX-transient structure.
6888 *
6889 * @remarks No-long-jump zone!!!
6890 */
6891DECLINLINE(int) hmR0VmxRunGuest(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6892{
6893 /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
6894 pVCpu->cpum.GstCtx.fExtrn |= HMVMX_CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_HM;
6895
6896 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6897 bool const fResumeVM = RT_BOOL(pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_LAUNCHED);
6898#ifdef VBOX_WITH_STATISTICS
6899 if (fResumeVM)
6900 STAM_COUNTER_INC(&pVCpu->hm.s.StatVmxVmResume);
6901 else
6902 STAM_COUNTER_INC(&pVCpu->hm.s.StatVmxVmLaunch);
6903#endif
6904 int rc = pVCpu->hmr0.s.vmx.pfnStartVm(pVmcsInfo, pVCpu, fResumeVM);
6905 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
6906 return rc;
6907}
6908
6909
6910/**
6911 * Reports world-switch error and dumps some useful debug info.
6912 *
6913 * @param pVCpu The cross context virtual CPU structure.
6914 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
6915 * @param pVmxTransient The VMX-transient structure (only
6916 * exitReason updated).
6917 */
6918static void hmR0VmxReportWorldSwitchError(PVMCPUCC pVCpu, int rcVMRun, PVMXTRANSIENT pVmxTransient)
6919{
6920 Assert(pVCpu);
6921 Assert(pVmxTransient);
6922 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
6923
6924 Log4Func(("VM-entry failure: %Rrc\n", rcVMRun));
6925 switch (rcVMRun)
6926 {
6927 case VERR_VMX_INVALID_VMXON_PTR:
6928 AssertFailed();
6929 break;
6930 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
6931 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
6932 {
6933 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
6934 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
6935 AssertRC(rc);
6936 hmR0VmxReadExitQualVmcs(pVmxTransient);
6937
6938 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hmr0.s.idEnteredCpu;
6939 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
6940 Cannot do it here as we may have been long preempted. */
6941
6942#ifdef VBOX_STRICT
6943 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6944 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
6945 pVmxTransient->uExitReason));
6946 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQual));
6947 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
6948 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
6949 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
6950 else
6951 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
6952 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
6953 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
6954
6955 static struct
6956 {
6957 /** Name of the field to log. */
6958 const char *pszName;
6959 /** The VMCS field. */
6960 uint32_t uVmcsField;
6961 /** Whether host support of this field needs to be checked. */
6962 bool fCheckSupport;
6963 } const s_aVmcsFields[] =
6964 {
6965 { "VMX_VMCS32_CTRL_PIN_EXEC", VMX_VMCS32_CTRL_PIN_EXEC, false },
6966 { "VMX_VMCS32_CTRL_PROC_EXEC", VMX_VMCS32_CTRL_PROC_EXEC, false },
6967 { "VMX_VMCS32_CTRL_PROC_EXEC2", VMX_VMCS32_CTRL_PROC_EXEC2, true },
6968 { "VMX_VMCS32_CTRL_ENTRY", VMX_VMCS32_CTRL_ENTRY, false },
6969 { "VMX_VMCS32_CTRL_EXIT", VMX_VMCS32_CTRL_EXIT, false },
6970 { "VMX_VMCS32_CTRL_CR3_TARGET_COUNT", VMX_VMCS32_CTRL_CR3_TARGET_COUNT, false },
6971 { "VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO", VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, false },
6972 { "VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE", VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, false },
6973 { "VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH", VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, false },
6974 { "VMX_VMCS32_CTRL_TPR_THRESHOLD", VMX_VMCS32_CTRL_TPR_THRESHOLD, false },
6975 { "VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, false },
6976 { "VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, false },
6977 { "VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, false },
6978 { "VMX_VMCS32_CTRL_EXCEPTION_BITMAP", VMX_VMCS32_CTRL_EXCEPTION_BITMAP, false },
6979 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, false },
6980 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, false },
6981 { "VMX_VMCS_CTRL_CR0_MASK", VMX_VMCS_CTRL_CR0_MASK, false },
6982 { "VMX_VMCS_CTRL_CR0_READ_SHADOW", VMX_VMCS_CTRL_CR0_READ_SHADOW, false },
6983 { "VMX_VMCS_CTRL_CR4_MASK", VMX_VMCS_CTRL_CR4_MASK, false },
6984 { "VMX_VMCS_CTRL_CR4_READ_SHADOW", VMX_VMCS_CTRL_CR4_READ_SHADOW, false },
6985 { "VMX_VMCS64_CTRL_EPTP_FULL", VMX_VMCS64_CTRL_EPTP_FULL, true },
6986 { "VMX_VMCS_GUEST_RIP", VMX_VMCS_GUEST_RIP, false },
6987 { "VMX_VMCS_GUEST_RSP", VMX_VMCS_GUEST_RSP, false },
6988 { "VMX_VMCS_GUEST_RFLAGS", VMX_VMCS_GUEST_RFLAGS, false },
6989 { "VMX_VMCS16_VPID", VMX_VMCS16_VPID, true, },
6990 { "VMX_VMCS_HOST_CR0", VMX_VMCS_HOST_CR0, false },
6991 { "VMX_VMCS_HOST_CR3", VMX_VMCS_HOST_CR3, false },
6992 { "VMX_VMCS_HOST_CR4", VMX_VMCS_HOST_CR4, false },
6993 /* The order of selector fields below are fixed! */
6994 { "VMX_VMCS16_HOST_ES_SEL", VMX_VMCS16_HOST_ES_SEL, false },
6995 { "VMX_VMCS16_HOST_CS_SEL", VMX_VMCS16_HOST_CS_SEL, false },
6996 { "VMX_VMCS16_HOST_SS_SEL", VMX_VMCS16_HOST_SS_SEL, false },
6997 { "VMX_VMCS16_HOST_DS_SEL", VMX_VMCS16_HOST_DS_SEL, false },
6998 { "VMX_VMCS16_HOST_FS_SEL", VMX_VMCS16_HOST_FS_SEL, false },
6999 { "VMX_VMCS16_HOST_GS_SEL", VMX_VMCS16_HOST_GS_SEL, false },
7000 { "VMX_VMCS16_HOST_TR_SEL", VMX_VMCS16_HOST_TR_SEL, false },
7001 /* End of ordered selector fields. */
7002 { "VMX_VMCS_HOST_TR_BASE", VMX_VMCS_HOST_TR_BASE, false },
7003 { "VMX_VMCS_HOST_GDTR_BASE", VMX_VMCS_HOST_GDTR_BASE, false },
7004 { "VMX_VMCS_HOST_IDTR_BASE", VMX_VMCS_HOST_IDTR_BASE, false },
7005 { "VMX_VMCS32_HOST_SYSENTER_CS", VMX_VMCS32_HOST_SYSENTER_CS, false },
7006 { "VMX_VMCS_HOST_SYSENTER_EIP", VMX_VMCS_HOST_SYSENTER_EIP, false },
7007 { "VMX_VMCS_HOST_SYSENTER_ESP", VMX_VMCS_HOST_SYSENTER_ESP, false },
7008 { "VMX_VMCS_HOST_RSP", VMX_VMCS_HOST_RSP, false },
7009 { "VMX_VMCS_HOST_RIP", VMX_VMCS_HOST_RIP, false }
7010 };
7011
7012 RTGDTR HostGdtr;
7013 ASMGetGDTR(&HostGdtr);
7014
7015 uint32_t const cVmcsFields = RT_ELEMENTS(s_aVmcsFields);
7016 for (uint32_t i = 0; i < cVmcsFields; i++)
7017 {
7018 uint32_t const uVmcsField = s_aVmcsFields[i].uVmcsField;
7019
7020 bool fSupported;
7021 if (!s_aVmcsFields[i].fCheckSupport)
7022 fSupported = true;
7023 else
7024 {
7025 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7026 switch (uVmcsField)
7027 {
7028 case VMX_VMCS64_CTRL_EPTP_FULL: fSupported = pVM->hmr0.s.fNestedPaging; break;
7029 case VMX_VMCS16_VPID: fSupported = pVM->hmr0.s.vmx.fVpid; break;
7030 case VMX_VMCS32_CTRL_PROC_EXEC2:
7031 fSupported = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
7032 break;
7033 default:
7034 AssertMsgFailedReturnVoid(("Failed to provide VMCS field support for %#RX32\n", uVmcsField));
7035 }
7036 }
7037
7038 if (fSupported)
7039 {
7040 uint8_t const uWidth = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH);
7041 switch (uWidth)
7042 {
7043 case VMX_VMCSFIELD_WIDTH_16BIT:
7044 {
7045 uint16_t u16Val;
7046 rc = VMXReadVmcs16(uVmcsField, &u16Val);
7047 AssertRC(rc);
7048 Log4(("%-40s = %#RX16\n", s_aVmcsFields[i].pszName, u16Val));
7049
7050 if ( uVmcsField >= VMX_VMCS16_HOST_ES_SEL
7051 && uVmcsField <= VMX_VMCS16_HOST_TR_SEL)
7052 {
7053 if (u16Val < HostGdtr.cbGdt)
7054 {
7055 /* Order of selectors in s_apszSel is fixed and matches the order in s_aVmcsFields. */
7056 static const char * const s_apszSel[] = { "Host ES", "Host CS", "Host SS", "Host DS",
7057 "Host FS", "Host GS", "Host TR" };
7058 uint8_t const idxSel = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_INDEX);
7059 Assert(idxSel < RT_ELEMENTS(s_apszSel));
7060 PCX86DESCHC pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u16Val & X86_SEL_MASK));
7061 hmR0DumpDescriptor(pDesc, u16Val, s_apszSel[idxSel]);
7062 }
7063 else
7064 Log4((" Selector value exceeds GDT limit!\n"));
7065 }
7066 break;
7067 }
7068
7069 case VMX_VMCSFIELD_WIDTH_32BIT:
7070 {
7071 uint32_t u32Val;
7072 rc = VMXReadVmcs32(uVmcsField, &u32Val);
7073 AssertRC(rc);
7074 Log4(("%-40s = %#RX32\n", s_aVmcsFields[i].pszName, u32Val));
7075 break;
7076 }
7077
7078 case VMX_VMCSFIELD_WIDTH_64BIT:
7079 case VMX_VMCSFIELD_WIDTH_NATURAL:
7080 {
7081 uint64_t u64Val;
7082 rc = VMXReadVmcs64(uVmcsField, &u64Val);
7083 AssertRC(rc);
7084 Log4(("%-40s = %#RX64\n", s_aVmcsFields[i].pszName, u64Val));
7085 break;
7086 }
7087 }
7088 }
7089 }
7090
7091 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
7092 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
7093 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
7094 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
7095 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
7096 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
7097#endif /* VBOX_STRICT */
7098 break;
7099 }
7100
7101 default:
7102 /* Impossible */
7103 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
7104 break;
7105 }
7106}
7107
7108
7109/**
7110 * Sets up the usage of TSC-offsetting and updates the VMCS.
7111 *
7112 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
7113 * VMX-preemption timer.
7114 *
7115 * @returns VBox status code.
7116 * @param pVCpu The cross context virtual CPU structure.
7117 * @param pVmxTransient The VMX-transient structure.
7118 * @param idCurrentCpu The current CPU number.
7119 *
7120 * @remarks No-long-jump zone!!!
7121 */
7122static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, RTCPUID idCurrentCpu)
7123{
7124 bool fOffsettedTsc;
7125 bool fParavirtTsc;
7126 uint64_t uTscOffset;
7127 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7128 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7129
7130 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
7131 {
7132
7133 /* The TMCpuTickGetDeadlineAndTscOffset function is expensive (calling it on
7134 every entry slowed down the bs2-test1 CPUID testcase by ~33% (on an 10980xe). */
7135 uint64_t cTicksToDeadline;
7136 if ( idCurrentCpu == pVCpu->hmr0.s.idLastCpu
7137 && TMVirtualSyncIsCurrentDeadlineVersion(pVM, pVCpu->hmr0.s.vmx.uTscDeadlineVersion))
7138 {
7139 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionReusingDeadline);
7140 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
7141 cTicksToDeadline = pVCpu->hmr0.s.vmx.uTscDeadline - SUPReadTsc();
7142 if ((int64_t)cTicksToDeadline > 0)
7143 { /* hopefully */ }
7144 else
7145 {
7146 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionReusingDeadlineExpired);
7147 cTicksToDeadline = 0;
7148 }
7149 }
7150 else
7151 {
7152 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionRecalcingDeadline);
7153 cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &uTscOffset, &fOffsettedTsc, &fParavirtTsc,
7154 &pVCpu->hmr0.s.vmx.uTscDeadline,
7155 &pVCpu->hmr0.s.vmx.uTscDeadlineVersion);
7156 pVCpu->hmr0.s.vmx.uTscDeadline += cTicksToDeadline;
7157 if (cTicksToDeadline >= 128)
7158 { /* hopefully */ }
7159 else
7160 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionRecalcingDeadlineExpired);
7161 }
7162
7163 /* Make sure the returned values have sane upper and lower boundaries. */
7164 uint64_t const u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
7165 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64th of a second, 15.625ms. */ /** @todo r=bird: Once real+virtual timers move to separate thread, we can raise the upper limit (16ms isn't much). ASSUMES working poke cpu function. */
7166 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 32678); /* 1/32768th of a second, ~30us. */
7167 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
7168
7169 /** @todo r=ramshankar: We need to find a way to integrate nested-guest
7170 * preemption timers here. We probably need to clamp the preemption timer,
7171 * after converting the timer value to the host. */
7172 uint32_t const cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
7173 int rc = VMXWriteVmcs32(VMX_VMCS32_PREEMPT_TIMER_VALUE, cPreemptionTickCount);
7174 AssertRC(rc);
7175 }
7176 else
7177 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
7178
7179 if (fParavirtTsc)
7180 {
7181 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
7182 information before every VM-entry, hence disable it for performance sake. */
7183#if 0
7184 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
7185 AssertRC(rc);
7186#endif
7187 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
7188 }
7189
7190 if ( fOffsettedTsc
7191 && RT_LIKELY(!pVCpu->hmr0.s.fDebugWantRdTscExit))
7192 {
7193 if (pVmxTransient->fIsNestedGuest)
7194 uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
7195 hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
7196 hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
7197 }
7198 else
7199 {
7200 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
7201 hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
7202 }
7203}
7204
7205
7206/**
7207 * Gets the IEM exception flags for the specified vector and IDT vectoring /
7208 * VM-exit interruption info type.
7209 *
7210 * @returns The IEM exception flags.
7211 * @param uVector The event vector.
7212 * @param uVmxEventType The VMX event type.
7213 *
7214 * @remarks This function currently only constructs flags required for
7215 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
7216 * and CR2 aspects of an exception are not included).
7217 */
7218static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
7219{
7220 uint32_t fIemXcptFlags;
7221 switch (uVmxEventType)
7222 {
7223 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
7224 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
7225 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
7226 break;
7227
7228 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
7229 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
7230 break;
7231
7232 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
7233 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
7234 break;
7235
7236 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
7237 {
7238 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
7239 if (uVector == X86_XCPT_BP)
7240 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
7241 else if (uVector == X86_XCPT_OF)
7242 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
7243 else
7244 {
7245 fIemXcptFlags = 0;
7246 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
7247 }
7248 break;
7249 }
7250
7251 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
7252 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
7253 break;
7254
7255 default:
7256 fIemXcptFlags = 0;
7257 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
7258 break;
7259 }
7260 return fIemXcptFlags;
7261}
7262
7263
7264/**
7265 * Sets an event as a pending event to be injected into the guest.
7266 *
7267 * @param pVCpu The cross context virtual CPU structure.
7268 * @param u32IntInfo The VM-entry interruption-information field.
7269 * @param cbInstr The VM-entry instruction length in bytes (for
7270 * software interrupts, exceptions and privileged
7271 * software exceptions).
7272 * @param u32ErrCode The VM-entry exception error code.
7273 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
7274 * page-fault.
7275 */
7276DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPUCC pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
7277 RTGCUINTPTR GCPtrFaultAddress)
7278{
7279 Assert(!pVCpu->hm.s.Event.fPending);
7280 pVCpu->hm.s.Event.fPending = true;
7281 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
7282 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
7283 pVCpu->hm.s.Event.cbInstr = cbInstr;
7284 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
7285}
7286
7287
7288/**
7289 * Sets an external interrupt as pending-for-injection into the VM.
7290 *
7291 * @param pVCpu The cross context virtual CPU structure.
7292 * @param u8Interrupt The external interrupt vector.
7293 */
7294DECLINLINE(void) hmR0VmxSetPendingExtInt(PVMCPUCC pVCpu, uint8_t u8Interrupt)
7295{
7296 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
7297 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
7298 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7299 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7300 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7301}
7302
7303
7304/**
7305 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
7306 *
7307 * @param pVCpu The cross context virtual CPU structure.
7308 */
7309DECLINLINE(void) hmR0VmxSetPendingXcptNmi(PVMCPUCC pVCpu)
7310{
7311 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
7312 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
7313 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7314 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7315 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7316}
7317
7318
7319/**
7320 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
7321 *
7322 * @param pVCpu The cross context virtual CPU structure.
7323 */
7324DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPUCC pVCpu)
7325{
7326 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
7327 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7328 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7329 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7330 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7331}
7332
7333
7334/**
7335 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
7336 *
7337 * @param pVCpu The cross context virtual CPU structure.
7338 */
7339DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPUCC pVCpu)
7340{
7341 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
7342 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7343 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7344 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7345 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7346}
7347
7348
7349/**
7350 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
7351 *
7352 * @param pVCpu The cross context virtual CPU structure.
7353 */
7354DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPUCC pVCpu)
7355{
7356 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
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, 0)
7359 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7360 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7361}
7362
7363
7364#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7365/**
7366 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
7367 *
7368 * @param pVCpu The cross context virtual CPU structure.
7369 * @param u32ErrCode The error code for the general-protection exception.
7370 */
7371DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPUCC pVCpu, uint32_t u32ErrCode)
7372{
7373 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
7374 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7375 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7376 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7377 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
7378}
7379
7380
7381/**
7382 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
7383 *
7384 * @param pVCpu The cross context virtual CPU structure.
7385 * @param u32ErrCode The error code for the stack exception.
7386 */
7387DECLINLINE(void) hmR0VmxSetPendingXcptSS(PVMCPUCC pVCpu, uint32_t u32ErrCode)
7388{
7389 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
7390 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7391 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7392 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7393 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
7394}
7395#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
7396
7397
7398/**
7399 * Fixes up attributes for the specified segment register.
7400 *
7401 * @param pVCpu The cross context virtual CPU structure.
7402 * @param pSelReg The segment register that needs fixing.
7403 * @param pszRegName The register name (for logging and assertions).
7404 */
7405static void hmR0VmxFixUnusableSegRegAttr(PVMCPUCC pVCpu, PCPUMSELREG pSelReg, const char *pszRegName)
7406{
7407 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
7408
7409 /*
7410 * If VT-x marks the segment as unusable, most other bits remain undefined:
7411 * - For CS the L, D and G bits have meaning.
7412 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
7413 * - For the remaining data segments no bits are defined.
7414 *
7415 * The present bit and the unusable bit has been observed to be set at the
7416 * same time (the selector was supposed to be invalid as we started executing
7417 * a V8086 interrupt in ring-0).
7418 *
7419 * What should be important for the rest of the VBox code, is that the P bit is
7420 * cleared. Some of the other VBox code recognizes the unusable bit, but
7421 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
7422 * safe side here, we'll strip off P and other bits we don't care about. If
7423 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
7424 *
7425 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
7426 */
7427#ifdef VBOX_STRICT
7428 uint32_t const uAttr = pSelReg->Attr.u;
7429#endif
7430
7431 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
7432 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
7433 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
7434
7435#ifdef VBOX_STRICT
7436 VMMRZCallRing3Disable(pVCpu);
7437 Log4Func(("Unusable %s: sel=%#x attr=%#x -> %#x\n", pszRegName, pSelReg->Sel, uAttr, pSelReg->Attr.u));
7438# ifdef DEBUG_bird
7439 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
7440 ("%s: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
7441 pszRegName, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
7442# endif
7443 VMMRZCallRing3Enable(pVCpu);
7444 NOREF(uAttr);
7445#endif
7446 RT_NOREF2(pVCpu, pszRegName);
7447}
7448
7449
7450/**
7451 * Imports a guest segment register from the current VMCS into the guest-CPU
7452 * context.
7453 *
7454 * @param pVCpu The cross context virtual CPU structure.
7455 * @param iSegReg The segment register number (X86_SREG_XXX).
7456 *
7457 * @remarks Called with interrupts and/or preemption disabled.
7458 */
7459static void hmR0VmxImportGuestSegReg(PVMCPUCC pVCpu, uint32_t iSegReg)
7460{
7461 Assert(iSegReg < X86_SREG_COUNT);
7462 Assert((uint32_t)VMX_VMCS16_GUEST_SEG_SEL(iSegReg) == g_aVmcsSegSel[iSegReg]);
7463 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg) == g_aVmcsSegLimit[iSegReg]);
7464 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg) == g_aVmcsSegAttr[iSegReg]);
7465 Assert((uint32_t)VMX_VMCS_GUEST_SEG_BASE(iSegReg) == g_aVmcsSegBase[iSegReg]);
7466
7467 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
7468
7469 uint16_t u16Sel;
7470 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_SEG_SEL(iSegReg), &u16Sel); AssertRC(rc);
7471 pSelReg->Sel = u16Sel;
7472 pSelReg->ValidSel = u16Sel;
7473
7474 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg), &pSelReg->u32Limit); AssertRC(rc);
7475 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SEG_BASE(iSegReg), &pSelReg->u64Base); AssertRC(rc);
7476
7477 uint32_t u32Attr;
7478 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg), &u32Attr); AssertRC(rc);
7479 pSelReg->Attr.u = u32Attr;
7480 if (u32Attr & X86DESCATTR_UNUSABLE)
7481 hmR0VmxFixUnusableSegRegAttr(pVCpu, pSelReg, "ES\0CS\0SS\0DS\0FS\0GS" + iSegReg * 3);
7482
7483 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
7484}
7485
7486
7487/**
7488 * Imports the guest LDTR from the current VMCS into the guest-CPU context.
7489 *
7490 * @param pVCpu The cross context virtual CPU structure.
7491 *
7492 * @remarks Called with interrupts and/or preemption disabled.
7493 */
7494static void hmR0VmxImportGuestLdtr(PVMCPUCC pVCpu)
7495{
7496 uint16_t u16Sel;
7497 uint64_t u64Base;
7498 uint32_t u32Limit, u32Attr;
7499 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
7500 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
7501 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7502 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
7503
7504 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
7505 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
7506 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
7507 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
7508 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
7509 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
7510 if (u32Attr & X86DESCATTR_UNUSABLE)
7511 hmR0VmxFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, "LDTR");
7512}
7513
7514
7515/**
7516 * Imports the guest TR from the current VMCS into the guest-CPU context.
7517 *
7518 * @param pVCpu The cross context virtual CPU structure.
7519 *
7520 * @remarks Called with interrupts and/or preemption disabled.
7521 */
7522static void hmR0VmxImportGuestTr(PVMCPUCC pVCpu)
7523{
7524 uint16_t u16Sel;
7525 uint64_t u64Base;
7526 uint32_t u32Limit, u32Attr;
7527 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
7528 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
7529 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7530 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
7531
7532 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
7533 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
7534 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
7535 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
7536 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
7537 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
7538 /* TR is the only selector that can never be unusable. */
7539 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
7540}
7541
7542
7543/**
7544 * Imports the guest RIP from the VMCS back into the guest-CPU context.
7545 *
7546 * @param pVCpu The cross context virtual CPU structure.
7547 *
7548 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7549 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7550 * instead!!!
7551 */
7552static void hmR0VmxImportGuestRip(PVMCPUCC pVCpu)
7553{
7554 uint64_t u64Val;
7555 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7556 if (pCtx->fExtrn & CPUMCTX_EXTRN_RIP)
7557 {
7558 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
7559 AssertRC(rc);
7560
7561 pCtx->rip = u64Val;
7562 EMR0HistoryUpdatePC(pVCpu, pCtx->rip, false);
7563 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RIP;
7564 }
7565}
7566
7567
7568/**
7569 * Imports the guest RFLAGS from the VMCS back into the guest-CPU context.
7570 *
7571 * @param pVCpu The cross context virtual CPU structure.
7572 * @param pVmcsInfo The VMCS info. object.
7573 *
7574 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7575 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7576 * instead!!!
7577 */
7578static void hmR0VmxImportGuestRFlags(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7579{
7580 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7581 if (pCtx->fExtrn & CPUMCTX_EXTRN_RFLAGS)
7582 {
7583 uint64_t u64Val;
7584 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
7585 AssertRC(rc);
7586
7587 pCtx->rflags.u64 = u64Val;
7588 PCVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7589 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
7590 {
7591 pCtx->eflags.Bits.u1VM = 0;
7592 pCtx->eflags.Bits.u2IOPL = pVmcsInfoShared->RealMode.Eflags.Bits.u2IOPL;
7593 }
7594 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
7595 }
7596}
7597
7598
7599/**
7600 * Imports the guest interruptibility-state from the VMCS back into the guest-CPU
7601 * context.
7602 *
7603 * @param pVCpu The cross context virtual CPU structure.
7604 * @param pVmcsInfo The VMCS info. object.
7605 *
7606 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
7607 * do not log!
7608 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7609 * instead!!!
7610 */
7611static void hmR0VmxImportGuestIntrState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7612{
7613 uint32_t u32Val;
7614 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
7615 if (!u32Val)
7616 {
7617 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7618 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7619 CPUMSetGuestNmiBlocking(pVCpu, false);
7620 }
7621 else
7622 {
7623 /*
7624 * We must import RIP here to set our EM interrupt-inhibited state.
7625 * We also import RFLAGS as our code that evaluates pending interrupts
7626 * before VM-entry requires it.
7627 */
7628 hmR0VmxImportGuestRip(pVCpu);
7629 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7630
7631 if (u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
7632 EMSetInhibitInterruptsPC(pVCpu, pVCpu->cpum.GstCtx.rip);
7633 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7634 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7635
7636 bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
7637 CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
7638 }
7639}
7640
7641
7642/**
7643 * Worker for VMXR0ImportStateOnDemand.
7644 *
7645 * @returns VBox status code.
7646 * @param pVCpu The cross context virtual CPU structure.
7647 * @param pVmcsInfo The VMCS info. object.
7648 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7649 */
7650static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
7651{
7652 int rc = VINF_SUCCESS;
7653 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7654 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7655 uint32_t u32Val;
7656
7657 /*
7658 * Note! This is hack to workaround a mysterious BSOD observed with release builds
7659 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
7660 * neither are other host platforms.
7661 *
7662 * Committing this temporarily as it prevents BSOD.
7663 *
7664 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
7665 */
7666#ifdef RT_OS_WINDOWS
7667 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
7668 return VERR_HM_IPE_1;
7669#endif
7670
7671 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatImportGuestState, x);
7672
7673 /*
7674 * We disable interrupts to make the updating of the state and in particular
7675 * the fExtrn modification atomic wrt to preemption hooks.
7676 */
7677 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
7678
7679 fWhat &= pCtx->fExtrn;
7680 if (fWhat)
7681 {
7682 do
7683 {
7684 if (fWhat & CPUMCTX_EXTRN_RIP)
7685 hmR0VmxImportGuestRip(pVCpu);
7686
7687 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
7688 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7689
7690 if (fWhat & CPUMCTX_EXTRN_HM_VMX_INT_STATE)
7691 hmR0VmxImportGuestIntrState(pVCpu, pVmcsInfo);
7692
7693 if (fWhat & CPUMCTX_EXTRN_RSP)
7694 {
7695 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RSP, &pCtx->rsp);
7696 AssertRC(rc);
7697 }
7698
7699 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
7700 {
7701 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7702 bool const fRealOnV86Active = pVmcsInfoShared->RealMode.fRealOnV86Active;
7703 if (fWhat & CPUMCTX_EXTRN_CS)
7704 {
7705 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_CS);
7706 hmR0VmxImportGuestRip(pVCpu);
7707 if (fRealOnV86Active)
7708 pCtx->cs.Attr.u = pVmcsInfoShared->RealMode.AttrCS.u;
7709 EMR0HistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
7710 }
7711 if (fWhat & CPUMCTX_EXTRN_SS)
7712 {
7713 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_SS);
7714 if (fRealOnV86Active)
7715 pCtx->ss.Attr.u = pVmcsInfoShared->RealMode.AttrSS.u;
7716 }
7717 if (fWhat & CPUMCTX_EXTRN_DS)
7718 {
7719 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_DS);
7720 if (fRealOnV86Active)
7721 pCtx->ds.Attr.u = pVmcsInfoShared->RealMode.AttrDS.u;
7722 }
7723 if (fWhat & CPUMCTX_EXTRN_ES)
7724 {
7725 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_ES);
7726 if (fRealOnV86Active)
7727 pCtx->es.Attr.u = pVmcsInfoShared->RealMode.AttrES.u;
7728 }
7729 if (fWhat & CPUMCTX_EXTRN_FS)
7730 {
7731 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_FS);
7732 if (fRealOnV86Active)
7733 pCtx->fs.Attr.u = pVmcsInfoShared->RealMode.AttrFS.u;
7734 }
7735 if (fWhat & CPUMCTX_EXTRN_GS)
7736 {
7737 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_GS);
7738 if (fRealOnV86Active)
7739 pCtx->gs.Attr.u = pVmcsInfoShared->RealMode.AttrGS.u;
7740 }
7741 }
7742
7743 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
7744 {
7745 if (fWhat & CPUMCTX_EXTRN_LDTR)
7746 hmR0VmxImportGuestLdtr(pVCpu);
7747
7748 if (fWhat & CPUMCTX_EXTRN_GDTR)
7749 {
7750 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &pCtx->gdtr.pGdt); AssertRC(rc);
7751 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
7752 pCtx->gdtr.cbGdt = u32Val;
7753 }
7754
7755 /* Guest IDTR. */
7756 if (fWhat & CPUMCTX_EXTRN_IDTR)
7757 {
7758 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &pCtx->idtr.pIdt); AssertRC(rc);
7759 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
7760 pCtx->idtr.cbIdt = u32Val;
7761 }
7762
7763 /* Guest TR. */
7764 if (fWhat & CPUMCTX_EXTRN_TR)
7765 {
7766 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
7767 don't need to import that one. */
7768 if (!pVmcsInfo->pShared->RealMode.fRealOnV86Active)
7769 hmR0VmxImportGuestTr(pVCpu);
7770 }
7771 }
7772
7773 if (fWhat & CPUMCTX_EXTRN_DR7)
7774 {
7775 if (!pVCpu->hmr0.s.fUsingHyperDR7)
7776 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_DR7, &pCtx->dr[7]); AssertRC(rc);
7777 }
7778
7779 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
7780 {
7781 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, &pCtx->SysEnter.eip); AssertRC(rc);
7782 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, &pCtx->SysEnter.esp); AssertRC(rc);
7783 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
7784 pCtx->SysEnter.cs = u32Val;
7785 }
7786
7787 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
7788 {
7789 if ( pVM->hmr0.s.fAllow64BitGuests
7790 && (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7791 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
7792 }
7793
7794 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
7795 {
7796 if ( pVM->hmr0.s.fAllow64BitGuests
7797 && (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7798 {
7799 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
7800 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
7801 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
7802 }
7803 }
7804
7805 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
7806 {
7807 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7808 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
7809 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
7810 Assert(pMsrs);
7811 Assert(cMsrs <= VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc));
7812 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
7813 for (uint32_t i = 0; i < cMsrs; i++)
7814 {
7815 uint32_t const idMsr = pMsrs[i].u32Msr;
7816 switch (idMsr)
7817 {
7818 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
7819 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
7820 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
7821 default:
7822 {
7823 uint32_t idxLbrMsr;
7824 if (pVM->hmr0.s.vmx.fLbr)
7825 {
7826 if (hmR0VmxIsLbrBranchFromMsr(pVM, idMsr, &idxLbrMsr))
7827 {
7828 Assert(idxLbrMsr < RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr));
7829 pVmcsInfoShared->au64LbrFromIpMsr[idxLbrMsr] = pMsrs[i].u64Value;
7830 break;
7831 }
7832 if (hmR0VmxIsLbrBranchToMsr(pVM, idMsr, &idxLbrMsr))
7833 {
7834 Assert(idxLbrMsr < RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr));
7835 pVmcsInfoShared->au64LbrToIpMsr[idxLbrMsr] = pMsrs[i].u64Value;
7836 break;
7837 }
7838 if (idMsr == pVM->hmr0.s.vmx.idLbrTosMsr)
7839 {
7840 pVmcsInfoShared->u64LbrTosMsr = pMsrs[i].u64Value;
7841 break;
7842 }
7843 /* Fallthru (no break) */
7844 }
7845 pCtx->fExtrn = 0;
7846 pVCpu->hm.s.u32HMError = pMsrs->u32Msr;
7847 ASMSetFlags(fEFlags);
7848 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
7849 return VERR_HM_UNEXPECTED_LD_ST_MSR;
7850 }
7851 }
7852 }
7853 }
7854
7855 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
7856 {
7857 if (fWhat & CPUMCTX_EXTRN_CR0)
7858 {
7859 uint64_t u64Cr0;
7860 uint64_t u64Shadow;
7861 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Cr0); AssertRC(rc);
7862 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Shadow); AssertRC(rc);
7863#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
7864 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7865 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7866#else
7867 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
7868 {
7869 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7870 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7871 }
7872 else
7873 {
7874 /*
7875 * We've merged the guest and nested-guest's CR0 guest/host mask while executing
7876 * the nested-guest using hardware-assisted VMX. Accordingly we need to
7877 * re-construct CR0. See @bugref{9180#c95} for details.
7878 */
7879 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
7880 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
7881 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7882 | (pVmcsNstGst->u64GuestCr0.u & pVmcsNstGst->u64Cr0Mask.u)
7883 | (u64Shadow & (pVmcsInfoGst->u64Cr0Mask & ~pVmcsNstGst->u64Cr0Mask.u));
7884 }
7885#endif
7886 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
7887 CPUMSetGuestCR0(pVCpu, u64Cr0);
7888 VMMRZCallRing3Enable(pVCpu);
7889 }
7890
7891 if (fWhat & CPUMCTX_EXTRN_CR4)
7892 {
7893 uint64_t u64Cr4;
7894 uint64_t u64Shadow;
7895 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64Cr4); AssertRC(rc);
7896 rc |= VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Shadow); AssertRC(rc);
7897#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
7898 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7899 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7900#else
7901 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
7902 {
7903 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7904 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7905 }
7906 else
7907 {
7908 /*
7909 * We've merged the guest and nested-guest's CR4 guest/host mask while executing
7910 * the nested-guest using hardware-assisted VMX. Accordingly we need to
7911 * re-construct CR4. See @bugref{9180#c95} for details.
7912 */
7913 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
7914 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
7915 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7916 | (pVmcsNstGst->u64GuestCr4.u & pVmcsNstGst->u64Cr4Mask.u)
7917 | (u64Shadow & (pVmcsInfoGst->u64Cr4Mask & ~pVmcsNstGst->u64Cr4Mask.u));
7918 }
7919#endif
7920 pCtx->cr4 = u64Cr4;
7921 }
7922
7923 if (fWhat & CPUMCTX_EXTRN_CR3)
7924 {
7925 /* CR0.PG bit changes are always intercepted, so it's up to date. */
7926 if ( pVM->hmr0.s.vmx.fUnrestrictedGuest
7927 || ( pVM->hmr0.s.fNestedPaging
7928 && CPUMIsGuestPagingEnabledEx(pCtx)))
7929 {
7930 uint64_t u64Cr3;
7931 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR3, &u64Cr3); AssertRC(rc);
7932 if (pCtx->cr3 != u64Cr3)
7933 {
7934 pCtx->cr3 = u64Cr3;
7935 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7936 }
7937
7938 /* If the guest is in PAE mode, sync back the PDPE's into the guest state.
7939 Note: CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date. */
7940 if (CPUMIsGuestInPAEModeEx(pCtx))
7941 {
7942 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &pVCpu->hm.s.aPdpes[0].u); AssertRC(rc);
7943 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &pVCpu->hm.s.aPdpes[1].u); AssertRC(rc);
7944 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &pVCpu->hm.s.aPdpes[2].u); AssertRC(rc);
7945 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &pVCpu->hm.s.aPdpes[3].u); AssertRC(rc);
7946 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
7947 }
7948 }
7949 }
7950 }
7951
7952#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7953 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
7954 {
7955 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7956 && !CPUMIsGuestInVmxNonRootMode(pCtx))
7957 {
7958 Assert(CPUMIsGuestInVmxRootMode(pCtx));
7959 rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
7960 if (RT_SUCCESS(rc))
7961 { /* likely */ }
7962 else
7963 break;
7964 }
7965 }
7966#endif
7967 } while (0);
7968
7969 if (RT_SUCCESS(rc))
7970 {
7971 /* Update fExtrn. */
7972 pCtx->fExtrn &= ~fWhat;
7973
7974 /* If everything has been imported, clear the HM keeper bit. */
7975 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
7976 {
7977 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
7978 Assert(!pCtx->fExtrn);
7979 }
7980 }
7981 }
7982 else
7983 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
7984
7985 /*
7986 * Restore interrupts.
7987 */
7988 ASMSetFlags(fEFlags);
7989
7990 STAM_PROFILE_ADV_STOP(& pVCpu->hm.s.StatImportGuestState, x);
7991
7992 if (RT_SUCCESS(rc))
7993 { /* likely */ }
7994 else
7995 return rc;
7996
7997 /*
7998 * Honor any pending CR3 updates.
7999 *
8000 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> VMXR0CallRing3Callback()
8001 * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
8002 * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
8003 *
8004 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
8005 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
8006 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
8007 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
8008 *
8009 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
8010 */
8011 if (VMMRZCallRing3IsEnabled(pVCpu))
8012 {
8013 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
8014 {
8015 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
8016 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
8017 }
8018
8019 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
8020 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
8021
8022 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
8023 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
8024 }
8025
8026 return VINF_SUCCESS;
8027}
8028
8029
8030/**
8031 * Saves the guest state from the VMCS into the guest-CPU context.
8032 *
8033 * @returns VBox status code.
8034 * @param pVCpu The cross context virtual CPU structure.
8035 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
8036 */
8037VMMR0DECL(int) VMXR0ImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat)
8038{
8039 AssertPtr(pVCpu);
8040 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8041 return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
8042}
8043
8044
8045/**
8046 * Check per-VM and per-VCPU force flag actions that require us to go back to
8047 * ring-3 for one reason or another.
8048 *
8049 * @returns Strict VBox status code (i.e. informational status codes too)
8050 * @retval VINF_SUCCESS if we don't have any actions that require going back to
8051 * ring-3.
8052 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
8053 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
8054 * interrupts)
8055 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
8056 * all EMTs to be in ring-3.
8057 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
8058 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
8059 * to the EM loop.
8060 *
8061 * @param pVCpu The cross context virtual CPU structure.
8062 * @param pVmxTransient The VMX-transient structure.
8063 * @param fStepping Whether we are single-stepping the guest using the
8064 * hypervisor debugger.
8065 *
8066 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
8067 * is no longer in VMX non-root mode.
8068 */
8069static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, bool fStepping)
8070{
8071 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8072
8073 /*
8074 * Update pending interrupts into the APIC's IRR.
8075 */
8076 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
8077 APICUpdatePendingInterrupts(pVCpu);
8078
8079 /*
8080 * Anything pending? Should be more likely than not if we're doing a good job.
8081 */
8082 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8083 if ( !fStepping
8084 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
8085 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
8086 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
8087 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
8088 return VINF_SUCCESS;
8089
8090 /* Pending PGM C3 sync. */
8091 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
8092 {
8093 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8094 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
8095 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
8096 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
8097 if (rcStrict != VINF_SUCCESS)
8098 {
8099 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
8100 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
8101 return rcStrict;
8102 }
8103 }
8104
8105 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
8106 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
8107 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
8108 {
8109 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
8110 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
8111 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
8112 return rc;
8113 }
8114
8115 /* Pending VM request packets, such as hardware interrupts. */
8116 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
8117 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
8118 {
8119 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchVmReq);
8120 Log4Func(("Pending VM request forcing us back to ring-3\n"));
8121 return VINF_EM_PENDING_REQUEST;
8122 }
8123
8124 /* Pending PGM pool flushes. */
8125 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
8126 {
8127 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPgmPoolFlush);
8128 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
8129 return VINF_PGM_POOL_FLUSH_PENDING;
8130 }
8131
8132 /* Pending DMA requests. */
8133 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
8134 {
8135 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchDma);
8136 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
8137 return VINF_EM_RAW_TO_R3;
8138 }
8139
8140#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8141 /*
8142 * Pending nested-guest events.
8143 *
8144 * Please note the priority of these events are specified and important.
8145 * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
8146 * See Intel spec. 6.9 "Priority Among Simultaneous Exceptions And Interrupts".
8147 */
8148 if (pVmxTransient->fIsNestedGuest)
8149 {
8150 /* Pending nested-guest APIC-write. */
8151 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
8152 {
8153 Log4Func(("Pending nested-guest APIC-write\n"));
8154 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
8155 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8156 return rcStrict;
8157 }
8158
8159 /* Pending nested-guest monitor-trap flag (MTF). */
8160 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF))
8161 {
8162 Log4Func(("Pending nested-guest MTF\n"));
8163 VBOXSTRICTRC rcStrict = IEMExecVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* uExitQual */);
8164 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8165 return rcStrict;
8166 }
8167
8168 /* Pending nested-guest VMX-preemption timer expired. */
8169 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))
8170 {
8171 Log4Func(("Pending nested-guest MTF\n"));
8172 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitPreemptTimer(pVCpu);
8173 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8174 return rcStrict;
8175 }
8176 }
8177#else
8178 NOREF(pVmxTransient);
8179#endif
8180
8181 return VINF_SUCCESS;
8182}
8183
8184
8185/**
8186 * Converts any TRPM trap into a pending HM event. This is typically used when
8187 * entering from ring-3 (not longjmp returns).
8188 *
8189 * @param pVCpu The cross context virtual CPU structure.
8190 */
8191static void hmR0VmxTrpmTrapToPendingEvent(PVMCPUCC pVCpu)
8192{
8193 Assert(TRPMHasTrap(pVCpu));
8194 Assert(!pVCpu->hm.s.Event.fPending);
8195
8196 uint8_t uVector;
8197 TRPMEVENT enmTrpmEvent;
8198 uint32_t uErrCode;
8199 RTGCUINTPTR GCPtrFaultAddress;
8200 uint8_t cbInstr;
8201 bool fIcebp;
8202
8203 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr, &fIcebp);
8204 AssertRC(rc);
8205
8206 uint32_t u32IntInfo;
8207 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
8208 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent, fIcebp);
8209
8210 rc = TRPMResetTrap(pVCpu);
8211 AssertRC(rc);
8212 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
8213 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
8214
8215 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
8216}
8217
8218
8219/**
8220 * Converts the pending HM event into a TRPM trap.
8221 *
8222 * @param pVCpu The cross context virtual CPU structure.
8223 */
8224static void hmR0VmxPendingEventToTrpmTrap(PVMCPUCC pVCpu)
8225{
8226 Assert(pVCpu->hm.s.Event.fPending);
8227
8228 /* If a trap was already pending, we did something wrong! */
8229 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
8230
8231 uint32_t const u32IntInfo = pVCpu->hm.s.Event.u64IntInfo;
8232 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
8233 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
8234
8235 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
8236
8237 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
8238 AssertRC(rc);
8239
8240 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8241 TRPMSetErrorCode(pVCpu, pVCpu->hm.s.Event.u32ErrCode);
8242
8243 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
8244 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
8245 else
8246 {
8247 uint8_t const uVectorType = VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo);
8248 switch (uVectorType)
8249 {
8250 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
8251 TRPMSetTrapDueToIcebp(pVCpu);
8252 RT_FALL_THRU();
8253 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
8254 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
8255 {
8256 AssertMsg( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
8257 || ( uVector == X86_XCPT_BP /* INT3 */
8258 || uVector == X86_XCPT_OF /* INTO */
8259 || uVector == X86_XCPT_DB /* INT1 (ICEBP) */),
8260 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
8261 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
8262 break;
8263 }
8264 }
8265 }
8266
8267 /* We're now done converting the pending event. */
8268 pVCpu->hm.s.Event.fPending = false;
8269}
8270
8271
8272/**
8273 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
8274 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
8275 *
8276 * @param pVmcsInfo The VMCS info. object.
8277 */
8278static void hmR0VmxSetIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8279{
8280 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
8281 {
8282 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
8283 {
8284 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
8285 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8286 AssertRC(rc);
8287 }
8288 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
8289}
8290
8291
8292/**
8293 * Clears the interrupt-window exiting control in the VMCS.
8294 *
8295 * @param pVmcsInfo The VMCS info. object.
8296 */
8297DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8298{
8299 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
8300 {
8301 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
8302 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8303 AssertRC(rc);
8304 }
8305}
8306
8307
8308/**
8309 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
8310 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
8311 *
8312 * @param pVmcsInfo The VMCS info. object.
8313 */
8314static void hmR0VmxSetNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8315{
8316 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
8317 {
8318 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
8319 {
8320 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
8321 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8322 AssertRC(rc);
8323 Log4Func(("Setup NMI-window exiting\n"));
8324 }
8325 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
8326}
8327
8328
8329/**
8330 * Clears the NMI-window exiting control in the VMCS.
8331 *
8332 * @param pVmcsInfo The VMCS info. object.
8333 */
8334DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8335{
8336 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
8337 {
8338 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
8339 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8340 AssertRC(rc);
8341 }
8342}
8343
8344
8345/**
8346 * Does the necessary state syncing before returning to ring-3 for any reason
8347 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
8348 *
8349 * @returns VBox status code.
8350 * @param pVCpu The cross context virtual CPU structure.
8351 * @param fImportState Whether to import the guest state from the VMCS back
8352 * to the guest-CPU context.
8353 *
8354 * @remarks No-long-jmp zone!!!
8355 */
8356static int hmR0VmxLeave(PVMCPUCC pVCpu, bool fImportState)
8357{
8358 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8359 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8360
8361 RTCPUID const idCpu = RTMpCpuId();
8362 Log4Func(("HostCpuId=%u\n", idCpu));
8363
8364 /*
8365 * !!! IMPORTANT !!!
8366 * If you modify code here, check whether VMXR0CallRing3Callback() needs to be updated too.
8367 */
8368
8369 /* Save the guest state if necessary. */
8370 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8371 if (fImportState)
8372 {
8373 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8374 AssertRCReturn(rc, rc);
8375 }
8376
8377 /* Restore host FPU state if necessary. We will resync on next R0 reentry. */
8378 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8379 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
8380
8381 /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
8382#ifdef VBOX_STRICT
8383 if (CPUMIsHyperDebugStateActive(pVCpu))
8384 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
8385#endif
8386 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8387 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
8388 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
8389
8390 /* Restore host-state bits that VT-x only restores partially. */
8391 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
8392 {
8393 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hmr0.s.vmx.fRestoreHostFlags, idCpu));
8394 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
8395 }
8396 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
8397
8398 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8399 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8400 {
8401 /* We shouldn't restore the host MSRs without saving the guest MSRs first. */
8402 if (!fImportState)
8403 {
8404 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS);
8405 AssertRCReturn(rc, rc);
8406 }
8407 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8408 Assert(!pVCpu->hmr0.s.vmx.fLazyMsrs);
8409 }
8410 else
8411 pVCpu->hmr0.s.vmx.fLazyMsrs = 0;
8412
8413 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8414 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
8415
8416 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
8417 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatImportGuestState);
8418 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExportGuestState);
8419 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatPreExit);
8420 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitHandling);
8421 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
8422 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
8423 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
8424 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitVmentry);
8425 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8426
8427 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8428
8429 /** @todo This partially defeats the purpose of having preemption hooks.
8430 * The problem is, deregistering the hooks should be moved to a place that
8431 * lasts until the EMT is about to be destroyed not everytime while leaving HM
8432 * context.
8433 */
8434 int rc = hmR0VmxClearVmcs(pVmcsInfo);
8435 AssertRCReturn(rc, rc);
8436
8437#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8438 /*
8439 * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
8440 * clear a shadow VMCS before allowing that VMCS to become active on another
8441 * logical processor. We may or may not be importing guest state which clears
8442 * it, so cover for it here.
8443 *
8444 * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
8445 */
8446 if ( pVmcsInfo->pvShadowVmcs
8447 && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
8448 {
8449 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
8450 AssertRCReturn(rc, rc);
8451 }
8452
8453 /*
8454 * Flag that we need to re-export the host state if we switch to this VMCS before
8455 * executing guest or nested-guest code.
8456 */
8457 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
8458#endif
8459
8460 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
8461 NOREF(idCpu);
8462 return VINF_SUCCESS;
8463}
8464
8465
8466/**
8467 * Leaves the VT-x session.
8468 *
8469 * @returns VBox status code.
8470 * @param pVCpu The cross context virtual CPU structure.
8471 *
8472 * @remarks No-long-jmp zone!!!
8473 */
8474static int hmR0VmxLeaveSession(PVMCPUCC pVCpu)
8475{
8476 HM_DISABLE_PREEMPT(pVCpu);
8477 HMVMX_ASSERT_CPU_SAFE(pVCpu);
8478 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8479 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8480
8481 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
8482 and done this from the VMXR0ThreadCtxCallback(). */
8483 if (!pVCpu->hmr0.s.fLeaveDone)
8484 {
8485 int rc2 = hmR0VmxLeave(pVCpu, true /* fImportState */);
8486 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
8487 pVCpu->hmr0.s.fLeaveDone = true;
8488 }
8489 Assert(!pVCpu->cpum.GstCtx.fExtrn);
8490
8491 /*
8492 * !!! IMPORTANT !!!
8493 * If you modify code here, make sure to check whether VMXR0CallRing3Callback() needs to be updated too.
8494 */
8495
8496 /* Deregister hook now that we've left HM context before re-enabling preemption. */
8497 /** @todo Deregistering here means we need to VMCLEAR always
8498 * (longjmp/exit-to-r3) in VT-x which is not efficient, eliminate need
8499 * for calling VMMR0ThreadCtxHookDisable here! */
8500 VMMR0ThreadCtxHookDisable(pVCpu);
8501
8502 /* Leave HM context. This takes care of local init (term) and deregistering the longjmp-to-ring-3 callback. */
8503 int rc = HMR0LeaveCpu(pVCpu);
8504 HM_RESTORE_PREEMPT();
8505 return rc;
8506}
8507
8508
8509/**
8510 * Does the necessary state syncing before doing a longjmp to ring-3.
8511 *
8512 * @returns VBox status code.
8513 * @param pVCpu The cross context virtual CPU structure.
8514 *
8515 * @remarks No-long-jmp zone!!!
8516 */
8517DECLINLINE(int) hmR0VmxLongJmpToRing3(PVMCPUCC pVCpu)
8518{
8519 return hmR0VmxLeaveSession(pVCpu);
8520}
8521
8522
8523/**
8524 * Take necessary actions before going back to ring-3.
8525 *
8526 * An action requires us to go back to ring-3. This function does the necessary
8527 * steps before we can safely return to ring-3. This is not the same as longjmps
8528 * to ring-3, this is voluntary and prepares the guest so it may continue
8529 * executing outside HM (recompiler/IEM).
8530 *
8531 * @returns VBox status code.
8532 * @param pVCpu The cross context virtual CPU structure.
8533 * @param rcExit The reason for exiting to ring-3. Can be
8534 * VINF_VMM_UNKNOWN_RING3_CALL.
8535 */
8536static int hmR0VmxExitToRing3(PVMCPUCC pVCpu, VBOXSTRICTRC rcExit)
8537{
8538 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8539
8540 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8541 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
8542 {
8543 VMXGetCurrentVmcs(&pVCpu->hm.s.vmx.LastError.HCPhysCurrentVmcs);
8544 pVCpu->hm.s.vmx.LastError.u32VmcsRev = *(uint32_t *)pVmcsInfo->pvVmcs;
8545 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hmr0.s.idEnteredCpu;
8546 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
8547 }
8548
8549 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
8550 VMMRZCallRing3Disable(pVCpu);
8551 Log4Func(("rcExit=%d\n", VBOXSTRICTRC_VAL(rcExit)));
8552
8553 /*
8554 * Convert any pending HM events back to TRPM due to premature exits to ring-3.
8555 * We need to do this only on returns to ring-3 and not for longjmps to ring3.
8556 *
8557 * This is because execution may continue from ring-3 and we would need to inject
8558 * the event from there (hence place it back in TRPM).
8559 */
8560 if (pVCpu->hm.s.Event.fPending)
8561 {
8562 hmR0VmxPendingEventToTrpmTrap(pVCpu);
8563 Assert(!pVCpu->hm.s.Event.fPending);
8564
8565 /* Clear the events from the VMCS. */
8566 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
8567 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, 0); AssertRC(rc);
8568 }
8569#ifdef VBOX_STRICT
8570 /*
8571 * We check for rcExit here since for errors like VERR_VMX_UNABLE_TO_START_VM (which are
8572 * fatal), we don't care about verifying duplicate injection of events. Errors like
8573 * VERR_EM_INTERPRET are converted to their VINF_* counterparts -prior- to calling this
8574 * function so those should and will be checked below.
8575 */
8576 else if (RT_SUCCESS(rcExit))
8577 {
8578 /*
8579 * Ensure we don't accidentally clear a pending HM event without clearing the VMCS.
8580 * This can be pretty hard to debug otherwise, interrupts might get injected twice
8581 * occasionally, see @bugref{9180#c42}.
8582 *
8583 * However, if the VM-entry failed, any VM entry-interruption info. field would
8584 * be left unmodified as the event would not have been injected to the guest. In
8585 * such cases, don't assert, we're not going to continue guest execution anyway.
8586 */
8587 uint32_t uExitReason;
8588 uint32_t uEntryIntInfo;
8589 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8590 rc |= VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &uEntryIntInfo);
8591 AssertRC(rc);
8592 AssertMsg(VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason) || !VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo),
8593 ("uExitReason=%#RX32 uEntryIntInfo=%#RX32 rcExit=%d\n", uExitReason, uEntryIntInfo, VBOXSTRICTRC_VAL(rcExit)));
8594 }
8595#endif
8596
8597 /*
8598 * Clear the interrupt-window and NMI-window VMCS controls as we could have got
8599 * a VM-exit with higher priority than interrupt-window or NMI-window VM-exits
8600 * (e.g. TPR below threshold).
8601 */
8602 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8603 {
8604 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
8605 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
8606 }
8607
8608 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
8609 and if we're injecting an event we should have a TRPM trap pending. */
8610 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8611#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a triple fault in progress. */
8612 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8613#endif
8614
8615 /* Save guest state and restore host state bits. */
8616 int rc = hmR0VmxLeaveSession(pVCpu);
8617 AssertRCReturn(rc, rc);
8618 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8619
8620 /* Thread-context hooks are unregistered at this point!!! */
8621 /* Ring-3 callback notifications are unregistered at this point!!! */
8622
8623 /* Sync recompiler state. */
8624 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
8625 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
8626 | CPUM_CHANGED_LDTR
8627 | CPUM_CHANGED_GDTR
8628 | CPUM_CHANGED_IDTR
8629 | CPUM_CHANGED_TR
8630 | CPUM_CHANGED_HIDDEN_SEL_REGS);
8631 if ( pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging
8632 && CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx))
8633 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
8634
8635 Assert(!pVCpu->hmr0.s.fClearTrapFlag);
8636
8637 /* Update the exit-to-ring 3 reason. */
8638 pVCpu->hm.s.rcLastExitToR3 = VBOXSTRICTRC_VAL(rcExit);
8639
8640 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
8641 if ( rcExit != VINF_EM_RAW_INTERRUPT
8642 || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8643 {
8644 Assert(!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL));
8645 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
8646 }
8647
8648 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
8649 VMMRZCallRing3Enable(pVCpu);
8650 return rc;
8651}
8652
8653
8654/**
8655 * VMMRZCallRing3() callback wrapper which saves the guest state before we
8656 * longjump to ring-3 and possibly get preempted.
8657 *
8658 * @returns VBox status code.
8659 * @param pVCpu The cross context virtual CPU structure.
8660 * @param enmOperation The operation causing the ring-3 longjump.
8661 */
8662VMMR0DECL(int) VMXR0CallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation)
8663{
8664 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
8665 {
8666 /*
8667 * !!! IMPORTANT !!!
8668 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
8669 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
8670 */
8671 VMMRZCallRing3RemoveNotification(pVCpu);
8672 VMMRZCallRing3Disable(pVCpu);
8673 HM_DISABLE_PREEMPT(pVCpu);
8674
8675 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8676 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8677 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8678 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8679
8680 /* Restore host-state bits that VT-x only restores partially. */
8681 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
8682 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
8683 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
8684
8685 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8686 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8687 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8688
8689 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8690 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
8691 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8692
8693 /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
8694 cleared as part of importing the guest state above. */
8695 hmR0VmxClearVmcs(pVmcsInfo);
8696
8697 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
8698 VMMR0ThreadCtxHookDisable(pVCpu);
8699
8700 /* Leave HM context. This takes care of local init (term). */
8701 HMR0LeaveCpu(pVCpu);
8702 HM_RESTORE_PREEMPT();
8703 return VINF_SUCCESS;
8704 }
8705
8706 Assert(pVCpu);
8707 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8708 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8709
8710 VMMRZCallRing3Disable(pVCpu);
8711 Assert(VMMR0IsLogFlushDisabled(pVCpu));
8712
8713 Log4Func(("-> hmR0VmxLongJmpToRing3 enmOperation=%d\n", enmOperation));
8714
8715 int rc = hmR0VmxLongJmpToRing3(pVCpu);
8716 AssertRCReturn(rc, rc);
8717
8718 VMMRZCallRing3Enable(pVCpu);
8719 return VINF_SUCCESS;
8720}
8721
8722
8723/**
8724 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8725 * stack.
8726 *
8727 * @returns Strict VBox status code (i.e. informational status codes too).
8728 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8729 * @param pVCpu The cross context virtual CPU structure.
8730 * @param uValue The value to push to the guest stack.
8731 */
8732static VBOXSTRICTRC hmR0VmxRealModeGuestStackPush(PVMCPUCC pVCpu, uint16_t uValue)
8733{
8734 /*
8735 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8736 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8737 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8738 */
8739 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8740 if (pCtx->sp == 1)
8741 return VINF_EM_RESET;
8742 pCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8743 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pCtx->ss.u64Base + pCtx->sp, &uValue, sizeof(uint16_t));
8744 AssertRC(rc);
8745 return rc;
8746}
8747
8748
8749/**
8750 * Injects an event into the guest upon VM-entry by updating the relevant fields
8751 * in the VM-entry area in the VMCS.
8752 *
8753 * @returns Strict VBox status code (i.e. informational status codes too).
8754 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8755 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8756 *
8757 * @param pVCpu The cross context virtual CPU structure.
8758 * @param pVmxTransient The VMX-transient structure.
8759 * @param pEvent The event being injected.
8760 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
8761 * will be updated if necessary. This cannot not be NULL.
8762 * @param fStepping Whether we're single-stepping guest execution and should
8763 * return VINF_EM_DBG_STEPPED if the event is injected
8764 * directly (registers modified by us, not by hardware on
8765 * VM-entry).
8766 */
8767static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PCHMEVENT pEvent, bool fStepping,
8768 uint32_t *pfIntrState)
8769{
8770 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8771 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
8772 Assert(pfIntrState);
8773
8774 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8775 uint32_t u32IntInfo = pEvent->u64IntInfo;
8776 uint32_t const u32ErrCode = pEvent->u32ErrCode;
8777 uint32_t const cbInstr = pEvent->cbInstr;
8778 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
8779 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
8780 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
8781
8782#ifdef VBOX_STRICT
8783 /*
8784 * Validate the error-code-valid bit for hardware exceptions.
8785 * No error codes for exceptions in real-mode.
8786 *
8787 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8788 */
8789 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8790 && !CPUMIsGuestInRealModeEx(pCtx))
8791 {
8792 switch (uVector)
8793 {
8794 case X86_XCPT_PF:
8795 case X86_XCPT_DF:
8796 case X86_XCPT_TS:
8797 case X86_XCPT_NP:
8798 case X86_XCPT_SS:
8799 case X86_XCPT_GP:
8800 case X86_XCPT_AC:
8801 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
8802 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8803 RT_FALL_THRU();
8804 default:
8805 break;
8806 }
8807 }
8808
8809 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8810 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
8811 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8812#endif
8813
8814 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8815 || uIntType == VMX_EXIT_INT_INFO_TYPE_NMI
8816 || uIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT
8817 || uIntType == VMX_EXIT_INT_INFO_TYPE_SW_XCPT)
8818 {
8819 Assert(uVector <= X86_XCPT_LAST);
8820 Assert(uIntType != VMX_EXIT_INT_INFO_TYPE_NMI || uVector == X86_XCPT_NMI);
8821 Assert(uIntType != VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT || uVector == X86_XCPT_DB);
8822 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedXcptsR0[uVector]);
8823 }
8824 else
8825 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[uVector & MASK_INJECT_IRQ_STAT]);
8826
8827 /*
8828 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
8829 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
8830 * interrupt handler in the (real-mode) guest.
8831 *
8832 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
8833 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8834 */
8835 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
8836 {
8837 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest)
8838 {
8839 /*
8840 * For CPUs with unrestricted guest execution enabled and with the guest
8841 * in real-mode, we must not set the deliver-error-code bit.
8842 *
8843 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8844 */
8845 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
8846 }
8847 else
8848 {
8849 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8850 Assert(PDMVmmDevHeapIsEnabled(pVM));
8851 Assert(pVM->hm.s.vmx.pRealModeTSS);
8852 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
8853
8854 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
8855 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8856 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
8857 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
8858 AssertRCReturn(rc2, rc2);
8859
8860 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8861 size_t const cbIdtEntry = sizeof(X86IDTR16);
8862 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
8863 {
8864 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8865 if (uVector == X86_XCPT_DF)
8866 return VINF_EM_RESET;
8867
8868 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
8869 No error codes for exceptions in real-mode. */
8870 if (uVector == X86_XCPT_GP)
8871 {
8872 uint32_t const uXcptDfInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
8873 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8874 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8875 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8876 HMEVENT EventXcptDf;
8877 RT_ZERO(EventXcptDf);
8878 EventXcptDf.u64IntInfo = uXcptDfInfo;
8879 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptDf, fStepping, pfIntrState);
8880 }
8881
8882 /*
8883 * If we're injecting an event with no valid IDT entry, inject a #GP.
8884 * No error codes for exceptions in real-mode.
8885 *
8886 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8887 */
8888 uint32_t const uXcptGpInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
8889 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8890 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8891 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8892 HMEVENT EventXcptGp;
8893 RT_ZERO(EventXcptGp);
8894 EventXcptGp.u64IntInfo = uXcptGpInfo;
8895 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptGp, fStepping, pfIntrState);
8896 }
8897
8898 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8899 uint16_t uGuestIp = pCtx->ip;
8900 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
8901 {
8902 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8903 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8904 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8905 }
8906 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
8907 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8908
8909 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8910 X86IDTR16 IdtEntry;
8911 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
8912 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8913 AssertRCReturn(rc2, rc2);
8914
8915 /* Construct the stack frame for the interrupt/exception handler. */
8916 VBOXSTRICTRC rcStrict;
8917 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->eflags.u32);
8918 if (rcStrict == VINF_SUCCESS)
8919 {
8920 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
8921 if (rcStrict == VINF_SUCCESS)
8922 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
8923 }
8924
8925 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8926 if (rcStrict == VINF_SUCCESS)
8927 {
8928 pCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8929 pCtx->rip = IdtEntry.offSel;
8930 pCtx->cs.Sel = IdtEntry.uSel;
8931 pCtx->cs.ValidSel = IdtEntry.uSel;
8932 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8933 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
8934 && uVector == X86_XCPT_PF)
8935 pCtx->cr2 = GCPtrFault;
8936
8937 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
8938 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8939 | HM_CHANGED_GUEST_RSP);
8940
8941 /*
8942 * If we delivered a hardware exception (other than an NMI) and if there was
8943 * block-by-STI in effect, we should clear it.
8944 */
8945 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8946 {
8947 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
8948 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
8949 Log4Func(("Clearing inhibition due to STI\n"));
8950 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
8951 }
8952
8953 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8954 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
8955
8956 /*
8957 * The event has been truly dispatched to the guest. Mark it as no longer pending so
8958 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
8959 */
8960 pVCpu->hm.s.Event.fPending = false;
8961
8962 /*
8963 * If we eventually support nested-guest execution without unrestricted guest execution,
8964 * we should set fInterceptEvents here.
8965 */
8966 Assert(!pVmxTransient->fIsNestedGuest);
8967
8968 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
8969 if (fStepping)
8970 rcStrict = VINF_EM_DBG_STEPPED;
8971 }
8972 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8973 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8974 return rcStrict;
8975 }
8976 }
8977
8978 /*
8979 * Validate.
8980 */
8981 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8982 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
8983
8984 /*
8985 * Inject the event into the VMCS.
8986 */
8987 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8988 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8989 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8990 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8991 AssertRC(rc);
8992
8993 /*
8994 * Update guest CR2 if this is a page-fault.
8995 */
8996 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
8997 pCtx->cr2 = GCPtrFault;
8998
8999 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
9000 return VINF_SUCCESS;
9001}
9002
9003
9004/**
9005 * Evaluates the event to be delivered to the guest and sets it as the pending
9006 * event.
9007 *
9008 * Toggling of interrupt force-flags here is safe since we update TRPM on premature
9009 * exits to ring-3 before executing guest code, see hmR0VmxExitToRing3(). We must
9010 * NOT restore these force-flags.
9011 *
9012 * @returns Strict VBox status code (i.e. informational status codes too).
9013 * @param pVCpu The cross context virtual CPU structure.
9014 * @param pVmxTransient The VMX-transient structure.
9015 * @param pfIntrState Where to store the VT-x guest-interruptibility state.
9016 */
9017static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
9018{
9019 Assert(pfIntrState);
9020 Assert(!TRPMHasTrap(pVCpu));
9021
9022 /*
9023 * Compute/update guest-interruptibility state related FFs.
9024 * The FFs will be used below while evaluating events to be injected.
9025 */
9026 *pfIntrState = hmR0VmxGetGuestIntrStateAndUpdateFFs(pVCpu);
9027
9028 /*
9029 * Evaluate if a new event needs to be injected.
9030 * An event that's already pending has already performed all necessary checks.
9031 */
9032 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
9033 bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
9034 if ( !pVCpu->hm.s.Event.fPending
9035 && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
9036 {
9037 /** @todo SMI. SMIs take priority over NMIs. */
9038
9039 /*
9040 * NMIs.
9041 * NMIs take priority over external interrupts.
9042 */
9043 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9044 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
9045 {
9046 /*
9047 * For a guest, the FF always indicates the guest's ability to receive an NMI.
9048 *
9049 * For a nested-guest, the FF always indicates the outer guest's ability to
9050 * receive an NMI while the guest-interruptibility state bit depends on whether
9051 * the nested-hypervisor is using virtual-NMIs.
9052 */
9053 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
9054 {
9055#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9056 if ( fIsNestedGuest
9057 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_NMI_EXIT))
9058 return IEMExecVmxVmexitXcptNmi(pVCpu);
9059#endif
9060 hmR0VmxSetPendingXcptNmi(pVCpu);
9061 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
9062 Log4Func(("NMI pending injection\n"));
9063
9064 /* We've injected the NMI, bail. */
9065 return VINF_SUCCESS;
9066 }
9067 else if (!fIsNestedGuest)
9068 hmR0VmxSetNmiWindowExitVmcs(pVmcsInfo);
9069 }
9070
9071 /*
9072 * External interrupts (PIC/APIC).
9073 * Once PDMGetInterrupt() returns a valid interrupt we -must- deliver it.
9074 * We cannot re-request the interrupt from the controller again.
9075 */
9076 if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
9077 && !pVCpu->hm.s.fSingleInstruction)
9078 {
9079 Assert(!DBGFIsStepping(pVCpu));
9080 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
9081 AssertRC(rc);
9082
9083 /*
9084 * We must not check EFLAGS directly when executing a nested-guest, use
9085 * CPUMIsGuestPhysIntrEnabled() instead as EFLAGS.IF does not control the blocking of
9086 * external interrupts when "External interrupt exiting" is set. This fixes a nasty
9087 * SMP hang while executing nested-guest VCPUs on spinlocks which aren't rescued by
9088 * other VM-exits (like a preemption timer), see @bugref{9562#c18}.
9089 *
9090 * See Intel spec. 25.4.1 "Event Blocking".
9091 */
9092 if (CPUMIsGuestPhysIntrEnabled(pVCpu))
9093 {
9094#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9095 if ( fIsNestedGuest
9096 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
9097 {
9098 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
9099 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
9100 return rcStrict;
9101 }
9102#endif
9103 uint8_t u8Interrupt;
9104 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
9105 if (RT_SUCCESS(rc))
9106 {
9107#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9108 if ( fIsNestedGuest
9109 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
9110 {
9111 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
9112 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
9113 return rcStrict;
9114 }
9115#endif
9116 hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
9117 Log4Func(("External interrupt (%#x) pending injection\n", u8Interrupt));
9118 }
9119 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
9120 {
9121 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
9122
9123 if ( !fIsNestedGuest
9124 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
9125 hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
9126 /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
9127
9128 /*
9129 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
9130 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
9131 * need to re-set this force-flag here.
9132 */
9133 }
9134 else
9135 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
9136
9137 /* We've injected the interrupt or taken necessary action, bail. */
9138 return VINF_SUCCESS;
9139 }
9140 if (!fIsNestedGuest)
9141 hmR0VmxSetIntWindowExitVmcs(pVmcsInfo);
9142 }
9143 }
9144 else if (!fIsNestedGuest)
9145 {
9146 /*
9147 * An event is being injected or we are in an interrupt shadow. Check if another event is
9148 * pending. If so, instruct VT-x to cause a VM-exit as soon as the guest is ready to accept
9149 * the pending event.
9150 */
9151 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
9152 hmR0VmxSetNmiWindowExitVmcs(pVmcsInfo);
9153 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
9154 && !pVCpu->hm.s.fSingleInstruction)
9155 hmR0VmxSetIntWindowExitVmcs(pVmcsInfo);
9156 }
9157 /* else: for nested-guests, NMI/interrupt-window exiting will be picked up when merging VMCS controls. */
9158
9159 return VINF_SUCCESS;
9160}
9161
9162
9163/**
9164 * Injects any pending events into the guest if the guest is in a state to
9165 * receive them.
9166 *
9167 * @returns Strict VBox status code (i.e. informational status codes too).
9168 * @param pVCpu The cross context virtual CPU structure.
9169 * @param pVmxTransient The VMX-transient structure.
9170 * @param fIntrState The VT-x guest-interruptibility state.
9171 * @param fStepping Whether we are single-stepping the guest using the
9172 * hypervisor debugger and should return
9173 * VINF_EM_DBG_STEPPED if the event was dispatched
9174 * directly.
9175 */
9176static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t fIntrState, bool fStepping)
9177{
9178 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9179 Assert(VMMRZCallRing3IsEnabled(pVCpu));
9180
9181#ifdef VBOX_STRICT
9182 /*
9183 * Verify guest-interruptibility state.
9184 *
9185 * We put this in a scoped block so we do not accidentally use fBlockSti or fBlockMovSS,
9186 * since injecting an event may modify the interruptibility state and we must thus always
9187 * use fIntrState.
9188 */
9189 {
9190 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
9191 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
9192 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
9193 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
9194 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
9195 Assert(!TRPMHasTrap(pVCpu));
9196 NOREF(fBlockMovSS); NOREF(fBlockSti);
9197 }
9198#endif
9199
9200 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
9201 if (pVCpu->hm.s.Event.fPending)
9202 {
9203 /*
9204 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
9205 * pending even while injecting an event and in this case, we want a VM-exit as soon as
9206 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
9207 *
9208 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
9209 */
9210 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
9211#ifdef VBOX_STRICT
9212 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
9213 {
9214 Assert(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_IF);
9215 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
9216 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
9217 }
9218 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
9219 {
9220 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI));
9221 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
9222 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
9223 }
9224#endif
9225 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
9226 uIntType));
9227
9228 /*
9229 * Inject the event and get any changes to the guest-interruptibility state.
9230 *
9231 * The guest-interruptibility state may need to be updated if we inject the event
9232 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
9233 */
9234 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &pVCpu->hm.s.Event, fStepping, &fIntrState);
9235 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
9236
9237 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
9238 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
9239 else
9240 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
9241 }
9242
9243 /*
9244 * Deliver any pending debug exceptions if the guest is single-stepping using EFLAGS.TF and
9245 * is an interrupt shadow (block-by-STI or block-by-MOV SS).
9246 */
9247 if ( (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
9248 && !pVmxTransient->fIsNestedGuest)
9249 {
9250 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
9251
9252 if (!pVCpu->hm.s.fSingleInstruction)
9253 {
9254 /*
9255 * Set or clear the BS bit depending on whether the trap flag is active or not. We need
9256 * to do both since we clear the BS bit from the VMCS while exiting to ring-3.
9257 */
9258 Assert(!DBGFIsStepping(pVCpu));
9259 uint8_t const fTrapFlag = !!(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_TF);
9260 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, fTrapFlag << VMX_BF_VMCS_PENDING_DBG_XCPT_BS_SHIFT);
9261 AssertRC(rc);
9262 }
9263 else
9264 {
9265 /*
9266 * We must not deliver a debug exception when single-stepping over STI/Mov-SS in the
9267 * hypervisor debugger using EFLAGS.TF but rather clear interrupt inhibition. However,
9268 * we take care of this case in hmR0VmxExportSharedDebugState and also the case if
9269 * we use MTF, so just make sure it's called before executing guest-code.
9270 */
9271 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR_MASK);
9272 }
9273 }
9274 /* else: for nested-guest currently handling while merging controls. */
9275
9276 /*
9277 * Finally, update the guest-interruptibility state.
9278 *
9279 * This is required for the real-on-v86 software interrupt injection, for
9280 * pending debug exceptions as well as updates to the guest state from ring-3 (IEM).
9281 */
9282 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
9283 AssertRC(rc);
9284
9285 /*
9286 * There's no need to clear the VM-entry interruption-information field here if we're not
9287 * injecting anything. VT-x clears the valid bit on every VM-exit.
9288 *
9289 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
9290 */
9291
9292 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
9293 return rcStrict;
9294}
9295
9296
9297/**
9298 * Enters the VT-x session.
9299 *
9300 * @returns VBox status code.
9301 * @param pVCpu The cross context virtual CPU structure.
9302 */
9303VMMR0DECL(int) VMXR0Enter(PVMCPUCC pVCpu)
9304{
9305 AssertPtr(pVCpu);
9306 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported);
9307 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9308
9309 LogFlowFunc(("pVCpu=%p\n", pVCpu));
9310 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9311 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
9312
9313#ifdef VBOX_STRICT
9314 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
9315 RTCCUINTREG uHostCr4 = ASMGetCR4();
9316 if (!(uHostCr4 & X86_CR4_VMXE))
9317 {
9318 LogRelFunc(("X86_CR4_VMXE bit in CR4 is not set!\n"));
9319 return VERR_VMX_X86_CR4_VMXE_CLEARED;
9320 }
9321#endif
9322
9323 /*
9324 * Do the EMT scheduled L1D and MDS flush here if needed.
9325 */
9326 if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_L1D_SCHED)
9327 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
9328 else if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_MDS_SCHED)
9329 hmR0MdsClear();
9330
9331 /*
9332 * Load the appropriate VMCS as the current and active one.
9333 */
9334 PVMXVMCSINFO pVmcsInfo;
9335 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx);
9336 if (!fInNestedGuestMode)
9337 pVmcsInfo = &pVCpu->hmr0.s.vmx.VmcsInfo;
9338 else
9339 pVmcsInfo = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
9340 int rc = hmR0VmxLoadVmcs(pVmcsInfo);
9341 if (RT_SUCCESS(rc))
9342 {
9343 pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs = fInNestedGuestMode;
9344 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcsCopyForRing3 = fInNestedGuestMode;
9345 pVCpu->hmr0.s.fLeaveDone = false;
9346 Log4Func(("Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
9347 }
9348 return rc;
9349}
9350
9351
9352/**
9353 * The thread-context callback (only on platforms which support it).
9354 *
9355 * @param enmEvent The thread-context event.
9356 * @param pVCpu The cross context virtual CPU structure.
9357 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
9358 * @thread EMT(pVCpu)
9359 */
9360VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit)
9361{
9362 AssertPtr(pVCpu);
9363 RT_NOREF1(fGlobalInit);
9364
9365 switch (enmEvent)
9366 {
9367 case RTTHREADCTXEVENT_OUT:
9368 {
9369 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9370 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
9371 VMCPU_ASSERT_EMT(pVCpu);
9372
9373 /* No longjmps (logger flushes, locks) in this fragile context. */
9374 VMMRZCallRing3Disable(pVCpu);
9375 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
9376
9377 /* Restore host-state (FPU, debug etc.) */
9378 if (!pVCpu->hmr0.s.fLeaveDone)
9379 {
9380 /*
9381 * Do -not- import the guest-state here as we might already be in the middle of importing
9382 * it, esp. bad if we're holding the PGM lock, see comment in hmR0VmxImportGuestState().
9383 */
9384 hmR0VmxLeave(pVCpu, false /* fImportState */);
9385 pVCpu->hmr0.s.fLeaveDone = true;
9386 }
9387
9388 /* Leave HM context, takes care of local init (term). */
9389 int rc = HMR0LeaveCpu(pVCpu);
9390 AssertRC(rc);
9391
9392 /* Restore longjmp state. */
9393 VMMRZCallRing3Enable(pVCpu);
9394 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
9395 break;
9396 }
9397
9398 case RTTHREADCTXEVENT_IN:
9399 {
9400 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9401 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
9402 VMCPU_ASSERT_EMT(pVCpu);
9403
9404 /* Do the EMT scheduled L1D and MDS flush here if needed. */
9405 if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_L1D_SCHED)
9406 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
9407 else if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_MDS_SCHED)
9408 hmR0MdsClear();
9409
9410 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
9411 VMMRZCallRing3Disable(pVCpu);
9412 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
9413
9414 /* Initialize the bare minimum state required for HM. This takes care of
9415 initializing VT-x if necessary (onlined CPUs, local init etc.) */
9416 int rc = hmR0EnterCpu(pVCpu);
9417 AssertRC(rc);
9418 Assert( (pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9419 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
9420
9421 /* Load the active VMCS as the current one. */
9422 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
9423 rc = hmR0VmxLoadVmcs(pVmcsInfo);
9424 AssertRC(rc);
9425 Log4Func(("Resumed: Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
9426 pVCpu->hmr0.s.fLeaveDone = false;
9427
9428 /* Restore longjmp state. */
9429 VMMRZCallRing3Enable(pVCpu);
9430 break;
9431 }
9432
9433 default:
9434 break;
9435 }
9436}
9437
9438
9439/**
9440 * Exports the host state into the VMCS host-state area.
9441 * Sets up the VM-exit MSR-load area.
9442 *
9443 * The CPU state will be loaded from these fields on every successful VM-exit.
9444 *
9445 * @returns VBox status code.
9446 * @param pVCpu The cross context virtual CPU structure.
9447 *
9448 * @remarks No-long-jump zone!!!
9449 */
9450static int hmR0VmxExportHostState(PVMCPUCC pVCpu)
9451{
9452 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9453
9454 int rc = VINF_SUCCESS;
9455 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
9456 {
9457 uint64_t uHostCr4 = hmR0VmxExportHostControlRegs();
9458
9459 rc = hmR0VmxExportHostSegmentRegs(pVCpu, uHostCr4);
9460 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9461
9462 hmR0VmxExportHostMsrs(pVCpu);
9463
9464 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_HOST_CONTEXT;
9465 }
9466 return rc;
9467}
9468
9469
9470/**
9471 * Saves the host state in the VMCS host-state.
9472 *
9473 * @returns VBox status code.
9474 * @param pVCpu The cross context virtual CPU structure.
9475 *
9476 * @remarks No-long-jump zone!!!
9477 */
9478VMMR0DECL(int) VMXR0ExportHostState(PVMCPUCC pVCpu)
9479{
9480 AssertPtr(pVCpu);
9481 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9482
9483 /*
9484 * Export the host state here while entering HM context.
9485 * When thread-context hooks are used, we might get preempted and have to re-save the host
9486 * state but most of the time we won't be, so do it here before we disable interrupts.
9487 */
9488 return hmR0VmxExportHostState(pVCpu);
9489}
9490
9491
9492/**
9493 * Exports the guest state into the VMCS guest-state area.
9494 *
9495 * The will typically be done before VM-entry when the guest-CPU state and the
9496 * VMCS state may potentially be out of sync.
9497 *
9498 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
9499 * VM-entry controls.
9500 * Sets up the appropriate VMX non-root function to execute guest code based on
9501 * the guest CPU mode.
9502 *
9503 * @returns VBox strict status code.
9504 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9505 * without unrestricted guest execution and the VMMDev is not presently
9506 * mapped (e.g. EFI32).
9507 *
9508 * @param pVCpu The cross context virtual CPU structure.
9509 * @param pVmxTransient The VMX-transient structure.
9510 *
9511 * @remarks No-long-jump zone!!!
9512 */
9513static VBOXSTRICTRC hmR0VmxExportGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9514{
9515 AssertPtr(pVCpu);
9516 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9517 LogFlowFunc(("pVCpu=%p\n", pVCpu));
9518
9519 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExportGuestState, x);
9520
9521 /*
9522 * Determine real-on-v86 mode.
9523 * Used when the guest is in real-mode and unrestricted guest execution is not used.
9524 */
9525 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmxTransient->pVmcsInfo->pShared;
9526 if ( pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest
9527 || !CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx))
9528 pVmcsInfoShared->RealMode.fRealOnV86Active = false;
9529 else
9530 {
9531 Assert(!pVmxTransient->fIsNestedGuest);
9532 pVmcsInfoShared->RealMode.fRealOnV86Active = true;
9533 }
9534
9535 /*
9536 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
9537 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
9538 */
9539 int rc = hmR0VmxExportGuestEntryExitCtls(pVCpu, pVmxTransient);
9540 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9541
9542 rc = hmR0VmxExportGuestCR0(pVCpu, pVmxTransient);
9543 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9544
9545 VBOXSTRICTRC rcStrict = hmR0VmxExportGuestCR3AndCR4(pVCpu, pVmxTransient);
9546 if (rcStrict == VINF_SUCCESS)
9547 { /* likely */ }
9548 else
9549 {
9550 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
9551 return rcStrict;
9552 }
9553
9554 rc = hmR0VmxExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
9555 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9556
9557 rc = hmR0VmxExportGuestMsrs(pVCpu, pVmxTransient);
9558 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9559
9560 hmR0VmxExportGuestApicTpr(pVCpu, pVmxTransient);
9561 hmR0VmxExportGuestXcptIntercepts(pVCpu, pVmxTransient);
9562 hmR0VmxExportGuestRip(pVCpu);
9563 hmR0VmxExportGuestRsp(pVCpu);
9564 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9565
9566 rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9567 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9568
9569 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
9570 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~( (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
9571 | HM_CHANGED_GUEST_CR2
9572 | (HM_CHANGED_GUEST_DR_MASK & ~HM_CHANGED_GUEST_DR7)
9573 | HM_CHANGED_GUEST_X87
9574 | HM_CHANGED_GUEST_SSE_AVX
9575 | HM_CHANGED_GUEST_OTHER_XSAVE
9576 | HM_CHANGED_GUEST_XCRx
9577 | HM_CHANGED_GUEST_KERNEL_GS_BASE /* Part of lazy or auto load-store MSRs. */
9578 | HM_CHANGED_GUEST_SYSCALL_MSRS /* Part of lazy or auto load-store MSRs. */
9579 | HM_CHANGED_GUEST_TSC_AUX
9580 | HM_CHANGED_GUEST_OTHER_MSRS
9581 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
9582
9583 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExportGuestState, x);
9584 return rc;
9585}
9586
9587
9588/**
9589 * Exports the state shared between the host and guest into the VMCS.
9590 *
9591 * @param pVCpu The cross context virtual CPU structure.
9592 * @param pVmxTransient The VMX-transient structure.
9593 *
9594 * @remarks No-long-jump zone!!!
9595 */
9596static void hmR0VmxExportSharedState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9597{
9598 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9599 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9600
9601 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_DR_MASK)
9602 {
9603 int rc = hmR0VmxExportSharedDebugState(pVCpu, pVmxTransient);
9604 AssertRC(rc);
9605 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_GUEST_DR_MASK;
9606
9607 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
9608 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_RFLAGS)
9609 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9610 }
9611
9612 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_GUEST_LAZY_MSRS)
9613 {
9614 hmR0VmxLazyLoadGuestMsrs(pVCpu);
9615 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_VMX_GUEST_LAZY_MSRS;
9616 }
9617
9618 AssertMsg(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE),
9619 ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
9620}
9621
9622
9623/**
9624 * Worker for loading the guest-state bits in the inner VT-x execution loop.
9625 *
9626 * @returns Strict VBox status code (i.e. informational status codes too).
9627 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9628 * without unrestricted guest execution and the VMMDev is not presently
9629 * mapped (e.g. EFI32).
9630 *
9631 * @param pVCpu The cross context virtual CPU structure.
9632 * @param pVmxTransient The VMX-transient structure.
9633 *
9634 * @remarks No-long-jump zone!!!
9635 */
9636static VBOXSTRICTRC hmR0VmxExportGuestStateOptimal(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9637{
9638 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9639 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9640 Assert(VMMR0IsLogFlushDisabled(pVCpu));
9641
9642#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
9643 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
9644#endif
9645
9646 /*
9647 * For many VM-exits only RIP/RSP/RFLAGS (and HWVIRT state when executing a nested-guest)
9648 * changes. First try to export only these without going through all other changed-flag checks.
9649 */
9650 VBOXSTRICTRC rcStrict;
9651 uint64_t const fCtxMask = HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE;
9652 uint64_t const fMinimalMask = HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT;
9653 uint64_t const fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9654
9655 /* If only RIP/RSP/RFLAGS/HWVIRT changed, export only those (quicker, happens more often).*/
9656 if ( (fCtxChanged & fMinimalMask)
9657 && !(fCtxChanged & (fCtxMask & ~fMinimalMask)))
9658 {
9659 hmR0VmxExportGuestRip(pVCpu);
9660 hmR0VmxExportGuestRsp(pVCpu);
9661 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9662 rcStrict = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9663 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportMinimal);
9664 }
9665 /* If anything else also changed, go through the full export routine and export as required. */
9666 else if (fCtxChanged & fCtxMask)
9667 {
9668 rcStrict = hmR0VmxExportGuestState(pVCpu, pVmxTransient);
9669 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9670 { /* likely */}
9671 else
9672 {
9673 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM, ("Failed to export guest state! rc=%Rrc\n",
9674 VBOXSTRICTRC_VAL(rcStrict)));
9675 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9676 return rcStrict;
9677 }
9678 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportFull);
9679 }
9680 /* Nothing changed, nothing to load here. */
9681 else
9682 rcStrict = VINF_SUCCESS;
9683
9684#ifdef VBOX_STRICT
9685 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
9686 uint64_t const fCtxChangedCur = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9687 AssertMsg(!(fCtxChangedCur & fCtxMask), ("fCtxChangedCur=%#RX64\n", fCtxChangedCur));
9688#endif
9689 return rcStrict;
9690}
9691
9692
9693/**
9694 * Tries to determine what part of the guest-state VT-x has deemed as invalid
9695 * and update error record fields accordingly.
9696 *
9697 * @returns VMX_IGS_* error codes.
9698 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
9699 * wrong with the guest state.
9700 *
9701 * @param pVCpu The cross context virtual CPU structure.
9702 * @param pVmcsInfo The VMCS info. object.
9703 *
9704 * @remarks This function assumes our cache of the VMCS controls
9705 * are valid, i.e. hmR0VmxCheckCachedVmcsCtls() succeeded.
9706 */
9707static uint32_t hmR0VmxCheckGuestState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
9708{
9709#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
9710#define HMVMX_CHECK_BREAK(expr, err) do { \
9711 if (!(expr)) { uError = (err); break; } \
9712 } while (0)
9713
9714 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9715 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9716 uint32_t uError = VMX_IGS_ERROR;
9717 uint32_t u32IntrState = 0;
9718 bool const fUnrestrictedGuest = pVM->hmr0.s.vmx.fUnrestrictedGuest;
9719 do
9720 {
9721 int rc;
9722
9723 /*
9724 * Guest-interruptibility state.
9725 *
9726 * Read this first so that any check that fails prior to those that actually
9727 * require the guest-interruptibility state would still reflect the correct
9728 * VMCS value and avoids causing further confusion.
9729 */
9730 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
9731 AssertRC(rc);
9732
9733 uint32_t u32Val;
9734 uint64_t u64Val;
9735
9736 /*
9737 * CR0.
9738 */
9739 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9740 uint64_t fSetCr0 = (g_HmMsrs.u.vmx.u64Cr0Fixed0 & g_HmMsrs.u.vmx.u64Cr0Fixed1);
9741 uint64_t const fZapCr0 = (g_HmMsrs.u.vmx.u64Cr0Fixed0 | g_HmMsrs.u.vmx.u64Cr0Fixed1);
9742 /* Exceptions for unrestricted guest execution for CR0 fixed bits (PE, PG).
9743 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
9744 if (fUnrestrictedGuest)
9745 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
9746
9747 uint64_t u64GuestCr0;
9748 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64GuestCr0);
9749 AssertRC(rc);
9750 HMVMX_CHECK_BREAK((u64GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
9751 HMVMX_CHECK_BREAK(!(u64GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
9752 if ( !fUnrestrictedGuest
9753 && (u64GuestCr0 & X86_CR0_PG)
9754 && !(u64GuestCr0 & X86_CR0_PE))
9755 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
9756
9757 /*
9758 * CR4.
9759 */
9760 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9761 uint64_t const fSetCr4 = (g_HmMsrs.u.vmx.u64Cr4Fixed0 & g_HmMsrs.u.vmx.u64Cr4Fixed1);
9762 uint64_t const fZapCr4 = (g_HmMsrs.u.vmx.u64Cr4Fixed0 | g_HmMsrs.u.vmx.u64Cr4Fixed1);
9763
9764 uint64_t u64GuestCr4;
9765 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64GuestCr4);
9766 AssertRC(rc);
9767 HMVMX_CHECK_BREAK((u64GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
9768 HMVMX_CHECK_BREAK(!(u64GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
9769
9770 /*
9771 * IA32_DEBUGCTL MSR.
9772 */
9773 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
9774 AssertRC(rc);
9775 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9776 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
9777 {
9778 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
9779 }
9780 uint64_t u64DebugCtlMsr = u64Val;
9781
9782#ifdef VBOX_STRICT
9783 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
9784 AssertRC(rc);
9785 Assert(u32Val == pVmcsInfo->u32EntryCtls);
9786#endif
9787 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
9788
9789 /*
9790 * RIP and RFLAGS.
9791 */
9792 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
9793 AssertRC(rc);
9794 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
9795 if ( !fLongModeGuest
9796 || !pCtx->cs.Attr.n.u1Long)
9797 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
9798 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
9799 * must be identical if the "IA-32e mode guest" VM-entry
9800 * control is 1 and CS.L is 1. No check applies if the
9801 * CPU supports 64 linear-address bits. */
9802
9803 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
9804 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
9805 AssertRC(rc);
9806 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
9807 VMX_IGS_RFLAGS_RESERVED);
9808 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
9809 uint32_t const u32Eflags = u64Val;
9810
9811 if ( fLongModeGuest
9812 || ( fUnrestrictedGuest
9813 && !(u64GuestCr0 & X86_CR0_PE)))
9814 {
9815 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
9816 }
9817
9818 uint32_t u32EntryInfo;
9819 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
9820 AssertRC(rc);
9821 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9822 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
9823
9824 /*
9825 * 64-bit checks.
9826 */
9827 if (fLongModeGuest)
9828 {
9829 HMVMX_CHECK_BREAK(u64GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
9830 HMVMX_CHECK_BREAK(u64GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
9831 }
9832
9833 if ( !fLongModeGuest
9834 && (u64GuestCr4 & X86_CR4_PCIDE))
9835 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
9836
9837 /** @todo CR3 field must be such that bits 63:52 and bits in the range
9838 * 51:32 beyond the processor's physical-address width are 0. */
9839
9840 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9841 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
9842 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
9843
9844 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
9845 AssertRC(rc);
9846 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
9847
9848 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
9849 AssertRC(rc);
9850 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
9851
9852 /*
9853 * PERF_GLOBAL MSR.
9854 */
9855 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
9856 {
9857 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
9858 AssertRC(rc);
9859 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
9860 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
9861 }
9862
9863 /*
9864 * PAT MSR.
9865 */
9866 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
9867 {
9868 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
9869 AssertRC(rc);
9870 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
9871 for (unsigned i = 0; i < 8; i++)
9872 {
9873 uint8_t u8Val = (u64Val & 0xff);
9874 if ( u8Val != 0 /* UC */
9875 && u8Val != 1 /* WC */
9876 && u8Val != 4 /* WT */
9877 && u8Val != 5 /* WP */
9878 && u8Val != 6 /* WB */
9879 && u8Val != 7 /* UC- */)
9880 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
9881 u64Val >>= 8;
9882 }
9883 }
9884
9885 /*
9886 * EFER MSR.
9887 */
9888 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
9889 {
9890 Assert(g_fHmVmxSupportsVmcsEfer);
9891 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
9892 AssertRC(rc);
9893 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
9894 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
9895 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
9896 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
9897 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
9898 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
9899 * iemVmxVmentryCheckGuestState(). */
9900 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9901 || !(u64GuestCr0 & X86_CR0_PG)
9902 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
9903 VMX_IGS_EFER_LMA_LME_MISMATCH);
9904 }
9905
9906 /*
9907 * Segment registers.
9908 */
9909 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9910 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
9911 if (!(u32Eflags & X86_EFL_VM))
9912 {
9913 /* CS */
9914 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
9915 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
9916 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
9917 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
9918 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9919 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
9920 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9921 /* CS cannot be loaded with NULL in protected mode. */
9922 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
9923 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
9924 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
9925 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
9926 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
9927 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
9928 else if (fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
9929 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
9930 else
9931 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
9932
9933 /* SS */
9934 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9935 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
9936 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
9937 if ( !(pCtx->cr0 & X86_CR0_PE)
9938 || pCtx->cs.Attr.n.u4Type == 3)
9939 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
9940
9941 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
9942 {
9943 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
9944 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
9945 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
9946 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
9947 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
9948 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9949 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
9950 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9951 }
9952
9953 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSReg(). */
9954 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
9955 {
9956 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
9957 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
9958 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9959 || pCtx->ds.Attr.n.u4Type > 11
9960 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9961 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
9962 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
9963 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
9964 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9965 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
9966 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9967 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9968 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
9969 }
9970 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
9971 {
9972 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
9973 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
9974 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9975 || pCtx->es.Attr.n.u4Type > 11
9976 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9977 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
9978 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
9979 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
9980 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9981 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
9982 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9983 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9984 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
9985 }
9986 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
9987 {
9988 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
9989 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
9990 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9991 || pCtx->fs.Attr.n.u4Type > 11
9992 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
9993 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
9994 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
9995 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
9996 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9997 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
9998 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
9999 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10000 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
10001 }
10002 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
10003 {
10004 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
10005 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
10006 HMVMX_CHECK_BREAK( fUnrestrictedGuest
10007 || pCtx->gs.Attr.n.u4Type > 11
10008 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
10009 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
10010 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
10011 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
10012 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10013 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
10014 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10015 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10016 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
10017 }
10018 /* 64-bit capable CPUs. */
10019 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10020 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10021 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10022 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10023 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10024 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
10025 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10026 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
10027 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10028 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
10029 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10030 }
10031 else
10032 {
10033 /* V86 mode checks. */
10034 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
10035 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
10036 {
10037 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
10038 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
10039 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
10040 }
10041 else
10042 {
10043 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
10044 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
10045 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
10046 }
10047
10048 /* CS */
10049 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
10050 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
10051 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
10052 /* SS */
10053 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
10054 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
10055 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
10056 /* DS */
10057 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
10058 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
10059 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
10060 /* ES */
10061 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
10062 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
10063 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
10064 /* FS */
10065 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
10066 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
10067 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
10068 /* GS */
10069 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
10070 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
10071 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
10072 /* 64-bit capable CPUs. */
10073 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10074 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10075 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10076 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10077 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10078 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
10079 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10080 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
10081 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10082 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
10083 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10084 }
10085
10086 /*
10087 * TR.
10088 */
10089 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
10090 /* 64-bit capable CPUs. */
10091 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
10092 if (fLongModeGuest)
10093 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
10094 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
10095 else
10096 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
10097 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
10098 VMX_IGS_TR_ATTR_TYPE_INVALID);
10099 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
10100 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
10101 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
10102 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
10103 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
10104 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
10105 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
10106 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
10107
10108 /*
10109 * GDTR and IDTR (64-bit capable checks).
10110 */
10111 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
10112 AssertRC(rc);
10113 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
10114
10115 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
10116 AssertRC(rc);
10117 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
10118
10119 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
10120 AssertRC(rc);
10121 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
10122
10123 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
10124 AssertRC(rc);
10125 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
10126
10127 /*
10128 * Guest Non-Register State.
10129 */
10130 /* Activity State. */
10131 uint32_t u32ActivityState;
10132 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
10133 AssertRC(rc);
10134 HMVMX_CHECK_BREAK( !u32ActivityState
10135 || (u32ActivityState & RT_BF_GET(g_HmMsrs.u.vmx.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
10136 VMX_IGS_ACTIVITY_STATE_INVALID);
10137 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
10138 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
10139
10140 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
10141 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10142 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
10143
10144 /** @todo Activity state and injecting interrupts. Left as a todo since we
10145 * currently don't use activity states but ACTIVE. */
10146
10147 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
10148 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
10149
10150 /* Guest interruptibility-state. */
10151 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
10152 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
10153 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10154 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
10155 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
10156 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
10157 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
10158 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
10159 {
10160 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10161 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10162 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
10163 }
10164 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
10165 {
10166 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10167 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
10168 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
10169 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
10170 }
10171 /** @todo Assumes the processor is not in SMM. */
10172 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
10173 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
10174 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
10175 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
10176 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
10177 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
10178 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
10179 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI), VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
10180
10181 /* Pending debug exceptions. */
10182 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
10183 AssertRC(rc);
10184 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
10185 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
10186 u32Val = u64Val; /* For pending debug exceptions checks below. */
10187
10188 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10189 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
10190 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
10191 {
10192 if ( (u32Eflags & X86_EFL_TF)
10193 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
10194 {
10195 /* Bit 14 is PendingDebug.BS. */
10196 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
10197 }
10198 if ( !(u32Eflags & X86_EFL_TF)
10199 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
10200 {
10201 /* Bit 14 is PendingDebug.BS. */
10202 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
10203 }
10204 }
10205
10206 /* VMCS link pointer. */
10207 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
10208 AssertRC(rc);
10209 if (u64Val != UINT64_C(0xffffffffffffffff))
10210 {
10211 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
10212 /** @todo Bits beyond the processor's physical-address width MBZ. */
10213 /** @todo SMM checks. */
10214 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
10215 Assert(pVmcsInfo->pvShadowVmcs);
10216 VMXVMCSREVID VmcsRevId;
10217 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
10218 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID),
10219 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
10220 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
10221 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
10222 }
10223
10224 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
10225 * not using nested paging? */
10226 if ( pVM->hmr0.s.fNestedPaging
10227 && !fLongModeGuest
10228 && CPUMIsGuestInPAEModeEx(pCtx))
10229 {
10230 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
10231 AssertRC(rc);
10232 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10233
10234 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
10235 AssertRC(rc);
10236 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10237
10238 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
10239 AssertRC(rc);
10240 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10241
10242 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
10243 AssertRC(rc);
10244 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10245 }
10246
10247 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
10248 if (uError == VMX_IGS_ERROR)
10249 uError = VMX_IGS_REASON_NOT_FOUND;
10250 } while (0);
10251
10252 pVCpu->hm.s.u32HMError = uError;
10253 pVCpu->hm.s.vmx.LastError.u32GuestIntrState = u32IntrState;
10254 return uError;
10255
10256#undef HMVMX_ERROR_BREAK
10257#undef HMVMX_CHECK_BREAK
10258}
10259
10260
10261/**
10262 * Map the APIC-access page for virtualizing APIC accesses.
10263 *
10264 * This can cause a longjumps to R3 due to the acquisition of the PGM lock. Hence,
10265 * this not done as part of exporting guest state, see @bugref{8721}.
10266 *
10267 * @returns VBox status code.
10268 * @param pVCpu The cross context virtual CPU structure.
10269 */
10270static int hmR0VmxMapHCApicAccessPage(PVMCPUCC pVCpu)
10271{
10272 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10273 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
10274
10275 Assert(PDMHasApic(pVM));
10276 Assert(u64MsrApicBase);
10277
10278 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
10279 Log4Func(("Mappping HC APIC-access page at %#RGp\n", GCPhysApicBase));
10280
10281 /* Unalias the existing mapping. */
10282 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
10283 AssertRCReturn(rc, rc);
10284
10285 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
10286 Assert(pVM->hmr0.s.vmx.HCPhysApicAccess != NIL_RTHCPHYS);
10287 rc = IOMR0MmioMapMmioHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hmr0.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
10288 AssertRCReturn(rc, rc);
10289
10290 /* Update the per-VCPU cache of the APIC base MSR. */
10291 pVCpu->hm.s.vmx.u64GstMsrApicBase = u64MsrApicBase;
10292 return VINF_SUCCESS;
10293}
10294
10295
10296/**
10297 * Worker function passed to RTMpOnSpecific() that is to be called on the target
10298 * CPU.
10299 *
10300 * @param idCpu The ID for the CPU the function is called on.
10301 * @param pvUser1 Null, not used.
10302 * @param pvUser2 Null, not used.
10303 */
10304static DECLCALLBACK(void) hmR0DispatchHostNmi(RTCPUID idCpu, void *pvUser1, void *pvUser2)
10305{
10306 RT_NOREF3(idCpu, pvUser1, pvUser2);
10307 VMXDispatchHostNmi();
10308}
10309
10310
10311/**
10312 * Dispatching an NMI on the host CPU that received it.
10313 *
10314 * @returns VBox status code.
10315 * @param pVCpu The cross context virtual CPU structure.
10316 * @param pVmcsInfo The VMCS info. object corresponding to the VMCS that was
10317 * executing when receiving the host NMI in VMX non-root
10318 * operation.
10319 */
10320static int hmR0VmxExitHostNmi(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
10321{
10322 RTCPUID const idCpu = pVmcsInfo->idHostCpuExec;
10323 Assert(idCpu != NIL_RTCPUID);
10324
10325 /*
10326 * We don't want to delay dispatching the NMI any more than we have to. However,
10327 * we have already chosen -not- to dispatch NMIs when interrupts were still disabled
10328 * after executing guest or nested-guest code for the following reasons:
10329 *
10330 * - We would need to perform VMREADs with interrupts disabled and is orders of
10331 * magnitude worse when we run as a nested hypervisor without VMCS shadowing
10332 * supported by the host hypervisor.
10333 *
10334 * - It affects the common VM-exit scenario and keeps interrupts disabled for a
10335 * longer period of time just for handling an edge case like host NMIs which do
10336 * not occur nearly as frequently as other VM-exits.
10337 *
10338 * Let's cover the most likely scenario first. Check if we are on the target CPU
10339 * and dispatch the NMI right away. This should be much faster than calling into
10340 * RTMpOnSpecific() machinery.
10341 */
10342 bool fDispatched = false;
10343 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
10344 if (idCpu == RTMpCpuId())
10345 {
10346 VMXDispatchHostNmi();
10347 fDispatched = true;
10348 }
10349 ASMSetFlags(fEFlags);
10350 if (fDispatched)
10351 {
10352 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
10353 return VINF_SUCCESS;
10354 }
10355
10356 /*
10357 * RTMpOnSpecific() waits until the worker function has run on the target CPU. So
10358 * there should be no race or recursion even if we are unlucky enough to be preempted
10359 * (to the target CPU) without dispatching the host NMI above.
10360 */
10361 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGCIpi);
10362 return RTMpOnSpecific(idCpu, &hmR0DispatchHostNmi, NULL /* pvUser1 */, NULL /* pvUser2 */);
10363}
10364
10365
10366#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10367/**
10368 * Merges the guest with the nested-guest MSR bitmap in preparation of executing the
10369 * nested-guest using hardware-assisted VMX.
10370 *
10371 * @param pVCpu The cross context virtual CPU structure.
10372 * @param pVmcsInfoNstGst The nested-guest VMCS info. object.
10373 * @param pVmcsInfoGst The guest VMCS info. object.
10374 */
10375static void hmR0VmxMergeMsrBitmapNested(PCVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
10376{
10377 uint32_t const cbMsrBitmap = X86_PAGE_4K_SIZE;
10378 uint64_t *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
10379 Assert(pu64MsrBitmap);
10380
10381 /*
10382 * We merge the guest MSR bitmap with the nested-guest MSR bitmap such that any
10383 * MSR that is intercepted by the guest is also intercepted while executing the
10384 * nested-guest using hardware-assisted VMX.
10385 *
10386 * Note! If the nested-guest is not using an MSR bitmap, every MSR must cause a
10387 * nested-guest VM-exit even if the outer guest is not intercepting some
10388 * MSRs. We cannot assume the caller has initialized the nested-guest
10389 * MSR bitmap in this case.
10390 *
10391 * The nested hypervisor may also switch whether it uses MSR bitmaps for
10392 * each of its VM-entry, hence initializing it once per-VM while setting
10393 * up the nested-guest VMCS is not sufficient.
10394 */
10395 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
10396 if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10397 {
10398 uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap);
10399 uint64_t const *pu64MsrBitmapGst = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
10400 Assert(pu64MsrBitmapNstGst);
10401 Assert(pu64MsrBitmapGst);
10402
10403 /** @todo Detect and use EVEX.POR? */
10404 uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
10405 for (uint32_t i = 0; i < cFrags; i++)
10406 pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
10407 }
10408 else
10409 ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
10410}
10411
10412
10413/**
10414 * Merges the guest VMCS in to the nested-guest VMCS controls in preparation of
10415 * hardware-assisted VMX execution of the nested-guest.
10416 *
10417 * For a guest, we don't modify these controls once we set up the VMCS and hence
10418 * this function is never called.
10419 *
10420 * For nested-guests since the nested hypervisor provides these controls on every
10421 * nested-guest VM-entry and could potentially change them everytime we need to
10422 * merge them before every nested-guest VM-entry.
10423 *
10424 * @returns VBox status code.
10425 * @param pVCpu The cross context virtual CPU structure.
10426 */
10427static int hmR0VmxMergeVmcsNested(PVMCPUCC pVCpu)
10428{
10429 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10430 PCVMXVMCSINFO pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
10431 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
10432 Assert(pVmcsNstGst);
10433
10434 /*
10435 * Merge the controls with the requirements of the guest VMCS.
10436 *
10437 * We do not need to validate the nested-guest VMX features specified in the nested-guest
10438 * VMCS with the features supported by the physical CPU as it's already done by the
10439 * VMLAUNCH/VMRESUME instruction emulation.
10440 *
10441 * This is because the VMX features exposed by CPUM (through CPUID/MSRs) to the guest are
10442 * derived from the VMX features supported by the physical CPU.
10443 */
10444
10445 /* Pin-based VM-execution controls. */
10446 uint32_t const u32PinCtls = pVmcsNstGst->u32PinCtls | pVmcsInfoGst->u32PinCtls;
10447
10448 /* Processor-based VM-execution controls. */
10449 uint32_t u32ProcCtls = (pVmcsNstGst->u32ProcCtls & ~VMX_PROC_CTLS_USE_IO_BITMAPS)
10450 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT
10451 | VMX_PROC_CTLS_NMI_WINDOW_EXIT
10452 | VMX_PROC_CTLS_USE_TPR_SHADOW
10453 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
10454
10455 /* Secondary processor-based VM-execution controls. */
10456 uint32_t const u32ProcCtls2 = (pVmcsNstGst->u32ProcCtls2 & ~VMX_PROC_CTLS2_VPID)
10457 | (pVmcsInfoGst->u32ProcCtls2 & ~( VMX_PROC_CTLS2_VIRT_APIC_ACCESS
10458 | VMX_PROC_CTLS2_INVPCID
10459 | VMX_PROC_CTLS2_VMCS_SHADOWING
10460 | VMX_PROC_CTLS2_RDTSCP
10461 | VMX_PROC_CTLS2_XSAVES_XRSTORS
10462 | VMX_PROC_CTLS2_APIC_REG_VIRT
10463 | VMX_PROC_CTLS2_VIRT_INT_DELIVERY
10464 | VMX_PROC_CTLS2_VMFUNC));
10465
10466 /*
10467 * VM-entry controls:
10468 * These controls contains state that depends on the nested-guest state (primarily
10469 * EFER MSR) and is thus not constant between VMLAUNCH/VMRESUME and the nested-guest
10470 * VM-exit. Although the nested hypervisor cannot change it, we need to in order to
10471 * properly continue executing the nested-guest if the EFER MSR changes but does not
10472 * cause a nested-guest VM-exits.
10473 *
10474 * VM-exit controls:
10475 * These controls specify the host state on return. We cannot use the controls from
10476 * the nested hypervisor state as is as it would contain the guest state rather than
10477 * the host state. Since the host state is subject to change (e.g. preemption, trips
10478 * to ring-3, longjmp and rescheduling to a different host CPU) they are not constant
10479 * through VMLAUNCH/VMRESUME and the nested-guest VM-exit.
10480 *
10481 * VM-entry MSR-load:
10482 * The guest MSRs from the VM-entry MSR-load area are already loaded into the guest-CPU
10483 * context by the VMLAUNCH/VMRESUME instruction emulation.
10484 *
10485 * VM-exit MSR-store:
10486 * The VM-exit emulation will take care of populating the MSRs from the guest-CPU context
10487 * back into the VM-exit MSR-store area.
10488 *
10489 * VM-exit MSR-load areas:
10490 * This must contain the real host MSRs with hardware-assisted VMX execution. Hence, we
10491 * can entirely ignore what the nested hypervisor wants to load here.
10492 */
10493
10494 /*
10495 * Exception bitmap.
10496 *
10497 * We could remove #UD from the guest bitmap and merge it with the nested-guest bitmap
10498 * here (and avoid doing anything while exporting nested-guest state), but to keep the
10499 * code more flexible if intercepting exceptions become more dynamic in the future we do
10500 * it as part of exporting the nested-guest state.
10501 */
10502 uint32_t const u32XcptBitmap = pVmcsNstGst->u32XcptBitmap | pVmcsInfoGst->u32XcptBitmap;
10503
10504 /*
10505 * CR0/CR4 guest/host mask.
10506 *
10507 * Modifications by the nested-guest to CR0/CR4 bits owned by the host and the guest must
10508 * cause VM-exits, so we need to merge them here.
10509 */
10510 uint64_t const u64Cr0Mask = pVmcsNstGst->u64Cr0Mask.u | pVmcsInfoGst->u64Cr0Mask;
10511 uint64_t const u64Cr4Mask = pVmcsNstGst->u64Cr4Mask.u | pVmcsInfoGst->u64Cr4Mask;
10512
10513 /*
10514 * Page-fault error-code mask and match.
10515 *
10516 * Although we require unrestricted guest execution (and thereby nested-paging) for
10517 * hardware-assisted VMX execution of nested-guests and thus the outer guest doesn't
10518 * normally intercept #PFs, it might intercept them for debugging purposes.
10519 *
10520 * If the outer guest is not intercepting #PFs, we can use the nested-guest #PF filters.
10521 * If the outer guest is intercepting #PFs, we must intercept all #PFs.
10522 */
10523 uint32_t u32XcptPFMask;
10524 uint32_t u32XcptPFMatch;
10525 if (!(pVmcsInfoGst->u32XcptBitmap & RT_BIT(X86_XCPT_PF)))
10526 {
10527 u32XcptPFMask = pVmcsNstGst->u32XcptPFMask;
10528 u32XcptPFMatch = pVmcsNstGst->u32XcptPFMatch;
10529 }
10530 else
10531 {
10532 u32XcptPFMask = 0;
10533 u32XcptPFMatch = 0;
10534 }
10535
10536 /*
10537 * Pause-Loop exiting.
10538 */
10539 /** @todo r=bird: given that both pVM->hm.s.vmx.cPleGapTicks and
10540 * pVM->hm.s.vmx.cPleWindowTicks defaults to zero, I cannot see how
10541 * this will work... */
10542 uint32_t const cPleGapTicks = RT_MIN(pVM->hm.s.vmx.cPleGapTicks, pVmcsNstGst->u32PleGap);
10543 uint32_t const cPleWindowTicks = RT_MIN(pVM->hm.s.vmx.cPleWindowTicks, pVmcsNstGst->u32PleWindow);
10544
10545 /*
10546 * Pending debug exceptions.
10547 * Currently just copy whatever the nested-guest provides us.
10548 */
10549 uint64_t const uPendingDbgXcpts = pVmcsNstGst->u64GuestPendingDbgXcpts.u;
10550
10551 /*
10552 * I/O Bitmap.
10553 *
10554 * We do not use the I/O bitmap that may be provided by the nested hypervisor as we always
10555 * intercept all I/O port accesses.
10556 */
10557 Assert(u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT);
10558 Assert(!(u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS));
10559
10560 /*
10561 * VMCS shadowing.
10562 *
10563 * We do not yet expose VMCS shadowing to the guest and thus VMCS shadowing should not be
10564 * enabled while executing the nested-guest.
10565 */
10566 Assert(!(u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING));
10567
10568 /*
10569 * APIC-access page.
10570 */
10571 RTHCPHYS HCPhysApicAccess;
10572 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10573 {
10574 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
10575 RTGCPHYS const GCPhysApicAccess = pVmcsNstGst->u64AddrApicAccess.u;
10576
10577 /** @todo NSTVMX: This is not really correct but currently is required to make
10578 * things work. We need to re-enable the page handler when we fallback to
10579 * IEM execution of the nested-guest! */
10580 PGMHandlerPhysicalPageTempOff(pVM, GCPhysApicAccess, GCPhysApicAccess);
10581
10582 void *pvPage;
10583 PGMPAGEMAPLOCK PgLockApicAccess;
10584 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysApicAccess, &pvPage, &PgLockApicAccess);
10585 if (RT_SUCCESS(rc))
10586 {
10587 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysApicAccess, &HCPhysApicAccess);
10588 AssertMsgRCReturn(rc, ("Failed to get host-physical address for APIC-access page at %#RGp\n", GCPhysApicAccess), rc);
10589
10590 /** @todo Handle proper releasing of page-mapping lock later. */
10591 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockApicAccess);
10592 }
10593 else
10594 return rc;
10595 }
10596 else
10597 HCPhysApicAccess = 0;
10598
10599 /*
10600 * Virtual-APIC page and TPR threshold.
10601 */
10602 RTHCPHYS HCPhysVirtApic;
10603 uint32_t u32TprThreshold;
10604 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10605 {
10606 Assert(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW);
10607 RTGCPHYS const GCPhysVirtApic = pVmcsNstGst->u64AddrVirtApic.u;
10608
10609 void *pvPage;
10610 PGMPAGEMAPLOCK PgLockVirtApic;
10611 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysVirtApic, &pvPage, &PgLockVirtApic);
10612 if (RT_SUCCESS(rc))
10613 {
10614 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysVirtApic, &HCPhysVirtApic);
10615 AssertMsgRCReturn(rc, ("Failed to get host-physical address for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10616
10617 /** @todo Handle proper releasing of page-mapping lock later. */
10618 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockVirtApic);
10619 }
10620 else
10621 return rc;
10622
10623 u32TprThreshold = pVmcsNstGst->u32TprThreshold;
10624 }
10625 else
10626 {
10627 HCPhysVirtApic = 0;
10628 u32TprThreshold = 0;
10629
10630 /*
10631 * We must make sure CR8 reads/write must cause VM-exits when TPR shadowing is not
10632 * used by the nested hypervisor. Preventing MMIO accesses to the physical APIC will
10633 * be taken care of by EPT/shadow paging.
10634 */
10635 if (pVM->hmr0.s.fAllow64BitGuests)
10636 u32ProcCtls |= VMX_PROC_CTLS_CR8_STORE_EXIT
10637 | VMX_PROC_CTLS_CR8_LOAD_EXIT;
10638 }
10639
10640 /*
10641 * Validate basic assumptions.
10642 */
10643 PVMXVMCSINFO pVmcsInfoNstGst = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
10644 Assert(pVM->hmr0.s.vmx.fUnrestrictedGuest);
10645 Assert(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
10646 Assert(hmGetVmxActiveVmcsInfo(pVCpu) == pVmcsInfoNstGst);
10647
10648 /*
10649 * Commit it to the nested-guest VMCS.
10650 */
10651 int rc = VINF_SUCCESS;
10652 if (pVmcsInfoNstGst->u32PinCtls != u32PinCtls)
10653 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, u32PinCtls);
10654 if (pVmcsInfoNstGst->u32ProcCtls != u32ProcCtls)
10655 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, u32ProcCtls);
10656 if (pVmcsInfoNstGst->u32ProcCtls2 != u32ProcCtls2)
10657 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, u32ProcCtls2);
10658 if (pVmcsInfoNstGst->u32XcptBitmap != u32XcptBitmap)
10659 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
10660 if (pVmcsInfoNstGst->u64Cr0Mask != u64Cr0Mask)
10661 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask);
10662 if (pVmcsInfoNstGst->u64Cr4Mask != u64Cr4Mask)
10663 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask);
10664 if (pVmcsInfoNstGst->u32XcptPFMask != u32XcptPFMask)
10665 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, u32XcptPFMask);
10666 if (pVmcsInfoNstGst->u32XcptPFMatch != u32XcptPFMatch)
10667 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, u32XcptPFMatch);
10668 if ( !(u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
10669 && (u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10670 {
10671 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT);
10672 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, cPleGapTicks);
10673 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, cPleWindowTicks);
10674 }
10675 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10676 {
10677 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
10678 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
10679 }
10680 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10681 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
10682 rc |= VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, uPendingDbgXcpts);
10683 AssertRC(rc);
10684
10685 /*
10686 * Update the nested-guest VMCS cache.
10687 */
10688 pVmcsInfoNstGst->u32PinCtls = u32PinCtls;
10689 pVmcsInfoNstGst->u32ProcCtls = u32ProcCtls;
10690 pVmcsInfoNstGst->u32ProcCtls2 = u32ProcCtls2;
10691 pVmcsInfoNstGst->u32XcptBitmap = u32XcptBitmap;
10692 pVmcsInfoNstGst->u64Cr0Mask = u64Cr0Mask;
10693 pVmcsInfoNstGst->u64Cr4Mask = u64Cr4Mask;
10694 pVmcsInfoNstGst->u32XcptPFMask = u32XcptPFMask;
10695 pVmcsInfoNstGst->u32XcptPFMatch = u32XcptPFMatch;
10696 pVmcsInfoNstGst->HCPhysVirtApic = HCPhysVirtApic;
10697
10698 /*
10699 * We need to flush the TLB if we are switching the APIC-access page address.
10700 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
10701 */
10702 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10703 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = true;
10704
10705 /*
10706 * MSR bitmap.
10707 *
10708 * The MSR bitmap address has already been initialized while setting up the nested-guest
10709 * VMCS, here we need to merge the MSR bitmaps.
10710 */
10711 if (u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10712 hmR0VmxMergeMsrBitmapNested(pVCpu, pVmcsInfoNstGst, pVmcsInfoGst);
10713
10714 return VINF_SUCCESS;
10715}
10716#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10717
10718
10719/**
10720 * Does the preparations before executing guest code in VT-x.
10721 *
10722 * This may cause longjmps to ring-3 and may even result in rescheduling to the
10723 * recompiler/IEM. We must be cautious what we do here regarding committing
10724 * guest-state information into the VMCS assuming we assuredly execute the
10725 * guest in VT-x mode.
10726 *
10727 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
10728 * the common-state (TRPM/forceflags), we must undo those changes so that the
10729 * recompiler/IEM can (and should) use them when it resumes guest execution.
10730 * Otherwise such operations must be done when we can no longer exit to ring-3.
10731 *
10732 * @returns Strict VBox status code (i.e. informational status codes too).
10733 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
10734 * have been disabled.
10735 * @retval VINF_VMX_VMEXIT if a nested-guest VM-exit occurs (e.g., while evaluating
10736 * pending events).
10737 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
10738 * double-fault into the guest.
10739 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
10740 * dispatched directly.
10741 * @retval VINF_* scheduling changes, we have to go back to ring-3.
10742 *
10743 * @param pVCpu The cross context virtual CPU structure.
10744 * @param pVmxTransient The VMX-transient structure.
10745 * @param fStepping Whether we are single-stepping the guest in the
10746 * hypervisor debugger. Makes us ignore some of the reasons
10747 * for returning to ring-3, and return VINF_EM_DBG_STEPPED
10748 * if event dispatching took place.
10749 */
10750static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, bool fStepping)
10751{
10752 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10753
10754 Log4Func(("fIsNested=%RTbool fStepping=%RTbool\n", pVmxTransient->fIsNestedGuest, fStepping));
10755
10756#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
10757 if (pVmxTransient->fIsNestedGuest)
10758 {
10759 RT_NOREF2(pVCpu, fStepping);
10760 Log2Func(("Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
10761 return VINF_EM_RESCHEDULE_REM;
10762 }
10763#endif
10764
10765 /*
10766 * Check and process force flag actions, some of which might require us to go back to ring-3.
10767 */
10768 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVCpu, pVmxTransient, fStepping);
10769 if (rcStrict == VINF_SUCCESS)
10770 {
10771 /* FFs don't get set all the time. */
10772#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10773 if ( pVmxTransient->fIsNestedGuest
10774 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10775 {
10776 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10777 return VINF_VMX_VMEXIT;
10778 }
10779#endif
10780 }
10781 else
10782 return rcStrict;
10783
10784 /*
10785 * Virtualize memory-mapped accesses to the physical APIC (may take locks).
10786 */
10787 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10788 if ( !pVCpu->hm.s.vmx.u64GstMsrApicBase
10789 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10790 && PDMHasApic(pVM))
10791 {
10792 int rc = hmR0VmxMapHCApicAccessPage(pVCpu);
10793 AssertRCReturn(rc, rc);
10794 }
10795
10796#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10797 /*
10798 * Merge guest VMCS controls with the nested-guest VMCS controls.
10799 *
10800 * Even if we have not executed the guest prior to this (e.g. when resuming from a
10801 * saved state), we should be okay with merging controls as we initialize the
10802 * guest VMCS controls as part of VM setup phase.
10803 */
10804 if ( pVmxTransient->fIsNestedGuest
10805 && !pVCpu->hm.s.vmx.fMergedNstGstCtls)
10806 {
10807 int rc = hmR0VmxMergeVmcsNested(pVCpu);
10808 AssertRCReturn(rc, rc);
10809 pVCpu->hm.s.vmx.fMergedNstGstCtls = true;
10810 }
10811#endif
10812
10813 /*
10814 * Evaluate events to be injected into the guest.
10815 *
10816 * Events in TRPM can be injected without inspecting the guest state.
10817 * If any new events (interrupts/NMI) are pending currently, we try to set up the
10818 * guest to cause a VM-exit the next time they are ready to receive the event.
10819 *
10820 * With nested-guests, evaluating pending events may cause VM-exits. Also, verify
10821 * that the event in TRPM that we will inject using hardware-assisted VMX is -not-
10822 * subject to interecption. Otherwise, we should have checked and injected them
10823 * manually elsewhere (IEM).
10824 */
10825 if (TRPMHasTrap(pVCpu))
10826 {
10827 Assert(!pVmxTransient->fIsNestedGuest || !CPUMIsGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx));
10828 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
10829 }
10830
10831 uint32_t fIntrState;
10832 rcStrict = hmR0VmxEvaluatePendingEvent(pVCpu, pVmxTransient, &fIntrState);
10833
10834#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10835 /*
10836 * While evaluating pending events if something failed (unlikely) or if we were
10837 * preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
10838 */
10839 if (rcStrict != VINF_SUCCESS)
10840 return rcStrict;
10841 if ( pVmxTransient->fIsNestedGuest
10842 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10843 {
10844 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10845 return VINF_VMX_VMEXIT;
10846 }
10847#else
10848 Assert(rcStrict == VINF_SUCCESS);
10849#endif
10850
10851 /*
10852 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
10853 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
10854 * also result in triple-faulting the VM.
10855 *
10856 * With nested-guests, the above does not apply since unrestricted guest execution is a
10857 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
10858 */
10859 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
10860 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10861 { /* likely */ }
10862 else
10863 {
10864 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
10865 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
10866 return rcStrict;
10867 }
10868
10869 /*
10870 * A longjump might result in importing CR3 even for VM-exits that don't necessarily
10871 * import CR3 themselves. We will need to update them here, as even as late as the above
10872 * hmR0VmxInjectPendingEvent() call may lazily import guest-CPU state on demand causing
10873 * the below force flags to be set.
10874 */
10875 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
10876 {
10877 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
10878 int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu));
10879 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
10880 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
10881 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10882 }
10883 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES))
10884 {
10885 PGMGstUpdatePaePdpes(pVCpu, &pVCpu->hm.s.aPdpes[0]);
10886 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
10887 }
10888
10889#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10890 /* Paranoia. */
10891 Assert(!pVmxTransient->fIsNestedGuest || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10892#endif
10893
10894 /*
10895 * No longjmps to ring-3 from this point on!!!
10896 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
10897 * This also disables flushing of the R0-logger instance (if any).
10898 */
10899 VMMRZCallRing3Disable(pVCpu);
10900
10901 /*
10902 * Export the guest state bits.
10903 *
10904 * We cannot perform longjmps while loading the guest state because we do not preserve the
10905 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
10906 * CPU migration.
10907 *
10908 * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
10909 * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
10910 */
10911 rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
10912 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10913 { /* likely */ }
10914 else
10915 {
10916 VMMRZCallRing3Enable(pVCpu);
10917 return rcStrict;
10918 }
10919
10920 /*
10921 * We disable interrupts so that we don't miss any interrupts that would flag preemption
10922 * (IPI/timers etc.) when thread-context hooks aren't used and we've been running with
10923 * preemption disabled for a while. Since this is purely to aid the
10924 * RTThreadPreemptIsPending() code, it doesn't matter that it may temporarily reenable and
10925 * disable interrupt on NT.
10926 *
10927 * We need to check for force-flags that could've possible been altered since we last
10928 * checked them (e.g. by PDMGetInterrupt() leaving the PDM critical section,
10929 * see @bugref{6398}).
10930 *
10931 * We also check a couple of other force-flags as a last opportunity to get the EMT back
10932 * to ring-3 before executing guest code.
10933 */
10934 pVmxTransient->fEFlags = ASMIntDisableFlags();
10935
10936 if ( ( !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
10937 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
10938 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
10939 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
10940 {
10941 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
10942 {
10943#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10944 /*
10945 * If we are executing a nested-guest make sure that we should intercept subsequent
10946 * events. The one we are injecting might be part of VM-entry. This is mainly to keep
10947 * the VM-exit instruction emulation happy.
10948 */
10949 if (pVmxTransient->fIsNestedGuest)
10950 CPUMSetGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx, true);
10951#endif
10952
10953 /*
10954 * We've injected any pending events. This is really the point of no return (to ring-3).
10955 *
10956 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
10957 * returns from this function, so do -not- enable them here.
10958 */
10959 pVCpu->hm.s.Event.fPending = false;
10960 return VINF_SUCCESS;
10961 }
10962
10963 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPendingHostIrq);
10964 rcStrict = VINF_EM_RAW_INTERRUPT;
10965 }
10966 else
10967 {
10968 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
10969 rcStrict = VINF_EM_RAW_TO_R3;
10970 }
10971
10972 ASMSetFlags(pVmxTransient->fEFlags);
10973 VMMRZCallRing3Enable(pVCpu);
10974
10975 return rcStrict;
10976}
10977
10978
10979/**
10980 * Final preparations before executing guest code using hardware-assisted VMX.
10981 *
10982 * We can no longer get preempted to a different host CPU and there are no returns
10983 * to ring-3. We ignore any errors that may happen from this point (e.g. VMWRITE
10984 * failures), this function is not intended to fail sans unrecoverable hardware
10985 * errors.
10986 *
10987 * @param pVCpu The cross context virtual CPU structure.
10988 * @param pVmxTransient The VMX-transient structure.
10989 *
10990 * @remarks Called with preemption disabled.
10991 * @remarks No-long-jump zone!!!
10992 */
10993static void hmR0VmxPreRunGuestCommitted(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10994{
10995 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10996 Assert(VMMR0IsLogFlushDisabled(pVCpu));
10997 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
10998 Assert(!pVCpu->hm.s.Event.fPending);
10999
11000 /*
11001 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
11002 */
11003 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
11004 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
11005
11006 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11007 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11008 PHMPHYSCPU pHostCpu = hmR0GetCurrentCpu();
11009 RTCPUID const idCurrentCpu = pHostCpu->idCpu;
11010
11011 if (!CPUMIsGuestFPUStateActive(pVCpu))
11012 {
11013 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestFpuState, x);
11014 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
11015 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_HOST_CONTEXT;
11016 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestFpuState, x);
11017 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadGuestFpu);
11018 }
11019
11020 /*
11021 * Re-export the host state bits as we may've been preempted (only happens when
11022 * thread-context hooks are used or when the VM start function changes) or if
11023 * the host CR0 is modified while loading the guest FPU state above.
11024 *
11025 * The 64-on-32 switcher saves the (64-bit) host state into the VMCS and if we
11026 * changed the switcher back to 32-bit, we *must* save the 32-bit host state here,
11027 * see @bugref{8432}.
11028 *
11029 * This may also happen when switching to/from a nested-guest VMCS without leaving
11030 * ring-0.
11031 */
11032 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
11033 {
11034 hmR0VmxExportHostState(pVCpu);
11035 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportHostState);
11036 }
11037 Assert(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT));
11038
11039 /*
11040 * Export the state shared between host and guest (FPU, debug, lazy MSRs).
11041 */
11042 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)
11043 hmR0VmxExportSharedState(pVCpu, pVmxTransient);
11044 AssertMsg(!pVCpu->hm.s.fCtxChanged, ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
11045
11046 /*
11047 * Store status of the shared guest/host debug state at the time of VM-entry.
11048 */
11049 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
11050 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
11051
11052 /*
11053 * Always cache the TPR-shadow if the virtual-APIC page exists, thereby skipping
11054 * more than one conditional check. The post-run side of our code shall determine
11055 * if it needs to sync. the virtual APIC TPR with the TPR-shadow.
11056 */
11057 if (pVmcsInfo->pbVirtApic)
11058 pVmxTransient->u8GuestTpr = pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR];
11059
11060 /*
11061 * Update the host MSRs values in the VM-exit MSR-load area.
11062 */
11063 if (!pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs)
11064 {
11065 if (pVmcsInfo->cExitMsrLoad > 0)
11066 hmR0VmxUpdateAutoLoadHostMsrs(pVCpu, pVmcsInfo);
11067 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = true;
11068 }
11069
11070 /*
11071 * Evaluate if we need to intercept guest RDTSC/P accesses. Set up the
11072 * VMX-preemption timer based on the next virtual sync clock deadline.
11073 */
11074 if ( !pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer
11075 || idCurrentCpu != pVCpu->hmr0.s.idLastCpu)
11076 {
11077 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pVmxTransient, idCurrentCpu);
11078 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = true;
11079 }
11080
11081 /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
11082 bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
11083 if (!fIsRdtscIntercepted)
11084 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
11085 else
11086 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
11087
11088 ASMAtomicUoWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
11089 hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo); /* Invalidate the appropriate guest entries from the TLB. */
11090 Assert(idCurrentCpu == pVCpu->hmr0.s.idLastCpu);
11091 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Record the error reporting info. with the current host CPU. */
11092 pVmcsInfo->idHostCpuState = idCurrentCpu; /* Record the CPU for which the host-state has been exported. */
11093 pVmcsInfo->idHostCpuExec = idCurrentCpu; /* Record the CPU on which we shall execute. */
11094
11095 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
11096
11097 TMNotifyStartOfExecution(pVM, pVCpu); /* Notify TM to resume its clocks when TSC is tied to execution,
11098 as we're about to start executing the guest. */
11099
11100 /*
11101 * Load the guest TSC_AUX MSR when we are not intercepting RDTSCP.
11102 *
11103 * This is done this late as updating the TSC offsetting/preemption timer above
11104 * figures out if we can skip intercepting RDTSCP by calculating the number of
11105 * host CPU ticks till the next virtual sync deadline (for the dynamic case).
11106 */
11107 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
11108 && !fIsRdtscIntercepted)
11109 {
11110 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
11111
11112 /* NB: Because we call hmR0VmxAddAutoLoadStoreMsr with fUpdateHostMsr=true,
11113 it's safe even after hmR0VmxUpdateAutoLoadHostMsrs has already been done. */
11114 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX, CPUMGetGuestTscAux(pVCpu),
11115 true /* fSetReadWrite */, true /* fUpdateHostMsr */);
11116 AssertRC(rc);
11117 Assert(!pVmxTransient->fRemoveTscAuxMsr);
11118 pVmxTransient->fRemoveTscAuxMsr = true;
11119 }
11120
11121#ifdef VBOX_STRICT
11122 Assert(pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs);
11123 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
11124 hmR0VmxCheckHostEferMsr(pVmcsInfo);
11125 AssertRC(hmR0VmxCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest));
11126#endif
11127
11128#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
11129 /** @todo r=ramshankar: We can now probably use iemVmxVmentryCheckGuestState here.
11130 * Add a PVMXMSRS parameter to it, so that IEM can look at the host MSRs,
11131 * see @bugref{9180#c54}. */
11132 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
11133 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
11134 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
11135#endif
11136}
11137
11138
11139/**
11140 * First C routine invoked after running guest code using hardware-assisted VMX.
11141 *
11142 * @param pVCpu The cross context virtual CPU structure.
11143 * @param pVmxTransient The VMX-transient structure.
11144 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
11145 *
11146 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
11147 *
11148 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
11149 * unconditionally when it is safe to do so.
11150 */
11151static void hmR0VmxPostRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, int rcVMRun)
11152{
11153 ASMAtomicUoWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
11154 ASMAtomicIncU32(&pVCpu->hmr0.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
11155 pVCpu->hm.s.fCtxChanged = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
11156 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
11157 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
11158 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
11159
11160 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11161 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
11162 {
11163 uint64_t uGstTsc;
11164 if (!pVmxTransient->fIsNestedGuest)
11165 uGstTsc = pVCpu->hmr0.s.uTscExit + pVmcsInfo->u64TscOffset;
11166 else
11167 {
11168 uint64_t const uNstGstTsc = pVCpu->hmr0.s.uTscExit + pVmcsInfo->u64TscOffset;
11169 uGstTsc = CPUMRemoveNestedGuestTscOffset(pVCpu, uNstGstTsc);
11170 }
11171 TMCpuTickSetLastSeen(pVCpu, uGstTsc); /* Update TM with the guest TSC. */
11172 }
11173
11174 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatPreExit, x);
11175 TMNotifyEndOfExecution(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->hmr0.s.uTscExit); /* Notify TM that the guest is no longer running. */
11176 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
11177
11178 pVCpu->hmr0.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Some host state messed up by VMX needs restoring. */
11179 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
11180#ifdef VBOX_STRICT
11181 hmR0VmxCheckHostEferMsr(pVmcsInfo); /* Verify that the host EFER MSR wasn't modified. */
11182#endif
11183 Assert(!ASMIntAreEnabled());
11184 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
11185 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
11186
11187#ifdef HMVMX_ALWAYS_CLEAN_TRANSIENT
11188 /*
11189 * Clean all the VMCS fields in the transient structure before reading
11190 * anything from the VMCS.
11191 */
11192 pVmxTransient->uExitReason = 0;
11193 pVmxTransient->uExitIntErrorCode = 0;
11194 pVmxTransient->uExitQual = 0;
11195 pVmxTransient->uGuestLinearAddr = 0;
11196 pVmxTransient->uExitIntInfo = 0;
11197 pVmxTransient->cbExitInstr = 0;
11198 pVmxTransient->ExitInstrInfo.u = 0;
11199 pVmxTransient->uEntryIntInfo = 0;
11200 pVmxTransient->uEntryXcptErrorCode = 0;
11201 pVmxTransient->cbEntryInstr = 0;
11202 pVmxTransient->uIdtVectoringInfo = 0;
11203 pVmxTransient->uIdtVectoringErrorCode = 0;
11204#endif
11205
11206 /*
11207 * Save the basic VM-exit reason and check if the VM-entry failed.
11208 * See Intel spec. 24.9.1 "Basic VM-exit Information".
11209 */
11210 uint32_t uExitReason;
11211 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
11212 AssertRC(rc);
11213 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
11214 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
11215
11216 /*
11217 * Log the VM-exit before logging anything else as otherwise it might be a
11218 * tad confusing what happens before and after the world-switch.
11219 */
11220 HMVMX_LOG_EXIT(pVCpu, uExitReason);
11221
11222 /*
11223 * Remove the TSC_AUX MSR from the auto-load/store MSR area and reset any MSR
11224 * bitmap permissions, if it was added before VM-entry.
11225 */
11226 if (pVmxTransient->fRemoveTscAuxMsr)
11227 {
11228 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX);
11229 pVmxTransient->fRemoveTscAuxMsr = false;
11230 }
11231
11232 /*
11233 * Check if VMLAUNCH/VMRESUME succeeded.
11234 * If this failed, we cause a guru meditation and cease further execution.
11235 *
11236 * However, if we are executing a nested-guest we might fail if we use the
11237 * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
11238 */
11239 if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
11240 {
11241 /*
11242 * Update the VM-exit history array here even if the VM-entry failed due to:
11243 * - Invalid guest state.
11244 * - MSR loading.
11245 * - Machine-check event.
11246 *
11247 * In any of the above cases we will still have a "valid" VM-exit reason
11248 * despite @a fVMEntryFailed being false.
11249 *
11250 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
11251 *
11252 * Note! We don't have CS or RIP at this point. Will probably address that later
11253 * by amending the history entry added here.
11254 */
11255 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_VMX, pVmxTransient->uExitReason & EMEXIT_F_TYPE_MASK),
11256 UINT64_MAX, pVCpu->hmr0.s.uTscExit);
11257
11258 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
11259 {
11260 VMMRZCallRing3Enable(pVCpu);
11261
11262 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
11263 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
11264
11265#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
11266 hmR0VmxReadAllRoFieldsVmcs(pVmxTransient);
11267#endif
11268
11269 /*
11270 * Import the guest-interruptibility state always as we need it while evaluating
11271 * injecting events on re-entry.
11272 *
11273 * We don't import CR0 (when unrestricted guest execution is unavailable) despite
11274 * checking for real-mode while exporting the state because all bits that cause
11275 * mode changes wrt CR0 are intercepted.
11276 */
11277 uint64_t const fImportMask = CPUMCTX_EXTRN_HM_VMX_INT_STATE
11278#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
11279 | HMVMX_CPUMCTX_EXTRN_ALL
11280#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
11281 | CPUMCTX_EXTRN_RFLAGS
11282#endif
11283 ;
11284 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImportMask);
11285 AssertRC(rc);
11286
11287 /*
11288 * Sync the TPR shadow with our APIC state.
11289 */
11290 if ( !pVmxTransient->fIsNestedGuest
11291 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
11292 {
11293 Assert(pVmcsInfo->pbVirtApic);
11294 if (pVmxTransient->u8GuestTpr != pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR])
11295 {
11296 rc = APICSetTpr(pVCpu, pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR]);
11297 AssertRC(rc);
11298 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
11299 }
11300 }
11301
11302 Assert(VMMRZCallRing3IsEnabled(pVCpu));
11303 return;
11304 }
11305 }
11306#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11307 else if (pVmxTransient->fIsNestedGuest)
11308 AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
11309#endif
11310 else
11311 Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
11312
11313 VMMRZCallRing3Enable(pVCpu);
11314}
11315
11316
11317/**
11318 * Runs the guest code using hardware-assisted VMX the normal way.
11319 *
11320 * @returns VBox status code.
11321 * @param pVCpu The cross context virtual CPU structure.
11322 * @param pcLoops Pointer to the number of executed loops.
11323 */
11324static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVMCPUCC pVCpu, uint32_t *pcLoops)
11325{
11326 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
11327 Assert(pcLoops);
11328 Assert(*pcLoops <= cMaxResumeLoops);
11329 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
11330
11331#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11332 /*
11333 * Switch to the guest VMCS as we may have transitioned from executing the nested-guest
11334 * without leaving ring-0. Otherwise, if we came from ring-3 we would have loaded the
11335 * guest VMCS while entering the VMX ring-0 session.
11336 */
11337 if (pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
11338 {
11339 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, false /* fSwitchToNstGstVmcs */);
11340 if (RT_SUCCESS(rc))
11341 { /* likely */ }
11342 else
11343 {
11344 LogRelFunc(("Failed to switch to the guest VMCS. rc=%Rrc\n", rc));
11345 return rc;
11346 }
11347 }
11348#endif
11349
11350 VMXTRANSIENT VmxTransient;
11351 RT_ZERO(VmxTransient);
11352 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
11353
11354 /* Paranoia. */
11355 Assert(VmxTransient.pVmcsInfo == &pVCpu->hmr0.s.vmx.VmcsInfo);
11356
11357 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
11358 for (;;)
11359 {
11360 Assert(!HMR0SuspendPending());
11361 HMVMX_ASSERT_CPU_SAFE(pVCpu);
11362 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
11363
11364 /*
11365 * Preparatory work for running nested-guest code, this may force us to
11366 * return to ring-3.
11367 *
11368 * Warning! This bugger disables interrupts on VINF_SUCCESS!
11369 */
11370 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
11371 if (rcStrict != VINF_SUCCESS)
11372 break;
11373
11374 /* Interrupts are disabled at this point! */
11375 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
11376 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
11377 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
11378 /* Interrupts are re-enabled at this point! */
11379
11380 /*
11381 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
11382 */
11383 if (RT_SUCCESS(rcRun))
11384 { /* very likely */ }
11385 else
11386 {
11387 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
11388 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
11389 return rcRun;
11390 }
11391
11392 /*
11393 * Profile the VM-exit.
11394 */
11395 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
11396 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
11397 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
11398 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
11399 HMVMX_START_EXIT_DISPATCH_PROF();
11400
11401 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
11402
11403 /*
11404 * Handle the VM-exit.
11405 */
11406#ifdef HMVMX_USE_FUNCTION_TABLE
11407 rcStrict = g_aVMExitHandlers[VmxTransient.uExitReason].pfn(pVCpu, &VmxTransient);
11408#else
11409 rcStrict = hmR0VmxHandleExit(pVCpu, &VmxTransient);
11410#endif
11411 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
11412 if (rcStrict == VINF_SUCCESS)
11413 {
11414 if (++(*pcLoops) <= cMaxResumeLoops)
11415 continue;
11416 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
11417 rcStrict = VINF_EM_RAW_INTERRUPT;
11418 }
11419 break;
11420 }
11421
11422 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11423 return rcStrict;
11424}
11425
11426
11427#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11428/**
11429 * Runs the nested-guest code using hardware-assisted VMX.
11430 *
11431 * @returns VBox status code.
11432 * @param pVCpu The cross context virtual CPU structure.
11433 * @param pcLoops Pointer to the number of executed loops.
11434 *
11435 * @sa hmR0VmxRunGuestCodeNormal.
11436 */
11437static VBOXSTRICTRC hmR0VmxRunGuestCodeNested(PVMCPUCC pVCpu, uint32_t *pcLoops)
11438{
11439 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
11440 Assert(pcLoops);
11441 Assert(*pcLoops <= cMaxResumeLoops);
11442 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
11443
11444 /*
11445 * Switch to the nested-guest VMCS as we may have transitioned from executing the
11446 * guest without leaving ring-0. Otherwise, if we came from ring-3 we would have
11447 * loaded the nested-guest VMCS while entering the VMX ring-0 session.
11448 */
11449 if (!pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
11450 {
11451 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, true /* fSwitchToNstGstVmcs */);
11452 if (RT_SUCCESS(rc))
11453 { /* likely */ }
11454 else
11455 {
11456 LogRelFunc(("Failed to switch to the nested-guest VMCS. rc=%Rrc\n", rc));
11457 return rc;
11458 }
11459 }
11460
11461 VMXTRANSIENT VmxTransient;
11462 RT_ZERO(VmxTransient);
11463 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
11464 VmxTransient.fIsNestedGuest = true;
11465
11466 /* Paranoia. */
11467 Assert(VmxTransient.pVmcsInfo == &pVCpu->hmr0.s.vmx.VmcsInfoNstGst);
11468
11469 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
11470 for (;;)
11471 {
11472 Assert(!HMR0SuspendPending());
11473 HMVMX_ASSERT_CPU_SAFE(pVCpu);
11474 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
11475
11476 /*
11477 * Preparatory work for running guest code, this may force us to
11478 * return to ring-3.
11479 *
11480 * Warning! This bugger disables interrupts on VINF_SUCCESS!
11481 */
11482 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
11483 if (rcStrict != VINF_SUCCESS)
11484 break;
11485
11486 /* Interrupts are disabled at this point! */
11487 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
11488 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
11489 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
11490 /* Interrupts are re-enabled at this point! */
11491
11492 /*
11493 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
11494 */
11495 if (RT_SUCCESS(rcRun))
11496 { /* very likely */ }
11497 else
11498 {
11499 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
11500 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
11501 return rcRun;
11502 }
11503
11504 /*
11505 * Profile the VM-exit.
11506 */
11507 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
11508 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
11509 STAM_COUNTER_INC(&pVCpu->hm.s.StatNestedExitAll);
11510 STAM_COUNTER_INC(&pVCpu->hm.s.paStatNestedExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
11511 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
11512 HMVMX_START_EXIT_DISPATCH_PROF();
11513
11514 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
11515
11516 /*
11517 * Handle the VM-exit.
11518 */
11519 rcStrict = hmR0VmxHandleExitNested(pVCpu, &VmxTransient);
11520 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
11521 if (rcStrict == VINF_SUCCESS)
11522 {
11523 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
11524 {
11525 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
11526 rcStrict = VINF_VMX_VMEXIT;
11527 }
11528 else
11529 {
11530 if (++(*pcLoops) <= cMaxResumeLoops)
11531 continue;
11532 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
11533 rcStrict = VINF_EM_RAW_INTERRUPT;
11534 }
11535 }
11536 else
11537 Assert(rcStrict != VINF_VMX_VMEXIT);
11538 break;
11539 }
11540
11541 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11542 return rcStrict;
11543}
11544#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
11545
11546
11547/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
11548 * probes.
11549 *
11550 * The following few functions and associated structure contains the bloat
11551 * necessary for providing detailed debug events and dtrace probes as well as
11552 * reliable host side single stepping. This works on the principle of
11553 * "subclassing" the normal execution loop and workers. We replace the loop
11554 * method completely and override selected helpers to add necessary adjustments
11555 * to their core operation.
11556 *
11557 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
11558 * any performance for debug and analysis features.
11559 *
11560 * @{
11561 */
11562
11563/**
11564 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11565 * the debug run loop.
11566 */
11567typedef struct VMXRUNDBGSTATE
11568{
11569 /** The RIP we started executing at. This is for detecting that we stepped. */
11570 uint64_t uRipStart;
11571 /** The CS we started executing with. */
11572 uint16_t uCsStart;
11573
11574 /** Whether we've actually modified the 1st execution control field. */
11575 bool fModifiedProcCtls : 1;
11576 /** Whether we've actually modified the 2nd execution control field. */
11577 bool fModifiedProcCtls2 : 1;
11578 /** Whether we've actually modified the exception bitmap. */
11579 bool fModifiedXcptBitmap : 1;
11580
11581 /** We desire the modified the CR0 mask to be cleared. */
11582 bool fClearCr0Mask : 1;
11583 /** We desire the modified the CR4 mask to be cleared. */
11584 bool fClearCr4Mask : 1;
11585 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11586 uint32_t fCpe1Extra;
11587 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11588 uint32_t fCpe1Unwanted;
11589 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11590 uint32_t fCpe2Extra;
11591 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11592 uint32_t bmXcptExtra;
11593 /** The sequence number of the Dtrace provider settings the state was
11594 * configured against. */
11595 uint32_t uDtraceSettingsSeqNo;
11596 /** VM-exits to check (one bit per VM-exit). */
11597 uint32_t bmExitsToCheck[3];
11598
11599 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11600 uint32_t fProcCtlsInitial;
11601 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11602 uint32_t fProcCtls2Initial;
11603 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11604 uint32_t bmXcptInitial;
11605} VMXRUNDBGSTATE;
11606AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11607typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11608
11609
11610/**
11611 * Initializes the VMXRUNDBGSTATE structure.
11612 *
11613 * @param pVCpu The cross context virtual CPU structure of the
11614 * calling EMT.
11615 * @param pVmxTransient The VMX-transient structure.
11616 * @param pDbgState The debug state to initialize.
11617 */
11618static void hmR0VmxRunDebugStateInit(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11619{
11620 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11621 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11622
11623 pDbgState->fModifiedProcCtls = false;
11624 pDbgState->fModifiedProcCtls2 = false;
11625 pDbgState->fModifiedXcptBitmap = false;
11626 pDbgState->fClearCr0Mask = false;
11627 pDbgState->fClearCr4Mask = false;
11628 pDbgState->fCpe1Extra = 0;
11629 pDbgState->fCpe1Unwanted = 0;
11630 pDbgState->fCpe2Extra = 0;
11631 pDbgState->bmXcptExtra = 0;
11632 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11633 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11634 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11635}
11636
11637
11638/**
11639 * Updates the VMSC fields with changes requested by @a pDbgState.
11640 *
11641 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11642 * immediately before executing guest code, i.e. when interrupts are disabled.
11643 * We don't check status codes here as we cannot easily assert or return in the
11644 * latter case.
11645 *
11646 * @param pVCpu The cross context virtual CPU structure.
11647 * @param pVmxTransient The VMX-transient structure.
11648 * @param pDbgState The debug state.
11649 */
11650static void hmR0VmxPreRunGuestDebugStateApply(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11651{
11652 /*
11653 * Ensure desired flags in VMCS control fields are set.
11654 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11655 *
11656 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11657 * there should be no stale data in pCtx at this point.
11658 */
11659 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11660 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11661 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11662 {
11663 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11664 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11665 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11666 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11667 pDbgState->fModifiedProcCtls = true;
11668 }
11669
11670 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11671 {
11672 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11673 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11674 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11675 pDbgState->fModifiedProcCtls2 = true;
11676 }
11677
11678 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11679 {
11680 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11681 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11682 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11683 pDbgState->fModifiedXcptBitmap = true;
11684 }
11685
11686 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11687 {
11688 pVmcsInfo->u64Cr0Mask = 0;
11689 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, 0);
11690 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11691 }
11692
11693 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11694 {
11695 pVmcsInfo->u64Cr4Mask = 0;
11696 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, 0);
11697 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11698 }
11699
11700 NOREF(pVCpu);
11701}
11702
11703
11704/**
11705 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11706 * re-entry next time around.
11707 *
11708 * @returns Strict VBox status code (i.e. informational status codes too).
11709 * @param pVCpu The cross context virtual CPU structure.
11710 * @param pVmxTransient The VMX-transient structure.
11711 * @param pDbgState The debug state.
11712 * @param rcStrict The return code from executing the guest using single
11713 * stepping.
11714 */
11715static VBOXSTRICTRC hmR0VmxRunDebugStateRevert(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11716 VBOXSTRICTRC rcStrict)
11717{
11718 /*
11719 * Restore VM-exit control settings as we may not reenter this function the
11720 * next time around.
11721 */
11722 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11723
11724 /* We reload the initial value, trigger what we can of recalculations the
11725 next time around. From the looks of things, that's all that's required atm. */
11726 if (pDbgState->fModifiedProcCtls)
11727 {
11728 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11729 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11730 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11731 AssertRC(rc2);
11732 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11733 }
11734
11735 /* We're currently the only ones messing with this one, so just restore the
11736 cached value and reload the field. */
11737 if ( pDbgState->fModifiedProcCtls2
11738 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11739 {
11740 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11741 AssertRC(rc2);
11742 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11743 }
11744
11745 /* If we've modified the exception bitmap, we restore it and trigger
11746 reloading and partial recalculation the next time around. */
11747 if (pDbgState->fModifiedXcptBitmap)
11748 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11749
11750 return rcStrict;
11751}
11752
11753
11754/**
11755 * Configures VM-exit controls for current DBGF and DTrace settings.
11756 *
11757 * This updates @a pDbgState and the VMCS execution control fields to reflect
11758 * the necessary VM-exits demanded by DBGF and DTrace.
11759 *
11760 * @param pVCpu The cross context virtual CPU structure.
11761 * @param pVmxTransient The VMX-transient structure. May update
11762 * fUpdatedTscOffsettingAndPreemptTimer.
11763 * @param pDbgState The debug state.
11764 */
11765static void hmR0VmxPreRunGuestDebugStateUpdate(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11766{
11767 /*
11768 * Take down the dtrace serial number so we can spot changes.
11769 */
11770 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11771 ASMCompilerBarrier();
11772
11773 /*
11774 * We'll rebuild most of the middle block of data members (holding the
11775 * current settings) as we go along here, so start by clearing it all.
11776 */
11777 pDbgState->bmXcptExtra = 0;
11778 pDbgState->fCpe1Extra = 0;
11779 pDbgState->fCpe1Unwanted = 0;
11780 pDbgState->fCpe2Extra = 0;
11781 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11782 pDbgState->bmExitsToCheck[i] = 0;
11783
11784 /*
11785 * Software interrupts (INT XXh) - no idea how to trigger these...
11786 */
11787 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11788 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11789 || VBOXVMM_INT_SOFTWARE_ENABLED())
11790 {
11791 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11792 }
11793
11794 /*
11795 * INT3 breakpoints - triggered by #BP exceptions.
11796 */
11797 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11798 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11799
11800 /*
11801 * Exception bitmap and XCPT events+probes.
11802 */
11803 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11804 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11805 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11806
11807 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11808 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11809 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11810 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11811 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11812 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11813 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11814 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11815 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11816 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11817 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11818 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11819 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11820 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11821 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11822 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11823 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11824 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11825
11826 if (pDbgState->bmXcptExtra)
11827 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11828
11829 /*
11830 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11831 *
11832 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11833 * So, when adding/changing/removing please don't forget to update it.
11834 *
11835 * Some of the macros are picking up local variables to save horizontal space,
11836 * (being able to see it in a table is the lesser evil here).
11837 */
11838#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11839 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11840 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11841#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11842 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11843 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11844 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11845 } else do { } while (0)
11846#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11847 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11848 { \
11849 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11850 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11851 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11852 } else do { } while (0)
11853#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11854 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11855 { \
11856 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11857 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11858 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11859 } else do { } while (0)
11860#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11861 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11862 { \
11863 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11864 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11865 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11866 } else do { } while (0)
11867
11868 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11869 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11870 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11871 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11872 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11873
11874 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11875 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11876 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11877 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11878 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11879 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11880 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11881 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11882 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11883 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11884 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11885 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11886 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11887 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11888 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11889 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11890 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11891 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11892 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11893 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11894 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11895 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11896 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11897 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11898 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11899 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11900 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11901 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11902 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11903 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11904 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11905 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11906 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11907 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11908 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11909 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11910
11911 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11912 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11913 {
11914 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4
11915 | CPUMCTX_EXTRN_APIC_TPR);
11916 AssertRC(rc);
11917
11918#if 0 /** @todo fix me */
11919 pDbgState->fClearCr0Mask = true;
11920 pDbgState->fClearCr4Mask = true;
11921#endif
11922 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11923 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11924 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11925 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11926 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11927 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11928 require clearing here and in the loop if we start using it. */
11929 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11930 }
11931 else
11932 {
11933 if (pDbgState->fClearCr0Mask)
11934 {
11935 pDbgState->fClearCr0Mask = false;
11936 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR0);
11937 }
11938 if (pDbgState->fClearCr4Mask)
11939 {
11940 pDbgState->fClearCr4Mask = false;
11941 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR4);
11942 }
11943 }
11944 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11945 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11946
11947 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11948 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11949 {
11950 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11951 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11952 }
11953 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11954 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11955
11956 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11957 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11958 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11959 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11960 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11961 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11962 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11963 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11964#if 0 /** @todo too slow, fix handler. */
11965 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11966#endif
11967 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11968
11969 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11970 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11971 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11972 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11973 {
11974 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11975 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11976 }
11977 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11978 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11979 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11980 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11981
11982 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11983 || IS_EITHER_ENABLED(pVM, INSTR_STR)
11984 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
11985 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
11986 {
11987 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11988 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
11989 }
11990 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
11991 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
11992 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
11993 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
11994
11995 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
11996 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
11997 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
11998 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
11999 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
12000 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
12001 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
12002 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
12003 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
12004 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
12005 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
12006 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
12007 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
12008 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
12009 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
12010 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
12011 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
12012 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
12013 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
12014 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
12015 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
12016 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
12017
12018#undef IS_EITHER_ENABLED
12019#undef SET_ONLY_XBM_IF_EITHER_EN
12020#undef SET_CPE1_XBM_IF_EITHER_EN
12021#undef SET_CPEU_XBM_IF_EITHER_EN
12022#undef SET_CPE2_XBM_IF_EITHER_EN
12023
12024 /*
12025 * Sanitize the control stuff.
12026 */
12027 pDbgState->fCpe2Extra &= g_HmMsrs.u.vmx.ProcCtls2.n.allowed1;
12028 if (pDbgState->fCpe2Extra)
12029 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
12030 pDbgState->fCpe1Extra &= g_HmMsrs.u.vmx.ProcCtls.n.allowed1;
12031 pDbgState->fCpe1Unwanted &= ~g_HmMsrs.u.vmx.ProcCtls.n.allowed0;
12032 if (pVCpu->hmr0.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
12033 {
12034 pVCpu->hmr0.s.fDebugWantRdTscExit ^= true;
12035 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
12036 }
12037
12038 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
12039 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
12040 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
12041 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
12042}
12043
12044
12045/**
12046 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
12047 * appropriate.
12048 *
12049 * The caller has checked the VM-exit against the
12050 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
12051 * already, so we don't have to do that either.
12052 *
12053 * @returns Strict VBox status code (i.e. informational status codes too).
12054 * @param pVCpu The cross context virtual CPU structure.
12055 * @param pVmxTransient The VMX-transient structure.
12056 * @param uExitReason The VM-exit reason.
12057 *
12058 * @remarks The name of this function is displayed by dtrace, so keep it short
12059 * and to the point. No longer than 33 chars long, please.
12060 */
12061static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
12062{
12063 /*
12064 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
12065 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
12066 *
12067 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
12068 * does. Must add/change/remove both places. Same ordering, please.
12069 *
12070 * Added/removed events must also be reflected in the next section
12071 * where we dispatch dtrace events.
12072 */
12073 bool fDtrace1 = false;
12074 bool fDtrace2 = false;
12075 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
12076 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
12077 uint32_t uEventArg = 0;
12078#define SET_EXIT(a_EventSubName) \
12079 do { \
12080 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
12081 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
12082 } while (0)
12083#define SET_BOTH(a_EventSubName) \
12084 do { \
12085 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
12086 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
12087 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
12088 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
12089 } while (0)
12090 switch (uExitReason)
12091 {
12092 case VMX_EXIT_MTF:
12093 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
12094
12095 case VMX_EXIT_XCPT_OR_NMI:
12096 {
12097 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
12098 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
12099 {
12100 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
12101 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
12102 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
12103 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
12104 {
12105 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
12106 {
12107 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
12108 uEventArg = pVmxTransient->uExitIntErrorCode;
12109 }
12110 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
12111 switch (enmEvent1)
12112 {
12113 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
12114 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
12115 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
12116 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
12117 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
12118 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
12119 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
12120 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
12121 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
12122 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
12123 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
12124 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
12125 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
12126 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
12127 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
12128 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
12129 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
12130 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
12131 default: break;
12132 }
12133 }
12134 else
12135 AssertFailed();
12136 break;
12137
12138 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
12139 uEventArg = idxVector;
12140 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
12141 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
12142 break;
12143 }
12144 break;
12145 }
12146
12147 case VMX_EXIT_TRIPLE_FAULT:
12148 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
12149 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
12150 break;
12151 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
12152 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
12153 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
12154 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
12155 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
12156
12157 /* Instruction specific VM-exits: */
12158 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
12159 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
12160 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
12161 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
12162 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
12163 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
12164 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
12165 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
12166 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
12167 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
12168 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
12169 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
12170 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
12171 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
12172 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
12173 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
12174 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
12175 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
12176 case VMX_EXIT_MOV_CRX:
12177 hmR0VmxReadExitQualVmcs(pVmxTransient);
12178 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
12179 SET_BOTH(CRX_READ);
12180 else
12181 SET_BOTH(CRX_WRITE);
12182 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
12183 break;
12184 case VMX_EXIT_MOV_DRX:
12185 hmR0VmxReadExitQualVmcs(pVmxTransient);
12186 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
12187 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
12188 SET_BOTH(DRX_READ);
12189 else
12190 SET_BOTH(DRX_WRITE);
12191 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
12192 break;
12193 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
12194 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
12195 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
12196 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
12197 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
12198 case VMX_EXIT_GDTR_IDTR_ACCESS:
12199 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12200 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
12201 {
12202 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
12203 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
12204 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
12205 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
12206 }
12207 break;
12208
12209 case VMX_EXIT_LDTR_TR_ACCESS:
12210 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12211 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
12212 {
12213 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
12214 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
12215 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
12216 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
12217 }
12218 break;
12219
12220 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
12221 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
12222 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
12223 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
12224 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
12225 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
12226 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
12227 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
12228 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
12229 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
12230 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
12231
12232 /* Events that aren't relevant at this point. */
12233 case VMX_EXIT_EXT_INT:
12234 case VMX_EXIT_INT_WINDOW:
12235 case VMX_EXIT_NMI_WINDOW:
12236 case VMX_EXIT_TPR_BELOW_THRESHOLD:
12237 case VMX_EXIT_PREEMPT_TIMER:
12238 case VMX_EXIT_IO_INSTR:
12239 break;
12240
12241 /* Errors and unexpected events. */
12242 case VMX_EXIT_INIT_SIGNAL:
12243 case VMX_EXIT_SIPI:
12244 case VMX_EXIT_IO_SMI:
12245 case VMX_EXIT_SMI:
12246 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12247 case VMX_EXIT_ERR_MSR_LOAD:
12248 case VMX_EXIT_ERR_MACHINE_CHECK:
12249 case VMX_EXIT_PML_FULL:
12250 case VMX_EXIT_VIRTUALIZED_EOI:
12251 break;
12252
12253 default:
12254 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12255 break;
12256 }
12257#undef SET_BOTH
12258#undef SET_EXIT
12259
12260 /*
12261 * Dtrace tracepoints go first. We do them here at once so we don't
12262 * have to copy the guest state saving and stuff a few dozen times.
12263 * Down side is that we've got to repeat the switch, though this time
12264 * we use enmEvent since the probes are a subset of what DBGF does.
12265 */
12266 if (fDtrace1 || fDtrace2)
12267 {
12268 hmR0VmxReadExitQualVmcs(pVmxTransient);
12269 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12270 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12271 switch (enmEvent1)
12272 {
12273 /** @todo consider which extra parameters would be helpful for each probe. */
12274 case DBGFEVENT_END: break;
12275 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
12276 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
12277 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
12278 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
12279 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
12280 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
12281 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
12282 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
12283 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
12284 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
12285 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
12286 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
12287 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
12288 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
12289 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
12290 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
12291 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
12292 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
12293 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12294 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
12295 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
12296 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
12297 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
12298 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
12299 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
12300 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
12301 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
12302 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12303 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12304 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12305 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12306 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
12307 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
12308 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
12309 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
12310 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
12311 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
12312 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
12313 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
12314 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
12315 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
12316 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
12317 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
12318 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
12319 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
12320 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
12321 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
12322 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
12323 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
12324 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
12325 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
12326 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
12327 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
12328 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
12329 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
12330 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
12331 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
12332 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
12333 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
12334 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
12335 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
12336 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
12337 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
12338 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
12339 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
12340 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
12341 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
12342 }
12343 switch (enmEvent2)
12344 {
12345 /** @todo consider which extra parameters would be helpful for each probe. */
12346 case DBGFEVENT_END: break;
12347 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
12348 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
12349 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
12350 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
12351 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
12352 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
12353 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
12354 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
12355 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
12356 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12357 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12358 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12359 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12360 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
12361 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
12362 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
12363 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
12364 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
12365 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
12366 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
12367 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
12368 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
12369 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
12370 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
12371 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
12372 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
12373 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
12374 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
12375 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
12376 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
12377 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
12378 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
12379 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
12380 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
12381 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
12382 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
12383 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
12384 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
12385 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
12386 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
12387 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
12388 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
12389 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
12390 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
12391 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
12392 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
12393 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
12394 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
12395 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
12396 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
12397 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
12398 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
12399 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
12400 }
12401 }
12402
12403 /*
12404 * Fire of the DBGF event, if enabled (our check here is just a quick one,
12405 * the DBGF call will do a full check).
12406 *
12407 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
12408 * Note! If we have to events, we prioritize the first, i.e. the instruction
12409 * one, in order to avoid event nesting.
12410 */
12411 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
12412 if ( enmEvent1 != DBGFEVENT_END
12413 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
12414 {
12415 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12416 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
12417 if (rcStrict != VINF_SUCCESS)
12418 return rcStrict;
12419 }
12420 else if ( enmEvent2 != DBGFEVENT_END
12421 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
12422 {
12423 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12424 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
12425 if (rcStrict != VINF_SUCCESS)
12426 return rcStrict;
12427 }
12428
12429 return VINF_SUCCESS;
12430}
12431
12432
12433/**
12434 * Single-stepping VM-exit filtering.
12435 *
12436 * This is preprocessing the VM-exits and deciding whether we've gotten far
12437 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
12438 * handling is performed.
12439 *
12440 * @returns Strict VBox status code (i.e. informational status codes too).
12441 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
12442 * @param pVmxTransient The VMX-transient structure.
12443 * @param pDbgState The debug state.
12444 */
12445DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
12446{
12447 /*
12448 * Expensive (saves context) generic dtrace VM-exit probe.
12449 */
12450 uint32_t const uExitReason = pVmxTransient->uExitReason;
12451 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
12452 { /* more likely */ }
12453 else
12454 {
12455 hmR0VmxReadExitQualVmcs(pVmxTransient);
12456 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12457 AssertRC(rc);
12458 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
12459 }
12460
12461 /*
12462 * Check for host NMI, just to get that out of the way.
12463 */
12464 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
12465 { /* normally likely */ }
12466 else
12467 {
12468 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
12469 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
12470 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
12471 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
12472 }
12473
12474 /*
12475 * Check for single stepping event if we're stepping.
12476 */
12477 if (pVCpu->hm.s.fSingleInstruction)
12478 {
12479 switch (uExitReason)
12480 {
12481 case VMX_EXIT_MTF:
12482 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
12483
12484 /* Various events: */
12485 case VMX_EXIT_XCPT_OR_NMI:
12486 case VMX_EXIT_EXT_INT:
12487 case VMX_EXIT_TRIPLE_FAULT:
12488 case VMX_EXIT_INT_WINDOW:
12489 case VMX_EXIT_NMI_WINDOW:
12490 case VMX_EXIT_TASK_SWITCH:
12491 case VMX_EXIT_TPR_BELOW_THRESHOLD:
12492 case VMX_EXIT_APIC_ACCESS:
12493 case VMX_EXIT_EPT_VIOLATION:
12494 case VMX_EXIT_EPT_MISCONFIG:
12495 case VMX_EXIT_PREEMPT_TIMER:
12496
12497 /* Instruction specific VM-exits: */
12498 case VMX_EXIT_CPUID:
12499 case VMX_EXIT_GETSEC:
12500 case VMX_EXIT_HLT:
12501 case VMX_EXIT_INVD:
12502 case VMX_EXIT_INVLPG:
12503 case VMX_EXIT_RDPMC:
12504 case VMX_EXIT_RDTSC:
12505 case VMX_EXIT_RSM:
12506 case VMX_EXIT_VMCALL:
12507 case VMX_EXIT_VMCLEAR:
12508 case VMX_EXIT_VMLAUNCH:
12509 case VMX_EXIT_VMPTRLD:
12510 case VMX_EXIT_VMPTRST:
12511 case VMX_EXIT_VMREAD:
12512 case VMX_EXIT_VMRESUME:
12513 case VMX_EXIT_VMWRITE:
12514 case VMX_EXIT_VMXOFF:
12515 case VMX_EXIT_VMXON:
12516 case VMX_EXIT_MOV_CRX:
12517 case VMX_EXIT_MOV_DRX:
12518 case VMX_EXIT_IO_INSTR:
12519 case VMX_EXIT_RDMSR:
12520 case VMX_EXIT_WRMSR:
12521 case VMX_EXIT_MWAIT:
12522 case VMX_EXIT_MONITOR:
12523 case VMX_EXIT_PAUSE:
12524 case VMX_EXIT_GDTR_IDTR_ACCESS:
12525 case VMX_EXIT_LDTR_TR_ACCESS:
12526 case VMX_EXIT_INVEPT:
12527 case VMX_EXIT_RDTSCP:
12528 case VMX_EXIT_INVVPID:
12529 case VMX_EXIT_WBINVD:
12530 case VMX_EXIT_XSETBV:
12531 case VMX_EXIT_RDRAND:
12532 case VMX_EXIT_INVPCID:
12533 case VMX_EXIT_VMFUNC:
12534 case VMX_EXIT_RDSEED:
12535 case VMX_EXIT_XSAVES:
12536 case VMX_EXIT_XRSTORS:
12537 {
12538 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12539 AssertRCReturn(rc, rc);
12540 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
12541 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
12542 return VINF_EM_DBG_STEPPED;
12543 break;
12544 }
12545
12546 /* Errors and unexpected events: */
12547 case VMX_EXIT_INIT_SIGNAL:
12548 case VMX_EXIT_SIPI:
12549 case VMX_EXIT_IO_SMI:
12550 case VMX_EXIT_SMI:
12551 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12552 case VMX_EXIT_ERR_MSR_LOAD:
12553 case VMX_EXIT_ERR_MACHINE_CHECK:
12554 case VMX_EXIT_PML_FULL:
12555 case VMX_EXIT_VIRTUALIZED_EOI:
12556 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
12557 break;
12558
12559 default:
12560 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12561 break;
12562 }
12563 }
12564
12565 /*
12566 * Check for debugger event breakpoints and dtrace probes.
12567 */
12568 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12569 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12570 {
12571 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12572 if (rcStrict != VINF_SUCCESS)
12573 return rcStrict;
12574 }
12575
12576 /*
12577 * Normal processing.
12578 */
12579#ifdef HMVMX_USE_FUNCTION_TABLE
12580 return g_aVMExitHandlers[uExitReason].pfn(pVCpu, pVmxTransient);
12581#else
12582 return hmR0VmxHandleExit(pVCpu, pVmxTransient, uExitReason);
12583#endif
12584}
12585
12586
12587/**
12588 * Single steps guest code using hardware-assisted VMX.
12589 *
12590 * This is -not- the same as the guest single-stepping itself (say using EFLAGS.TF)
12591 * but single-stepping through the hypervisor debugger.
12592 *
12593 * @returns Strict VBox status code (i.e. informational status codes too).
12594 * @param pVCpu The cross context virtual CPU structure.
12595 * @param pcLoops Pointer to the number of executed loops.
12596 *
12597 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
12598 */
12599static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVMCPUCC pVCpu, uint32_t *pcLoops)
12600{
12601 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
12602 Assert(pcLoops);
12603 Assert(*pcLoops <= cMaxResumeLoops);
12604
12605 VMXTRANSIENT VmxTransient;
12606 RT_ZERO(VmxTransient);
12607 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
12608
12609 /* Set HMCPU indicators. */
12610 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
12611 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
12612 pVCpu->hmr0.s.fDebugWantRdTscExit = false;
12613 pVCpu->hmr0.s.fUsingDebugLoop = true;
12614
12615 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
12616 VMXRUNDBGSTATE DbgState;
12617 hmR0VmxRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
12618 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12619
12620 /*
12621 * The loop.
12622 */
12623 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
12624 for (;;)
12625 {
12626 Assert(!HMR0SuspendPending());
12627 HMVMX_ASSERT_CPU_SAFE(pVCpu);
12628 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
12629 bool fStepping = pVCpu->hm.s.fSingleInstruction;
12630
12631 /* Set up VM-execution controls the next two can respond to. */
12632 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12633
12634 /*
12635 * Preparatory work for running guest code, this may force us to
12636 * return to ring-3.
12637 *
12638 * Warning! This bugger disables interrupts on VINF_SUCCESS!
12639 */
12640 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, fStepping);
12641 if (rcStrict != VINF_SUCCESS)
12642 break;
12643
12644 /* Interrupts are disabled at this point! */
12645 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
12646
12647 /* Override any obnoxious code in the above two calls. */
12648 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12649
12650 /*
12651 * Finally execute the guest.
12652 */
12653 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
12654
12655 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
12656 /* Interrupts are re-enabled at this point! */
12657
12658 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
12659 if (RT_SUCCESS(rcRun))
12660 { /* very likely */ }
12661 else
12662 {
12663 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
12664 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
12665 return rcRun;
12666 }
12667
12668 /* Profile the VM-exit. */
12669 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
12670 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
12671 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
12672 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
12673 HMVMX_START_EXIT_DISPATCH_PROF();
12674
12675 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
12676
12677 /*
12678 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
12679 */
12680 rcStrict = hmR0VmxRunDebugHandleExit(pVCpu, &VmxTransient, &DbgState);
12681 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
12682 if (rcStrict != VINF_SUCCESS)
12683 break;
12684 if (++(*pcLoops) > cMaxResumeLoops)
12685 {
12686 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
12687 rcStrict = VINF_EM_RAW_INTERRUPT;
12688 break;
12689 }
12690
12691 /*
12692 * Stepping: Did the RIP change, if so, consider it a single step.
12693 * Otherwise, make sure one of the TFs gets set.
12694 */
12695 if (fStepping)
12696 {
12697 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12698 AssertRC(rc);
12699 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
12700 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
12701 {
12702 rcStrict = VINF_EM_DBG_STEPPED;
12703 break;
12704 }
12705 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
12706 }
12707
12708 /*
12709 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
12710 */
12711 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
12712 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12713
12714 /* Restore all controls applied by hmR0VmxPreRunGuestDebugStateApply above. */
12715 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
12716 Assert(rcStrict == VINF_SUCCESS);
12717 }
12718
12719 /*
12720 * Clear the X86_EFL_TF if necessary.
12721 */
12722 if (pVCpu->hmr0.s.fClearTrapFlag)
12723 {
12724 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
12725 AssertRC(rc);
12726 pVCpu->hmr0.s.fClearTrapFlag = false;
12727 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
12728 }
12729 /** @todo there seems to be issues with the resume flag when the monitor trap
12730 * flag is pending without being used. Seen early in bios init when
12731 * accessing APIC page in protected mode. */
12732
12733 /* Restore HMCPU indicators. */
12734 pVCpu->hmr0.s.fUsingDebugLoop = false;
12735 pVCpu->hmr0.s.fDebugWantRdTscExit = false;
12736 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
12737
12738 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
12739 return rcStrict;
12740}
12741
12742
12743/** @} */
12744
12745
12746/**
12747 * Checks if any expensive dtrace probes are enabled and we should go to the
12748 * debug loop.
12749 *
12750 * @returns true if we should use debug loop, false if not.
12751 */
12752static bool hmR0VmxAnyExpensiveProbesEnabled(void)
12753{
12754 /* It's probably faster to OR the raw 32-bit counter variables together.
12755 Since the variables are in an array and the probes are next to one
12756 another (more or less), we have good locality. So, better read
12757 eight-nine cache lines ever time and only have one conditional, than
12758 128+ conditionals, right? */
12759 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
12760 | VBOXVMM_XCPT_DE_ENABLED_RAW()
12761 | VBOXVMM_XCPT_DB_ENABLED_RAW()
12762 | VBOXVMM_XCPT_BP_ENABLED_RAW()
12763 | VBOXVMM_XCPT_OF_ENABLED_RAW()
12764 | VBOXVMM_XCPT_BR_ENABLED_RAW()
12765 | VBOXVMM_XCPT_UD_ENABLED_RAW()
12766 | VBOXVMM_XCPT_NM_ENABLED_RAW()
12767 | VBOXVMM_XCPT_DF_ENABLED_RAW()
12768 | VBOXVMM_XCPT_TS_ENABLED_RAW()
12769 | VBOXVMM_XCPT_NP_ENABLED_RAW()
12770 | VBOXVMM_XCPT_SS_ENABLED_RAW()
12771 | VBOXVMM_XCPT_GP_ENABLED_RAW()
12772 | VBOXVMM_XCPT_PF_ENABLED_RAW()
12773 | VBOXVMM_XCPT_MF_ENABLED_RAW()
12774 | VBOXVMM_XCPT_AC_ENABLED_RAW()
12775 | VBOXVMM_XCPT_XF_ENABLED_RAW()
12776 | VBOXVMM_XCPT_VE_ENABLED_RAW()
12777 | VBOXVMM_XCPT_SX_ENABLED_RAW()
12778 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
12779 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
12780 ) != 0
12781 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
12782 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
12783 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
12784 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
12785 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
12786 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
12787 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
12788 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
12789 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
12790 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
12791 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
12792 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
12793 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
12794 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
12795 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
12796 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
12797 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
12798 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
12799 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
12800 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
12801 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
12802 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
12803 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
12804 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
12805 | VBOXVMM_INSTR_STR_ENABLED_RAW()
12806 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
12807 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
12808 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
12809 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
12810 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
12811 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
12812 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
12813 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
12814 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
12815 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
12816 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
12817 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
12818 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
12819 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
12820 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
12821 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
12822 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
12823 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
12824 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
12825 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
12826 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
12827 ) != 0
12828 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
12829 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
12830 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
12831 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
12832 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
12833 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
12834 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
12835 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
12836 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
12837 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
12838 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
12839 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
12840 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
12841 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
12842 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
12843 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
12844 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
12845 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
12846 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
12847 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
12848 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
12849 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
12850 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
12851 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
12852 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
12853 | VBOXVMM_EXIT_STR_ENABLED_RAW()
12854 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
12855 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
12856 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
12857 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
12858 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
12859 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
12860 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
12861 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
12862 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
12863 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
12864 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
12865 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
12866 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
12867 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
12868 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
12869 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
12870 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
12871 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
12872 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
12873 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
12874 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
12875 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
12876 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
12877 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
12878 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
12879 ) != 0;
12880}
12881
12882
12883/**
12884 * Runs the guest using hardware-assisted VMX.
12885 *
12886 * @returns Strict VBox status code (i.e. informational status codes too).
12887 * @param pVCpu The cross context virtual CPU structure.
12888 */
12889VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVMCPUCC pVCpu)
12890{
12891 AssertPtr(pVCpu);
12892 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12893 Assert(VMMRZCallRing3IsEnabled(pVCpu));
12894 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12895 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
12896
12897 VBOXSTRICTRC rcStrict;
12898 uint32_t cLoops = 0;
12899 for (;;)
12900 {
12901#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12902 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(pCtx);
12903#else
12904 NOREF(pCtx);
12905 bool const fInNestedGuestMode = false;
12906#endif
12907 if (!fInNestedGuestMode)
12908 {
12909 if ( !pVCpu->hm.s.fUseDebugLoop
12910 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
12911 && !DBGFIsStepping(pVCpu)
12912 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
12913 rcStrict = hmR0VmxRunGuestCodeNormal(pVCpu, &cLoops);
12914 else
12915 rcStrict = hmR0VmxRunGuestCodeDebug(pVCpu, &cLoops);
12916 }
12917#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12918 else
12919 rcStrict = hmR0VmxRunGuestCodeNested(pVCpu, &cLoops);
12920
12921 if (rcStrict == VINF_VMX_VMLAUNCH_VMRESUME)
12922 {
12923 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
12924 continue;
12925 }
12926 if (rcStrict == VINF_VMX_VMEXIT)
12927 {
12928 Assert(!CPUMIsGuestInVmxNonRootMode(pCtx));
12929 continue;
12930 }
12931#endif
12932 break;
12933 }
12934
12935 int const rcLoop = VBOXSTRICTRC_VAL(rcStrict);
12936 switch (rcLoop)
12937 {
12938 case VERR_EM_INTERPRETER: rcStrict = VINF_EM_RAW_EMULATE_INSTR; break;
12939 case VINF_EM_RESET: rcStrict = VINF_EM_TRIPLE_FAULT; break;
12940 }
12941
12942 int rc2 = hmR0VmxExitToRing3(pVCpu, rcStrict);
12943 if (RT_FAILURE(rc2))
12944 {
12945 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
12946 rcStrict = rc2;
12947 }
12948 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12949 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
12950 return rcStrict;
12951}
12952
12953
12954#ifndef HMVMX_USE_FUNCTION_TABLE
12955/**
12956 * Handles a guest VM-exit from hardware-assisted VMX execution.
12957 *
12958 * @returns Strict VBox status code (i.e. informational status codes too).
12959 * @param pVCpu The cross context virtual CPU structure.
12960 * @param pVmxTransient The VMX-transient structure.
12961 */
12962DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12963{
12964#ifdef DEBUG_ramshankar
12965# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
12966 do { \
12967 if (a_fSave != 0) \
12968 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
12969 VBOXSTRICTRC rcStrict = a_CallExpr; \
12970 if (a_fSave != 0) \
12971 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST); \
12972 return rcStrict; \
12973 } while (0)
12974#else
12975# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
12976#endif
12977 uint32_t const uExitReason = pVmxTransient->uExitReason;
12978 switch (uExitReason)
12979 {
12980 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient));
12981 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, hmR0VmxExitEptViolation(pVCpu, pVmxTransient));
12982 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, hmR0VmxExitIoInstr(pVCpu, pVmxTransient));
12983 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, hmR0VmxExitCpuid(pVCpu, pVmxTransient));
12984 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, hmR0VmxExitRdtsc(pVCpu, pVmxTransient));
12985 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, hmR0VmxExitRdtscp(pVCpu, pVmxTransient));
12986 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, hmR0VmxExitApicAccess(pVCpu, pVmxTransient));
12987 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, hmR0VmxExitXcptOrNmi(pVCpu, pVmxTransient));
12988 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovCRx(pVCpu, pVmxTransient));
12989 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, hmR0VmxExitExtInt(pVCpu, pVmxTransient));
12990 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, hmR0VmxExitIntWindow(pVCpu, pVmxTransient));
12991 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient));
12992 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, hmR0VmxExitMwait(pVCpu, pVmxTransient));
12993 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, hmR0VmxExitMonitor(pVCpu, pVmxTransient));
12994 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, hmR0VmxExitTaskSwitch(pVCpu, pVmxTransient));
12995 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient));
12996 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, hmR0VmxExitRdmsr(pVCpu, pVmxTransient));
12997 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, hmR0VmxExitWrmsr(pVCpu, pVmxTransient));
12998 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, hmR0VmxExitVmcall(pVCpu, pVmxTransient));
12999 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovDRx(pVCpu, pVmxTransient));
13000 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, hmR0VmxExitHlt(pVCpu, pVmxTransient));
13001 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, hmR0VmxExitInvd(pVCpu, pVmxTransient));
13002 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, hmR0VmxExitInvlpg(pVCpu, pVmxTransient));
13003 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, hmR0VmxExitMtf(pVCpu, pVmxTransient));
13004 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, hmR0VmxExitPause(pVCpu, pVmxTransient));
13005 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, hmR0VmxExitWbinvd(pVCpu, pVmxTransient));
13006 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, hmR0VmxExitXsetbv(pVCpu, pVmxTransient));
13007 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, hmR0VmxExitInvpcid(pVCpu, pVmxTransient));
13008 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, hmR0VmxExitGetsec(pVCpu, pVmxTransient));
13009 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, hmR0VmxExitRdpmc(pVCpu, pVmxTransient));
13010#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13011 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, hmR0VmxExitVmclear(pVCpu, pVmxTransient));
13012 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, hmR0VmxExitVmlaunch(pVCpu, pVmxTransient));
13013 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrld(pVCpu, pVmxTransient));
13014 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrst(pVCpu, pVmxTransient));
13015 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, hmR0VmxExitVmread(pVCpu, pVmxTransient));
13016 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, hmR0VmxExitVmwrite(pVCpu, pVmxTransient));
13017 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, hmR0VmxExitVmresume(pVCpu, pVmxTransient));
13018 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, hmR0VmxExitVmxoff(pVCpu, pVmxTransient));
13019 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, hmR0VmxExitVmxon(pVCpu, pVmxTransient));
13020 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, hmR0VmxExitInvvpid(pVCpu, pVmxTransient));
13021 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient));
13022#else
13023 case VMX_EXIT_VMCLEAR:
13024 case VMX_EXIT_VMLAUNCH:
13025 case VMX_EXIT_VMPTRLD:
13026 case VMX_EXIT_VMPTRST:
13027 case VMX_EXIT_VMREAD:
13028 case VMX_EXIT_VMRESUME:
13029 case VMX_EXIT_VMWRITE:
13030 case VMX_EXIT_VMXOFF:
13031 case VMX_EXIT_VMXON:
13032 case VMX_EXIT_INVVPID:
13033 case VMX_EXIT_INVEPT:
13034 return hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient);
13035#endif
13036
13037 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pVmxTransient);
13038 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pVmxTransient);
13039 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
13040
13041 case VMX_EXIT_INIT_SIGNAL:
13042 case VMX_EXIT_SIPI:
13043 case VMX_EXIT_IO_SMI:
13044 case VMX_EXIT_SMI:
13045 case VMX_EXIT_ERR_MSR_LOAD:
13046 case VMX_EXIT_ERR_MACHINE_CHECK:
13047 case VMX_EXIT_PML_FULL:
13048 case VMX_EXIT_VIRTUALIZED_EOI:
13049 case VMX_EXIT_GDTR_IDTR_ACCESS:
13050 case VMX_EXIT_LDTR_TR_ACCESS:
13051 case VMX_EXIT_APIC_WRITE:
13052 case VMX_EXIT_RDRAND:
13053 case VMX_EXIT_RSM:
13054 case VMX_EXIT_VMFUNC:
13055 case VMX_EXIT_ENCLS:
13056 case VMX_EXIT_RDSEED:
13057 case VMX_EXIT_XSAVES:
13058 case VMX_EXIT_XRSTORS:
13059 case VMX_EXIT_UMWAIT:
13060 case VMX_EXIT_TPAUSE:
13061 default:
13062 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
13063 }
13064#undef VMEXIT_CALL_RET
13065}
13066#endif /* !HMVMX_USE_FUNCTION_TABLE */
13067
13068
13069#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13070/**
13071 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
13072 *
13073 * @returns Strict VBox status code (i.e. informational status codes too).
13074 * @param pVCpu The cross context virtual CPU structure.
13075 * @param pVmxTransient The VMX-transient structure.
13076 */
13077DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13078{
13079 uint32_t const uExitReason = pVmxTransient->uExitReason;
13080 switch (uExitReason)
13081 {
13082 case VMX_EXIT_EPT_MISCONFIG: return hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
13083 case VMX_EXIT_EPT_VIOLATION: return hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
13084 case VMX_EXIT_XCPT_OR_NMI: return hmR0VmxExitXcptOrNmiNested(pVCpu, pVmxTransient);
13085 case VMX_EXIT_IO_INSTR: return hmR0VmxExitIoInstrNested(pVCpu, pVmxTransient);
13086 case VMX_EXIT_HLT: return hmR0VmxExitHltNested(pVCpu, pVmxTransient);
13087
13088 /*
13089 * We shouldn't direct host physical interrupts to the nested-guest.
13090 */
13091 case VMX_EXIT_EXT_INT:
13092 return hmR0VmxExitExtInt(pVCpu, pVmxTransient);
13093
13094 /*
13095 * Instructions that cause VM-exits unconditionally or the condition is
13096 * always is taken solely from the nested hypervisor (meaning if the VM-exit
13097 * happens, it's guaranteed to be a nested-guest VM-exit).
13098 *
13099 * - Provides VM-exit instruction length ONLY.
13100 */
13101 case VMX_EXIT_CPUID: /* Unconditional. */
13102 case VMX_EXIT_VMCALL:
13103 case VMX_EXIT_GETSEC:
13104 case VMX_EXIT_INVD:
13105 case VMX_EXIT_XSETBV:
13106 case VMX_EXIT_VMLAUNCH:
13107 case VMX_EXIT_VMRESUME:
13108 case VMX_EXIT_VMXOFF:
13109 case VMX_EXIT_ENCLS: /* Condition specified solely by nested hypervisor. */
13110 case VMX_EXIT_VMFUNC:
13111 return hmR0VmxExitInstrNested(pVCpu, pVmxTransient);
13112
13113 /*
13114 * Instructions that cause VM-exits unconditionally or the condition is
13115 * always is taken solely from the nested hypervisor (meaning if the VM-exit
13116 * happens, it's guaranteed to be a nested-guest VM-exit).
13117 *
13118 * - Provides VM-exit instruction length.
13119 * - Provides VM-exit information.
13120 * - Optionally provides Exit qualification.
13121 *
13122 * Since Exit qualification is 0 for all VM-exits where it is not
13123 * applicable, reading and passing it to the guest should produce
13124 * defined behavior.
13125 *
13126 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
13127 */
13128 case VMX_EXIT_INVEPT: /* Unconditional. */
13129 case VMX_EXIT_INVVPID:
13130 case VMX_EXIT_VMCLEAR:
13131 case VMX_EXIT_VMPTRLD:
13132 case VMX_EXIT_VMPTRST:
13133 case VMX_EXIT_VMXON:
13134 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by nested hypervisor. */
13135 case VMX_EXIT_LDTR_TR_ACCESS:
13136 case VMX_EXIT_RDRAND:
13137 case VMX_EXIT_RDSEED:
13138 case VMX_EXIT_XSAVES:
13139 case VMX_EXIT_XRSTORS:
13140 case VMX_EXIT_UMWAIT:
13141 case VMX_EXIT_TPAUSE:
13142 return hmR0VmxExitInstrWithInfoNested(pVCpu, pVmxTransient);
13143
13144 case VMX_EXIT_RDTSC: return hmR0VmxExitRdtscNested(pVCpu, pVmxTransient);
13145 case VMX_EXIT_RDTSCP: return hmR0VmxExitRdtscpNested(pVCpu, pVmxTransient);
13146 case VMX_EXIT_RDMSR: return hmR0VmxExitRdmsrNested(pVCpu, pVmxTransient);
13147 case VMX_EXIT_WRMSR: return hmR0VmxExitWrmsrNested(pVCpu, pVmxTransient);
13148 case VMX_EXIT_INVLPG: return hmR0VmxExitInvlpgNested(pVCpu, pVmxTransient);
13149 case VMX_EXIT_INVPCID: return hmR0VmxExitInvpcidNested(pVCpu, pVmxTransient);
13150 case VMX_EXIT_TASK_SWITCH: return hmR0VmxExitTaskSwitchNested(pVCpu, pVmxTransient);
13151 case VMX_EXIT_WBINVD: return hmR0VmxExitWbinvdNested(pVCpu, pVmxTransient);
13152 case VMX_EXIT_MTF: return hmR0VmxExitMtfNested(pVCpu, pVmxTransient);
13153 case VMX_EXIT_APIC_ACCESS: return hmR0VmxExitApicAccessNested(pVCpu, pVmxTransient);
13154 case VMX_EXIT_APIC_WRITE: return hmR0VmxExitApicWriteNested(pVCpu, pVmxTransient);
13155 case VMX_EXIT_VIRTUALIZED_EOI: return hmR0VmxExitVirtEoiNested(pVCpu, pVmxTransient);
13156 case VMX_EXIT_MOV_CRX: return hmR0VmxExitMovCRxNested(pVCpu, pVmxTransient);
13157 case VMX_EXIT_INT_WINDOW: return hmR0VmxExitIntWindowNested(pVCpu, pVmxTransient);
13158 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindowNested(pVCpu, pVmxTransient);
13159 case VMX_EXIT_TPR_BELOW_THRESHOLD: return hmR0VmxExitTprBelowThresholdNested(pVCpu, pVmxTransient);
13160 case VMX_EXIT_MWAIT: return hmR0VmxExitMwaitNested(pVCpu, pVmxTransient);
13161 case VMX_EXIT_MONITOR: return hmR0VmxExitMonitorNested(pVCpu, pVmxTransient);
13162 case VMX_EXIT_PAUSE: return hmR0VmxExitPauseNested(pVCpu, pVmxTransient);
13163
13164 case VMX_EXIT_PREEMPT_TIMER:
13165 {
13166 /** @todo NSTVMX: Preempt timer. */
13167 return hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient);
13168 }
13169
13170 case VMX_EXIT_MOV_DRX: return hmR0VmxExitMovDRxNested(pVCpu, pVmxTransient);
13171 case VMX_EXIT_RDPMC: return hmR0VmxExitRdpmcNested(pVCpu, pVmxTransient);
13172
13173 case VMX_EXIT_VMREAD:
13174 case VMX_EXIT_VMWRITE: return hmR0VmxExitVmreadVmwriteNested(pVCpu, pVmxTransient);
13175
13176 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFaultNested(pVCpu, pVmxTransient);
13177 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestStateNested(pVCpu, pVmxTransient);
13178
13179 case VMX_EXIT_INIT_SIGNAL:
13180 case VMX_EXIT_SIPI:
13181 case VMX_EXIT_IO_SMI:
13182 case VMX_EXIT_SMI:
13183 case VMX_EXIT_ERR_MSR_LOAD:
13184 case VMX_EXIT_ERR_MACHINE_CHECK:
13185 case VMX_EXIT_PML_FULL:
13186 case VMX_EXIT_RSM:
13187 default:
13188 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
13189 }
13190}
13191#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13192
13193
13194/** @name VM-exit helpers.
13195 * @{
13196 */
13197/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13198/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
13199/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13200
13201/** Macro for VM-exits called unexpectedly. */
13202#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
13203 do { \
13204 (a_pVCpu)->hm.s.u32HMError = (a_HmError); \
13205 return VERR_VMX_UNEXPECTED_EXIT; \
13206 } while (0)
13207
13208#ifdef VBOX_STRICT
13209/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
13210# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
13211 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
13212
13213# define HMVMX_ASSERT_PREEMPT_CPUID() \
13214 do { \
13215 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
13216 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
13217 } while (0)
13218
13219# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13220 do { \
13221 AssertPtr((a_pVCpu)); \
13222 AssertPtr((a_pVmxTransient)); \
13223 Assert((a_pVmxTransient)->fVMEntryFailed == false); \
13224 Assert((a_pVmxTransient)->pVmcsInfo); \
13225 Assert(ASMIntAreEnabled()); \
13226 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
13227 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
13228 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
13229 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
13230 if (VMMR0IsLogFlushDisabled((a_pVCpu))) \
13231 HMVMX_ASSERT_PREEMPT_CPUID(); \
13232 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
13233 } while (0)
13234
13235# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13236 do { \
13237 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
13238 Assert((a_pVmxTransient)->fIsNestedGuest); \
13239 } while (0)
13240
13241# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13242 do { \
13243 Log4Func(("\n")); \
13244 } while (0)
13245#else
13246# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13247 do { \
13248 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
13249 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
13250 } while (0)
13251
13252# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13253 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
13254
13255# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
13256#endif
13257
13258#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13259/** Macro that does the necessary privilege checks and intercepted VM-exits for
13260 * guests that attempted to execute a VMX instruction. */
13261# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
13262 do \
13263 { \
13264 VBOXSTRICTRC rcStrictTmp = hmR0VmxCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
13265 if (rcStrictTmp == VINF_SUCCESS) \
13266 { /* likely */ } \
13267 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
13268 { \
13269 Assert((a_pVCpu)->hm.s.Event.fPending); \
13270 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
13271 return VINF_SUCCESS; \
13272 } \
13273 else \
13274 { \
13275 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
13276 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
13277 } \
13278 } while (0)
13279
13280/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
13281# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
13282 do \
13283 { \
13284 VBOXSTRICTRC rcStrictTmp = hmR0VmxDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
13285 (a_pGCPtrEffAddr)); \
13286 if (rcStrictTmp == VINF_SUCCESS) \
13287 { /* likely */ } \
13288 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
13289 { \
13290 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
13291 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
13292 NOREF(uXcptTmp); \
13293 return VINF_SUCCESS; \
13294 } \
13295 else \
13296 { \
13297 Log4Func(("hmR0VmxDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
13298 return rcStrictTmp; \
13299 } \
13300 } while (0)
13301#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13302
13303
13304/**
13305 * Advances the guest RIP by the specified number of bytes.
13306 *
13307 * @param pVCpu The cross context virtual CPU structure.
13308 * @param cbInstr Number of bytes to advance the RIP by.
13309 *
13310 * @remarks No-long-jump zone!!!
13311 */
13312DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPUCC pVCpu, uint32_t cbInstr)
13313{
13314 /* Advance the RIP. */
13315 pVCpu->cpum.GstCtx.rip += cbInstr;
13316 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
13317
13318 /* Update interrupt inhibition. */
13319 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
13320 && pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
13321 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
13322}
13323
13324
13325/**
13326 * Advances the guest RIP after reading it from the VMCS.
13327 *
13328 * @returns VBox status code, no informational status codes.
13329 * @param pVCpu The cross context virtual CPU structure.
13330 * @param pVmxTransient The VMX-transient structure.
13331 *
13332 * @remarks No-long-jump zone!!!
13333 */
13334static int hmR0VmxAdvanceGuestRip(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13335{
13336 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13337 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
13338 AssertRCReturn(rc, rc);
13339
13340 hmR0VmxAdvanceGuestRipBy(pVCpu, pVmxTransient->cbExitInstr);
13341 return VINF_SUCCESS;
13342}
13343
13344
13345/**
13346 * Handle a condition that occurred while delivering an event through the guest or
13347 * nested-guest IDT.
13348 *
13349 * @returns Strict VBox status code (i.e. informational status codes too).
13350 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13351 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
13352 * to continue execution of the guest which will delivery the \#DF.
13353 * @retval VINF_EM_RESET if we detected a triple-fault condition.
13354 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
13355 *
13356 * @param pVCpu The cross context virtual CPU structure.
13357 * @param pVmxTransient The VMX-transient structure.
13358 *
13359 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13360 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
13361 * is due to an EPT violation, PML full or SPP-related event.
13362 *
13363 * @remarks No-long-jump zone!!!
13364 */
13365static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13366{
13367 Assert(!pVCpu->hm.s.Event.fPending);
13368 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
13369 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13370 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13371 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13372 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
13373
13374 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
13375 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13376 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
13377 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
13378 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
13379 {
13380 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
13381 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
13382
13383 /*
13384 * If the event was a software interrupt (generated with INT n) or a software exception
13385 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
13386 * can handle the VM-exit and continue guest execution which will re-execute the
13387 * instruction rather than re-injecting the exception, as that can cause premature
13388 * trips to ring-3 before injection and involve TRPM which currently has no way of
13389 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
13390 * the problem).
13391 */
13392 IEMXCPTRAISE enmRaise;
13393 IEMXCPTRAISEINFO fRaiseInfo;
13394 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
13395 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
13396 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
13397 {
13398 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
13399 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
13400 }
13401 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
13402 {
13403 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
13404 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
13405 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
13406
13407 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
13408 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
13409
13410 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
13411
13412 /* Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF(). */
13413 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
13414 {
13415 pVmxTransient->fVectoringPF = true;
13416 enmRaise = IEMXCPTRAISE_PREV_EVENT;
13417 }
13418 }
13419 else
13420 {
13421 /*
13422 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
13423 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
13424 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
13425 */
13426 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
13427 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
13428 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
13429 enmRaise = IEMXCPTRAISE_PREV_EVENT;
13430 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
13431 }
13432
13433 /*
13434 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
13435 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
13436 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
13437 * subsequent VM-entry would fail, see @bugref{7445}.
13438 *
13439 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
13440 */
13441 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
13442 && enmRaise == IEMXCPTRAISE_PREV_EVENT
13443 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13444 && CPUMIsGuestNmiBlocking(pVCpu))
13445 {
13446 CPUMSetGuestNmiBlocking(pVCpu, false);
13447 }
13448
13449 switch (enmRaise)
13450 {
13451 case IEMXCPTRAISE_CURRENT_XCPT:
13452 {
13453 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
13454 Assert(rcStrict == VINF_SUCCESS);
13455 break;
13456 }
13457
13458 case IEMXCPTRAISE_PREV_EVENT:
13459 {
13460 uint32_t u32ErrCode;
13461 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
13462 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
13463 else
13464 u32ErrCode = 0;
13465
13466 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
13467 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect);
13468 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */,
13469 u32ErrCode, pVCpu->cpum.GstCtx.cr2);
13470
13471 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo,
13472 pVCpu->hm.s.Event.u32ErrCode));
13473 Assert(rcStrict == VINF_SUCCESS);
13474 break;
13475 }
13476
13477 case IEMXCPTRAISE_REEXEC_INSTR:
13478 Assert(rcStrict == VINF_SUCCESS);
13479 break;
13480
13481 case IEMXCPTRAISE_DOUBLE_FAULT:
13482 {
13483 /*
13484 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
13485 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
13486 */
13487 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
13488 {
13489 pVmxTransient->fVectoringDoublePF = true;
13490 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo,
13491 pVCpu->cpum.GstCtx.cr2));
13492 rcStrict = VINF_SUCCESS;
13493 }
13494 else
13495 {
13496 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectConvertDF);
13497 hmR0VmxSetPendingXcptDF(pVCpu);
13498 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
13499 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
13500 rcStrict = VINF_HM_DOUBLE_FAULT;
13501 }
13502 break;
13503 }
13504
13505 case IEMXCPTRAISE_TRIPLE_FAULT:
13506 {
13507 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
13508 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
13509 rcStrict = VINF_EM_RESET;
13510 break;
13511 }
13512
13513 case IEMXCPTRAISE_CPU_HANG:
13514 {
13515 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
13516 rcStrict = VERR_EM_GUEST_CPU_HANG;
13517 break;
13518 }
13519
13520 default:
13521 {
13522 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
13523 rcStrict = VERR_VMX_IPE_2;
13524 break;
13525 }
13526 }
13527 }
13528 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13529 && !CPUMIsGuestNmiBlocking(pVCpu))
13530 {
13531 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
13532 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
13533 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
13534 {
13535 /*
13536 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
13537 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13538 * that virtual NMIs remain blocked until the IRET execution is completed.
13539 *
13540 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
13541 */
13542 CPUMSetGuestNmiBlocking(pVCpu, true);
13543 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13544 }
13545 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13546 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13547 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13548 {
13549 /*
13550 * Execution of IRET caused an EPT violation, page-modification log-full event or
13551 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
13552 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13553 * that virtual NMIs remain blocked until the IRET execution is completed.
13554 *
13555 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
13556 */
13557 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
13558 {
13559 CPUMSetGuestNmiBlocking(pVCpu, true);
13560 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13561 }
13562 }
13563 }
13564
13565 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
13566 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
13567 return rcStrict;
13568}
13569
13570
13571#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13572/**
13573 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
13574 * guest attempting to execute a VMX instruction.
13575 *
13576 * @returns Strict VBox status code (i.e. informational status codes too).
13577 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13578 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
13579 *
13580 * @param pVCpu The cross context virtual CPU structure.
13581 * @param uExitReason The VM-exit reason.
13582 *
13583 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
13584 * @remarks No-long-jump zone!!!
13585 */
13586static VBOXSTRICTRC hmR0VmxCheckExitDueToVmxInstr(PVMCPUCC pVCpu, uint32_t uExitReason)
13587{
13588 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
13589 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
13590
13591 /*
13592 * The physical CPU would have already checked the CPU mode/code segment.
13593 * We shall just assert here for paranoia.
13594 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
13595 */
13596 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13597 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
13598 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
13599
13600 if (uExitReason == VMX_EXIT_VMXON)
13601 {
13602 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
13603
13604 /*
13605 * We check CR4.VMXE because it is required to be always set while in VMX operation
13606 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
13607 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
13608 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
13609 */
13610 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
13611 {
13612 Log4Func(("CR4.VMXE is not set -> #UD\n"));
13613 hmR0VmxSetPendingXcptUD(pVCpu);
13614 return VINF_HM_PENDING_XCPT;
13615 }
13616 }
13617 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
13618 {
13619 /*
13620 * The guest has not entered VMX operation but attempted to execute a VMX instruction
13621 * (other than VMXON), we need to raise a #UD.
13622 */
13623 Log4Func(("Not in VMX root mode -> #UD\n"));
13624 hmR0VmxSetPendingXcptUD(pVCpu);
13625 return VINF_HM_PENDING_XCPT;
13626 }
13627
13628 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
13629 return VINF_SUCCESS;
13630}
13631
13632
13633/**
13634 * Decodes the memory operand of an instruction that caused a VM-exit.
13635 *
13636 * The Exit qualification field provides the displacement field for memory
13637 * operand instructions, if any.
13638 *
13639 * @returns Strict VBox status code (i.e. informational status codes too).
13640 * @retval VINF_SUCCESS if the operand was successfully decoded.
13641 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
13642 * operand.
13643 * @param pVCpu The cross context virtual CPU structure.
13644 * @param uExitInstrInfo The VM-exit instruction information field.
13645 * @param enmMemAccess The memory operand's access type (read or write).
13646 * @param GCPtrDisp The instruction displacement field, if any. For
13647 * RIP-relative addressing pass RIP + displacement here.
13648 * @param pGCPtrMem Where to store the effective destination memory address.
13649 *
13650 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
13651 * virtual-8086 mode hence skips those checks while verifying if the
13652 * segment is valid.
13653 */
13654static VBOXSTRICTRC hmR0VmxDecodeMemOperand(PVMCPUCC pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
13655 PRTGCPTR pGCPtrMem)
13656{
13657 Assert(pGCPtrMem);
13658 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
13659 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
13660 | CPUMCTX_EXTRN_CR0);
13661
13662 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
13663 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
13664 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
13665
13666 VMXEXITINSTRINFO ExitInstrInfo;
13667 ExitInstrInfo.u = uExitInstrInfo;
13668 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
13669 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
13670 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
13671 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
13672 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
13673 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
13674 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
13675 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
13676 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
13677
13678 /*
13679 * Validate instruction information.
13680 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
13681 */
13682 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
13683 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
13684 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
13685 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
13686 AssertLogRelMsgReturn(fIsMemOperand,
13687 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
13688
13689 /*
13690 * Compute the complete effective address.
13691 *
13692 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
13693 * See AMD spec. 4.5.2 "Segment Registers".
13694 */
13695 RTGCPTR GCPtrMem = GCPtrDisp;
13696 if (fBaseRegValid)
13697 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
13698 if (fIdxRegValid)
13699 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
13700
13701 RTGCPTR const GCPtrOff = GCPtrMem;
13702 if ( !fIsLongMode
13703 || iSegReg >= X86_SREG_FS)
13704 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
13705 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
13706
13707 /*
13708 * Validate effective address.
13709 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
13710 */
13711 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
13712 Assert(cbAccess > 0);
13713 if (fIsLongMode)
13714 {
13715 if (X86_IS_CANONICAL(GCPtrMem))
13716 {
13717 *pGCPtrMem = GCPtrMem;
13718 return VINF_SUCCESS;
13719 }
13720
13721 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
13722 * "Data Limit Checks in 64-bit Mode". */
13723 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
13724 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13725 return VINF_HM_PENDING_XCPT;
13726 }
13727
13728 /*
13729 * This is a watered down version of iemMemApplySegment().
13730 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
13731 * and segment CPL/DPL checks are skipped.
13732 */
13733 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
13734 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
13735 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
13736
13737 /* Check if the segment is present and usable. */
13738 if ( pSel->Attr.n.u1Present
13739 && !pSel->Attr.n.u1Unusable)
13740 {
13741 Assert(pSel->Attr.n.u1DescType);
13742 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
13743 {
13744 /* Check permissions for the data segment. */
13745 if ( enmMemAccess == VMXMEMACCESS_WRITE
13746 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
13747 {
13748 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13749 hmR0VmxSetPendingXcptGP(pVCpu, iSegReg);
13750 return VINF_HM_PENDING_XCPT;
13751 }
13752
13753 /* Check limits if it's a normal data segment. */
13754 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
13755 {
13756 if ( GCPtrFirst32 > pSel->u32Limit
13757 || GCPtrLast32 > pSel->u32Limit)
13758 {
13759 Log4Func(("Data segment limit exceeded. "
13760 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13761 GCPtrLast32, pSel->u32Limit));
13762 if (iSegReg == X86_SREG_SS)
13763 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13764 else
13765 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13766 return VINF_HM_PENDING_XCPT;
13767 }
13768 }
13769 else
13770 {
13771 /* Check limits if it's an expand-down data segment.
13772 Note! The upper boundary is defined by the B bit, not the G bit! */
13773 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
13774 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
13775 {
13776 Log4Func(("Expand-down data segment limit exceeded. "
13777 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13778 GCPtrLast32, pSel->u32Limit));
13779 if (iSegReg == X86_SREG_SS)
13780 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13781 else
13782 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13783 return VINF_HM_PENDING_XCPT;
13784 }
13785 }
13786 }
13787 else
13788 {
13789 /* Check permissions for the code segment. */
13790 if ( enmMemAccess == VMXMEMACCESS_WRITE
13791 || ( enmMemAccess == VMXMEMACCESS_READ
13792 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
13793 {
13794 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
13795 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13796 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13797 return VINF_HM_PENDING_XCPT;
13798 }
13799
13800 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
13801 if ( GCPtrFirst32 > pSel->u32Limit
13802 || GCPtrLast32 > pSel->u32Limit)
13803 {
13804 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
13805 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
13806 if (iSegReg == X86_SREG_SS)
13807 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13808 else
13809 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13810 return VINF_HM_PENDING_XCPT;
13811 }
13812 }
13813 }
13814 else
13815 {
13816 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13817 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13818 return VINF_HM_PENDING_XCPT;
13819 }
13820
13821 *pGCPtrMem = GCPtrMem;
13822 return VINF_SUCCESS;
13823}
13824#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13825
13826
13827/**
13828 * VM-exit helper for LMSW.
13829 */
13830static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
13831{
13832 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13833 AssertRCReturn(rc, rc);
13834
13835 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
13836 AssertMsg( rcStrict == VINF_SUCCESS
13837 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13838
13839 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13840 if (rcStrict == VINF_IEM_RAISED_XCPT)
13841 {
13842 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13843 rcStrict = VINF_SUCCESS;
13844 }
13845
13846 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
13847 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13848 return rcStrict;
13849}
13850
13851
13852/**
13853 * VM-exit helper for CLTS.
13854 */
13855static VBOXSTRICTRC hmR0VmxExitClts(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
13856{
13857 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13858 AssertRCReturn(rc, rc);
13859
13860 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
13861 AssertMsg( rcStrict == VINF_SUCCESS
13862 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13863
13864 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13865 if (rcStrict == VINF_IEM_RAISED_XCPT)
13866 {
13867 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13868 rcStrict = VINF_SUCCESS;
13869 }
13870
13871 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
13872 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13873 return rcStrict;
13874}
13875
13876
13877/**
13878 * VM-exit helper for MOV from CRx (CRx read).
13879 */
13880static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13881{
13882 Assert(iCrReg < 16);
13883 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
13884
13885 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13886 AssertRCReturn(rc, rc);
13887
13888 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
13889 AssertMsg( rcStrict == VINF_SUCCESS
13890 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13891
13892 if (iGReg == X86_GREG_xSP)
13893 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
13894 else
13895 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13896#ifdef VBOX_WITH_STATISTICS
13897 switch (iCrReg)
13898 {
13899 case 0: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Read); break;
13900 case 2: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Read); break;
13901 case 3: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Read); break;
13902 case 4: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Read); break;
13903 case 8: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Read); break;
13904 }
13905#endif
13906 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
13907 return rcStrict;
13908}
13909
13910
13911/**
13912 * VM-exit helper for MOV to CRx (CRx write).
13913 */
13914static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13915{
13916 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13917 AssertRCReturn(rc, rc);
13918
13919 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
13920 AssertMsg( rcStrict == VINF_SUCCESS
13921 || rcStrict == VINF_IEM_RAISED_XCPT
13922 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13923
13924 switch (iCrReg)
13925 {
13926 case 0:
13927 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0
13928 | HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
13929 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Write);
13930 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
13931 break;
13932
13933 case 2:
13934 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Write);
13935 /* Nothing to do here, CR2 it's not part of the VMCS. */
13936 break;
13937
13938 case 3:
13939 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
13940 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Write);
13941 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
13942 break;
13943
13944 case 4:
13945 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
13946 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Write);
13947 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
13948 pVCpu->cpum.GstCtx.cr4, pVCpu->hmr0.s.fLoadSaveGuestXcr0));
13949 break;
13950
13951 case 8:
13952 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
13953 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
13954 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Write);
13955 break;
13956
13957 default:
13958 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
13959 break;
13960 }
13961
13962 if (rcStrict == VINF_IEM_RAISED_XCPT)
13963 {
13964 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13965 rcStrict = VINF_SUCCESS;
13966 }
13967 return rcStrict;
13968}
13969
13970
13971/**
13972 * VM-exit exception handler for \#PF (Page-fault exception).
13973 *
13974 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13975 */
13976static VBOXSTRICTRC hmR0VmxExitXcptPF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13977{
13978 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13979 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
13980 hmR0VmxReadExitQualVmcs(pVmxTransient);
13981
13982 if (!pVM->hmr0.s.fNestedPaging)
13983 { /* likely */ }
13984 else
13985 {
13986#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13987 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hmr0.s.fUsingDebugLoop);
13988#endif
13989 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13990 if (!pVmxTransient->fVectoringDoublePF)
13991 {
13992 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13993 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
13994 }
13995 else
13996 {
13997 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13998 Assert(!pVmxTransient->fIsNestedGuest);
13999 hmR0VmxSetPendingXcptDF(pVCpu);
14000 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
14001 }
14002 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
14003 return VINF_SUCCESS;
14004 }
14005
14006 Assert(!pVmxTransient->fIsNestedGuest);
14007
14008 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
14009 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
14010 if (pVmxTransient->fVectoringPF)
14011 {
14012 Assert(pVCpu->hm.s.Event.fPending);
14013 return VINF_EM_RAW_INJECT_TRPM_EVENT;
14014 }
14015
14016 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14017 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14018 AssertRCReturn(rc, rc);
14019
14020 Log4Func(("#PF: cs:rip=%#04x:%#RX64 err_code=%#RX32 exit_qual=%#RX64 cr3=%#RX64\n", pCtx->cs.Sel, pCtx->rip,
14021 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual, pCtx->cr3));
14022
14023 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
14024 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pCtx), (RTGCPTR)pVmxTransient->uExitQual);
14025
14026 Log4Func(("#PF: rc=%Rrc\n", rc));
14027 if (rc == VINF_SUCCESS)
14028 {
14029 /*
14030 * This is typically a shadow page table sync or a MMIO instruction. But we may have
14031 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
14032 */
14033 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14034 TRPMResetTrap(pVCpu);
14035 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
14036 return rc;
14037 }
14038
14039 if (rc == VINF_EM_RAW_GUEST_TRAP)
14040 {
14041 if (!pVmxTransient->fVectoringDoublePF)
14042 {
14043 /* It's a guest page fault and needs to be reflected to the guest. */
14044 uint32_t const uGstErrorCode = TRPMGetErrorCode(pVCpu);
14045 TRPMResetTrap(pVCpu);
14046 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
14047 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
14048 uGstErrorCode, pVmxTransient->uExitQual);
14049 }
14050 else
14051 {
14052 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
14053 TRPMResetTrap(pVCpu);
14054 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
14055 hmR0VmxSetPendingXcptDF(pVCpu);
14056 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
14057 }
14058
14059 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
14060 return VINF_SUCCESS;
14061 }
14062
14063 TRPMResetTrap(pVCpu);
14064 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
14065 return rc;
14066}
14067
14068
14069/**
14070 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
14071 *
14072 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14073 */
14074static VBOXSTRICTRC hmR0VmxExitXcptMF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14075{
14076 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14077 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
14078
14079 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0);
14080 AssertRCReturn(rc, rc);
14081
14082 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
14083 {
14084 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
14085 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
14086
14087 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
14088 * provides VM-exit instruction length. If this causes problem later,
14089 * disassemble the instruction like it's done on AMD-V. */
14090 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14091 AssertRCReturn(rc2, rc2);
14092 return rc;
14093 }
14094
14095 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbExitInstr,
14096 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14097 return VINF_SUCCESS;
14098}
14099
14100
14101/**
14102 * VM-exit exception handler for \#BP (Breakpoint exception).
14103 *
14104 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14105 */
14106static VBOXSTRICTRC hmR0VmxExitXcptBP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14107{
14108 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14109 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
14110
14111 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14112 AssertRCReturn(rc, rc);
14113
14114 if (!pVmxTransient->fIsNestedGuest)
14115 rc = DBGFTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx));
14116 else
14117 rc = VINF_EM_RAW_GUEST_TRAP;
14118
14119 if (rc == VINF_EM_RAW_GUEST_TRAP)
14120 {
14121 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14122 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14123 rc = VINF_SUCCESS;
14124 }
14125
14126 Assert(rc == VINF_SUCCESS || rc == VINF_EM_DBG_BREAKPOINT);
14127 return rc;
14128}
14129
14130
14131/**
14132 * VM-exit exception handler for \#AC (Alignment-check exception).
14133 *
14134 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14135 */
14136static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14137{
14138 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14139 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC);
14140
14141 /* Re-inject it. We'll detect any nesting before getting here. */
14142 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14143 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14144 return VINF_SUCCESS;
14145}
14146
14147
14148/**
14149 * VM-exit exception handler for \#DB (Debug exception).
14150 *
14151 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14152 */
14153static VBOXSTRICTRC hmR0VmxExitXcptDB(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14154{
14155 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14156 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
14157
14158 /*
14159 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
14160 */
14161 hmR0VmxReadExitQualVmcs(pVmxTransient);
14162
14163 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
14164 uint64_t const uDR6 = X86_DR6_INIT_VAL
14165 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
14166 | X86_DR6_BD | X86_DR6_BS));
14167
14168 int rc;
14169 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14170 if (!pVmxTransient->fIsNestedGuest)
14171 {
14172 rc = DBGFTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
14173
14174 /*
14175 * Prevents stepping twice over the same instruction when the guest is stepping using
14176 * EFLAGS.TF and the hypervisor debugger is stepping using MTF.
14177 * Testcase: DOSQEMM, break (using "ba x 1") at cs:rip 0x70:0x774 and step (using "t").
14178 */
14179 if ( rc == VINF_EM_DBG_STEPPED
14180 && (pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MONITOR_TRAP_FLAG))
14181 {
14182 Assert(pVCpu->hm.s.fSingleInstruction);
14183 rc = VINF_EM_RAW_GUEST_TRAP;
14184 }
14185 }
14186 else
14187 rc = VINF_EM_RAW_GUEST_TRAP;
14188 Log6Func(("rc=%Rrc\n", rc));
14189 if (rc == VINF_EM_RAW_GUEST_TRAP)
14190 {
14191 /*
14192 * The exception was for the guest. Update DR6, DR7.GD and
14193 * IA32_DEBUGCTL.LBR before forwarding it.
14194 * See Intel spec. 27.1 "Architectural State before a VM-Exit".
14195 */
14196 VMMRZCallRing3Disable(pVCpu);
14197 HM_DISABLE_PREEMPT(pVCpu);
14198
14199 pCtx->dr[6] &= ~X86_DR6_B_MASK;
14200 pCtx->dr[6] |= uDR6;
14201 if (CPUMIsGuestDebugStateActive(pVCpu))
14202 ASMSetDR6(pCtx->dr[6]);
14203
14204 HM_RESTORE_PREEMPT();
14205 VMMRZCallRing3Enable(pVCpu);
14206
14207 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_DR7);
14208 AssertRCReturn(rc, rc);
14209
14210 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
14211 pCtx->dr[7] &= ~(uint64_t)X86_DR7_GD;
14212
14213 /* Paranoia. */
14214 pCtx->dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
14215 pCtx->dr[7] |= X86_DR7_RA1_MASK;
14216
14217 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, pCtx->dr[7]);
14218 AssertRC(rc);
14219
14220 /*
14221 * Raise #DB in the guest.
14222 *
14223 * It is important to reflect exactly what the VM-exit gave us (preserving the
14224 * interruption-type) rather than use hmR0VmxSetPendingXcptDB() as the #DB could've
14225 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
14226 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
14227 *
14228 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
14229 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
14230 */
14231 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14232 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14233 return VINF_SUCCESS;
14234 }
14235
14236 /*
14237 * Not a guest trap, must be a hypervisor related debug event then.
14238 * Update DR6 in case someone is interested in it.
14239 */
14240 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
14241 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
14242 CPUMSetHyperDR6(pVCpu, uDR6);
14243
14244 return rc;
14245}
14246
14247
14248/**
14249 * Hacks its way around the lovely mesa driver's backdoor accesses.
14250 *
14251 * @sa hmR0SvmHandleMesaDrvGp.
14252 */
14253static int hmR0VmxHandleMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
14254{
14255 LogFunc(("cs:rip=%#04x:%#RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
14256 RT_NOREF(pCtx);
14257
14258 /* For now we'll just skip the instruction. */
14259 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14260}
14261
14262
14263/**
14264 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
14265 * backdoor logging w/o checking what it is running inside.
14266 *
14267 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
14268 * backdoor port and magic numbers loaded in registers.
14269 *
14270 * @returns true if it is, false if it isn't.
14271 * @sa hmR0SvmIsMesaDrvGp.
14272 */
14273DECLINLINE(bool) hmR0VmxIsMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
14274{
14275 /* 0xed: IN eAX,dx */
14276 uint8_t abInstr[1];
14277 if (pVmxTransient->cbExitInstr != sizeof(abInstr))
14278 return false;
14279
14280 /* Check that it is #GP(0). */
14281 if (pVmxTransient->uExitIntErrorCode != 0)
14282 return false;
14283
14284 /* Check magic and port. */
14285 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
14286 /*Log(("hmR0VmxIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
14287 if (pCtx->rax != UINT32_C(0x564d5868))
14288 return false;
14289 if (pCtx->dx != UINT32_C(0x5658))
14290 return false;
14291
14292 /* Flat ring-3 CS. */
14293 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
14294 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
14295 /*Log(("hmR0VmxIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
14296 if (pCtx->cs.Attr.n.u2Dpl != 3)
14297 return false;
14298 if (pCtx->cs.u64Base != 0)
14299 return false;
14300
14301 /* Check opcode. */
14302 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
14303 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
14304 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
14305 /*Log(("hmR0VmxIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
14306 if (RT_FAILURE(rc))
14307 return false;
14308 if (abInstr[0] != 0xed)
14309 return false;
14310
14311 return true;
14312}
14313
14314
14315/**
14316 * VM-exit exception handler for \#GP (General-protection exception).
14317 *
14318 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14319 */
14320static VBOXSTRICTRC hmR0VmxExitXcptGP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14321{
14322 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14323 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
14324
14325 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14326 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14327 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
14328 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
14329 { /* likely */ }
14330 else
14331 {
14332#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14333 Assert(pVCpu->hmr0.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
14334#endif
14335 /*
14336 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
14337 * executing a nested-guest, reflect #GP to the guest or nested-guest.
14338 */
14339 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14340 AssertRCReturn(rc, rc);
14341 Log4Func(("Gst: cs:rip=%#04x:%#RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
14342 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
14343
14344 if ( pVmxTransient->fIsNestedGuest
14345 || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
14346 || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
14347 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14348 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14349 else
14350 rc = hmR0VmxHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
14351 return rc;
14352 }
14353
14354 Assert(CPUMIsGuestInRealModeEx(pCtx));
14355 Assert(!pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest);
14356 Assert(!pVmxTransient->fIsNestedGuest);
14357
14358 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14359 AssertRCReturn(rc, rc);
14360
14361 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
14362 if (rcStrict == VINF_SUCCESS)
14363 {
14364 if (!CPUMIsGuestInRealModeEx(pCtx))
14365 {
14366 /*
14367 * The guest is no longer in real-mode, check if we can continue executing the
14368 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
14369 */
14370 pVmcsInfoShared->RealMode.fRealOnV86Active = false;
14371 if (HMCanExecuteVmxGuest(pVCpu->pVMR0, pVCpu, pCtx))
14372 {
14373 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
14374 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14375 }
14376 else
14377 {
14378 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
14379 rcStrict = VINF_EM_RESCHEDULE;
14380 }
14381 }
14382 else
14383 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14384 }
14385 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14386 {
14387 rcStrict = VINF_SUCCESS;
14388 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14389 }
14390 return VBOXSTRICTRC_VAL(rcStrict);
14391}
14392
14393
14394/**
14395 * VM-exit exception handler wrapper for all other exceptions that are not handled
14396 * by a specific handler.
14397 *
14398 * This simply re-injects the exception back into the VM without any special
14399 * processing.
14400 *
14401 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14402 */
14403static VBOXSTRICTRC hmR0VmxExitXcptOthers(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14404{
14405 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14406
14407#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14408 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14409 AssertMsg(pVCpu->hmr0.s.fUsingDebugLoop || pVmcsInfo->pShared->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
14410 ("uVector=%#x u32XcptBitmap=%#X32\n",
14411 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
14412 NOREF(pVmcsInfo);
14413#endif
14414
14415 /*
14416 * Re-inject the exception into the guest. This cannot be a double-fault condition which
14417 * would have been handled while checking exits due to event delivery.
14418 */
14419 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14420
14421#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14422 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
14423 AssertRCReturn(rc, rc);
14424 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
14425#endif
14426
14427#ifdef VBOX_WITH_STATISTICS
14428 switch (uVector)
14429 {
14430 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE); break;
14431 case X86_XCPT_DB: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB); break;
14432 case X86_XCPT_BP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); break;
14433 case X86_XCPT_OF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
14434 case X86_XCPT_BR: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBR); break;
14435 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); break;
14436 case X86_XCPT_NM: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
14437 case X86_XCPT_DF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDF); break;
14438 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS); break;
14439 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP); break;
14440 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS); break;
14441 case X86_XCPT_GP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP); break;
14442 case X86_XCPT_PF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); break;
14443 case X86_XCPT_MF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF); break;
14444 case X86_XCPT_AC: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC); break;
14445 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF); break;
14446 default:
14447 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
14448 break;
14449 }
14450#endif
14451
14452 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
14453 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
14454 NOREF(uVector);
14455
14456 /* Re-inject the original exception into the guest. */
14457 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14458 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14459 return VINF_SUCCESS;
14460}
14461
14462
14463/**
14464 * VM-exit exception handler for all exceptions (except NMIs!).
14465 *
14466 * @remarks This may be called for both guests and nested-guests. Take care to not
14467 * make assumptions and avoid doing anything that is not relevant when
14468 * executing a nested-guest (e.g., Mesa driver hacks).
14469 */
14470static VBOXSTRICTRC hmR0VmxExitXcpt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14471{
14472 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
14473
14474 /*
14475 * If this VM-exit occurred while delivering an event through the guest IDT, take
14476 * action based on the return code and additional hints (e.g. for page-faults)
14477 * that will be updated in the VMX transient structure.
14478 */
14479 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
14480 if (rcStrict == VINF_SUCCESS)
14481 {
14482 /*
14483 * If an exception caused a VM-exit due to delivery of an event, the original
14484 * event may have to be re-injected into the guest. We shall reinject it and
14485 * continue guest execution. However, page-fault is a complicated case and
14486 * needs additional processing done in hmR0VmxExitXcptPF().
14487 */
14488 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14489 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14490 if ( !pVCpu->hm.s.Event.fPending
14491 || uVector == X86_XCPT_PF)
14492 {
14493 switch (uVector)
14494 {
14495 case X86_XCPT_PF: return hmR0VmxExitXcptPF(pVCpu, pVmxTransient);
14496 case X86_XCPT_GP: return hmR0VmxExitXcptGP(pVCpu, pVmxTransient);
14497 case X86_XCPT_MF: return hmR0VmxExitXcptMF(pVCpu, pVmxTransient);
14498 case X86_XCPT_DB: return hmR0VmxExitXcptDB(pVCpu, pVmxTransient);
14499 case X86_XCPT_BP: return hmR0VmxExitXcptBP(pVCpu, pVmxTransient);
14500 case X86_XCPT_AC: return hmR0VmxExitXcptAC(pVCpu, pVmxTransient);
14501 default:
14502 return hmR0VmxExitXcptOthers(pVCpu, pVmxTransient);
14503 }
14504 }
14505 /* else: inject pending event before resuming guest execution. */
14506 }
14507 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
14508 {
14509 Assert(pVCpu->hm.s.Event.fPending);
14510 rcStrict = VINF_SUCCESS;
14511 }
14512
14513 return rcStrict;
14514}
14515/** @} */
14516
14517
14518/** @name VM-exit handlers.
14519 * @{
14520 */
14521/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
14522/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
14523/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
14524
14525/**
14526 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
14527 */
14528HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14529{
14530 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14531 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
14532 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
14533 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
14534 return VINF_SUCCESS;
14535 return VINF_EM_RAW_INTERRUPT;
14536}
14537
14538
14539/**
14540 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
14541 * VM-exit.
14542 */
14543HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14544{
14545 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14546 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
14547
14548 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
14549
14550 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
14551 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14552 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14553
14554 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14555 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
14556 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
14557 NOREF(pVmcsInfo);
14558
14559 VBOXSTRICTRC rcStrict;
14560 switch (uExitIntType)
14561 {
14562 /*
14563 * Host physical NMIs:
14564 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
14565 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
14566 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
14567 *
14568 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
14569 * See Intel spec. 27.5.5 "Updating Non-Register State".
14570 */
14571 case VMX_EXIT_INT_INFO_TYPE_NMI:
14572 {
14573 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
14574 break;
14575 }
14576
14577 /*
14578 * Privileged software exceptions (#DB from ICEBP),
14579 * Software exceptions (#BP and #OF),
14580 * Hardware exceptions:
14581 * Process the required exceptions and resume guest execution if possible.
14582 */
14583 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
14584 Assert(uVector == X86_XCPT_DB);
14585 RT_FALL_THRU();
14586 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
14587 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
14588 RT_FALL_THRU();
14589 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
14590 {
14591 NOREF(uVector);
14592 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
14593 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14594 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
14595 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
14596
14597 rcStrict = hmR0VmxExitXcpt(pVCpu, pVmxTransient);
14598 break;
14599 }
14600
14601 default:
14602 {
14603 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
14604 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
14605 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
14606 break;
14607 }
14608 }
14609
14610 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
14611 return rcStrict;
14612}
14613
14614
14615/**
14616 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
14617 */
14618HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14619{
14620 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14621
14622 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
14623 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14624 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
14625
14626 /* Evaluate and deliver pending events and resume guest execution. */
14627 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
14628 return VINF_SUCCESS;
14629}
14630
14631
14632/**
14633 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
14634 */
14635HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14636{
14637 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14638
14639 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14640 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
14641 {
14642 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
14643 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14644 }
14645
14646 Assert(!CPUMIsGuestNmiBlocking(pVCpu));
14647
14648 /*
14649 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
14650 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
14651 */
14652 uint32_t fIntrState;
14653 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14654 AssertRC(rc);
14655 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
14656 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
14657 {
14658 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
14659 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
14660
14661 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
14662 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
14663 AssertRC(rc);
14664 }
14665
14666 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
14667 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
14668
14669 /* Evaluate and deliver pending events and resume guest execution. */
14670 return VINF_SUCCESS;
14671}
14672
14673
14674/**
14675 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
14676 */
14677HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14678{
14679 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14680 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14681}
14682
14683
14684/**
14685 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
14686 */
14687HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14688{
14689 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14690 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14691}
14692
14693
14694/**
14695 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
14696 */
14697HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14698{
14699 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14700
14701 /*
14702 * Get the state we need and update the exit history entry.
14703 */
14704 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14705 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14706
14707 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14708 AssertRCReturn(rc, rc);
14709
14710 VBOXSTRICTRC rcStrict;
14711 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
14712 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
14713 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
14714 if (!pExitRec)
14715 {
14716 /*
14717 * Regular CPUID instruction execution.
14718 */
14719 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbExitInstr);
14720 if (rcStrict == VINF_SUCCESS)
14721 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14722 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14723 {
14724 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14725 rcStrict = VINF_SUCCESS;
14726 }
14727 }
14728 else
14729 {
14730 /*
14731 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
14732 */
14733 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14734 AssertRCReturn(rc2, rc2);
14735
14736 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
14737 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
14738
14739 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
14740 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14741
14742 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
14743 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14744 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
14745 }
14746 return rcStrict;
14747}
14748
14749
14750/**
14751 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
14752 */
14753HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14754{
14755 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14756
14757 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14758 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
14759 AssertRCReturn(rc, rc);
14760
14761 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
14762 return VINF_EM_RAW_EMULATE_INSTR;
14763
14764 AssertMsgFailed(("hmR0VmxExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
14765 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14766}
14767
14768
14769/**
14770 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
14771 */
14772HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14773{
14774 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14775
14776 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14777 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14778 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14779 AssertRCReturn(rc, rc);
14780
14781 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbExitInstr);
14782 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14783 {
14784 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14785 we must reset offsetting on VM-entry. See @bugref{6634}. */
14786 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14787 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14788 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14789 }
14790 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14791 {
14792 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14793 rcStrict = VINF_SUCCESS;
14794 }
14795 return rcStrict;
14796}
14797
14798
14799/**
14800 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
14801 */
14802HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14803{
14804 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14805
14806 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14807 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14808 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
14809 AssertRCReturn(rc, rc);
14810
14811 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbExitInstr);
14812 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14813 {
14814 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14815 we must reset offsetting on VM-reentry. See @bugref{6634}. */
14816 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14817 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14818 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14819 }
14820 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14821 {
14822 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14823 rcStrict = VINF_SUCCESS;
14824 }
14825 return rcStrict;
14826}
14827
14828
14829/**
14830 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
14831 */
14832HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14833{
14834 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14835
14836 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14837 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0
14838 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
14839 AssertRCReturn(rc, rc);
14840
14841 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14842 rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
14843 if (RT_LIKELY(rc == VINF_SUCCESS))
14844 {
14845 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14846 Assert(pVmxTransient->cbExitInstr == 2);
14847 }
14848 else
14849 {
14850 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
14851 rc = VERR_EM_INTERPRETER;
14852 }
14853 return rc;
14854}
14855
14856
14857/**
14858 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
14859 */
14860HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14861{
14862 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14863
14864 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
14865 if (EMAreHypercallInstructionsEnabled(pVCpu))
14866 {
14867 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14868 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
14869 | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
14870 AssertRCReturn(rc, rc);
14871
14872 /* Perform the hypercall. */
14873 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
14874 if (rcStrict == VINF_SUCCESS)
14875 {
14876 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14877 AssertRCReturn(rc, rc);
14878 }
14879 else
14880 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
14881 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
14882 || RT_FAILURE(rcStrict));
14883
14884 /* If the hypercall changes anything other than guest's general-purpose registers,
14885 we would need to reload the guest changed bits here before VM-entry. */
14886 }
14887 else
14888 Log4Func(("Hypercalls not enabled\n"));
14889
14890 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
14891 if (RT_FAILURE(rcStrict))
14892 {
14893 hmR0VmxSetPendingXcptUD(pVCpu);
14894 rcStrict = VINF_SUCCESS;
14895 }
14896
14897 return rcStrict;
14898}
14899
14900
14901/**
14902 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
14903 */
14904HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14905{
14906 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14907 Assert(!pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging || pVCpu->hmr0.s.fUsingDebugLoop);
14908
14909 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14910 hmR0VmxReadExitQualVmcs(pVmxTransient);
14911 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14912 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
14913 AssertRCReturn(rc, rc);
14914
14915 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->uExitQual);
14916
14917 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
14918 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14919 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14920 {
14921 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14922 rcStrict = VINF_SUCCESS;
14923 }
14924 else
14925 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
14926 VBOXSTRICTRC_VAL(rcStrict)));
14927 return rcStrict;
14928}
14929
14930
14931/**
14932 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
14933 */
14934HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14935{
14936 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14937
14938 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14939 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14940 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
14941 AssertRCReturn(rc, rc);
14942
14943 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbExitInstr);
14944 if (rcStrict == VINF_SUCCESS)
14945 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14946 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14947 {
14948 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14949 rcStrict = VINF_SUCCESS;
14950 }
14951
14952 return rcStrict;
14953}
14954
14955
14956/**
14957 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
14958 */
14959HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14960{
14961 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14962
14963 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14964 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14965 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14966 AssertRCReturn(rc, rc);
14967
14968 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbExitInstr);
14969 if (RT_SUCCESS(rcStrict))
14970 {
14971 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14972 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
14973 rcStrict = VINF_SUCCESS;
14974 }
14975
14976 return rcStrict;
14977}
14978
14979
14980/**
14981 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
14982 * VM-exit.
14983 */
14984HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14985{
14986 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14987 return VINF_EM_RESET;
14988}
14989
14990
14991/**
14992 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
14993 */
14994HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14995{
14996 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14997
14998 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14999 AssertRCReturn(rc, rc);
15000
15001 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
15002 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
15003 rc = VINF_SUCCESS;
15004 else
15005 rc = VINF_EM_HALT;
15006
15007 if (rc != VINF_SUCCESS)
15008 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
15009 return rc;
15010}
15011
15012
15013/**
15014 * VM-exit handler for instructions that result in a \#UD exception delivered to
15015 * the guest.
15016 */
15017HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15018{
15019 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15020 hmR0VmxSetPendingXcptUD(pVCpu);
15021 return VINF_SUCCESS;
15022}
15023
15024
15025/**
15026 * VM-exit handler for expiry of the VMX-preemption timer.
15027 */
15028HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15029{
15030 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15031
15032 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
15033 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
15034Log12(("hmR0VmxExitPreemptTimer:\n"));
15035
15036 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
15037 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15038 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
15039 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
15040 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
15041}
15042
15043
15044/**
15045 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
15046 */
15047HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15048{
15049 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15050
15051 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15052 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15053 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
15054 AssertRCReturn(rc, rc);
15055
15056 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbExitInstr);
15057 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
15058 : HM_CHANGED_RAISED_XCPT_MASK);
15059
15060 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15061 bool const fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
15062 if (fLoadSaveGuestXcr0 != pVCpu->hmr0.s.fLoadSaveGuestXcr0)
15063 {
15064 pVCpu->hmr0.s.fLoadSaveGuestXcr0 = fLoadSaveGuestXcr0;
15065 hmR0VmxUpdateStartVmFunction(pVCpu);
15066 }
15067
15068 return rcStrict;
15069}
15070
15071
15072/**
15073 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
15074 */
15075HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15076{
15077 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15078
15079 /** @todo Enable the new code after finding a reliably guest test-case. */
15080#if 1
15081 return VERR_EM_INTERPRETER;
15082#else
15083 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15084 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15085 hmR0VmxReadExitQualVmcs(pVmxTransient);
15086 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15087 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15088 AssertRCReturn(rc, rc);
15089
15090 /* Paranoia. Ensure this has a memory operand. */
15091 Assert(!pVmxTransient->ExitInstrInfo.Inv.u1Cleared0);
15092
15093 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
15094 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
15095 uint64_t const uType = CPUMIsGuestIn64BitCode(pVCpu) ? pVCpu->cpum.GstCtx.aGRegs[iGReg].u64
15096 : pVCpu->cpum.GstCtx.aGRegs[iGReg].u32;
15097
15098 RTGCPTR GCPtrDesc;
15099 HMVMX_DECODE_MEM_OPERAND(pVCpu, pVmxTransient->ExitInstrInfo.u, pVmxTransient->uExitQual, VMXMEMACCESS_READ, &GCPtrDesc);
15100
15101 VBOXSTRICTRC rcStrict = IEMExecDecodedInvpcid(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->ExitInstrInfo.Inv.iSegReg,
15102 GCPtrDesc, uType);
15103 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15104 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15105 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15106 {
15107 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15108 rcStrict = VINF_SUCCESS;
15109 }
15110 return rcStrict;
15111#endif
15112}
15113
15114
15115/**
15116 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
15117 * VM-exit.
15118 */
15119HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15120{
15121 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15122 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15123 AssertRCReturn(rc, rc);
15124
15125 rc = hmR0VmxCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
15126 if (RT_FAILURE(rc))
15127 return rc;
15128
15129 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
15130 NOREF(uInvalidReason);
15131
15132#ifdef VBOX_STRICT
15133 uint32_t fIntrState;
15134 uint64_t u64Val;
15135 hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
15136 hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
15137 hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
15138
15139 Log4(("uInvalidReason %u\n", uInvalidReason));
15140 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
15141 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
15142 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
15143
15144 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState); AssertRC(rc);
15145 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
15146 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Val); AssertRC(rc);
15147 Log4(("VMX_VMCS_GUEST_CR0 %#RX64\n", u64Val));
15148 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_MASK, &u64Val); AssertRC(rc);
15149 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RX64\n", u64Val));
15150 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Val); AssertRC(rc);
15151 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
15152 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_MASK, &u64Val); AssertRC(rc);
15153 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RX64\n", u64Val));
15154 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Val); AssertRC(rc);
15155 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
15156 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging)
15157 {
15158 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
15159 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
15160 }
15161 hmR0DumpRegs(pVCpu, HM_DUMP_REG_FLAGS_ALL);
15162#endif
15163
15164 return VERR_VMX_INVALID_GUEST_STATE;
15165}
15166
15167/**
15168 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
15169 */
15170HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUnexpected(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15171{
15172 /*
15173 * Cumulative notes of all recognized but unexpected VM-exits.
15174 *
15175 * 1. This does -not- cover scenarios like a page-fault VM-exit occurring when
15176 * nested-paging is used.
15177 *
15178 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
15179 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
15180 * this function (and thereby stop VM execution) for handling such instructions.
15181 *
15182 *
15183 * VMX_EXIT_INIT_SIGNAL:
15184 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
15185 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
15186 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
15187 *
15188 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
15189 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
15190 * See Intel spec. "23.8 Restrictions on VMX operation".
15191 *
15192 * VMX_EXIT_SIPI:
15193 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
15194 * activity state is used. We don't make use of it as our guests don't have direct
15195 * access to the host local APIC.
15196 *
15197 * See Intel spec. 25.3 "Other Causes of VM-exits".
15198 *
15199 * VMX_EXIT_IO_SMI:
15200 * VMX_EXIT_SMI:
15201 * This can only happen if we support dual-monitor treatment of SMI, which can be
15202 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
15203 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
15204 * VMX root mode or receive an SMI. If we get here, something funny is going on.
15205 *
15206 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
15207 * See Intel spec. 25.3 "Other Causes of VM-Exits"
15208 *
15209 * VMX_EXIT_ERR_MSR_LOAD:
15210 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
15211 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
15212 * execution.
15213 *
15214 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
15215 *
15216 * VMX_EXIT_ERR_MACHINE_CHECK:
15217 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
15218 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
15219 * #MC exception abort class exception is raised. We thus cannot assume a
15220 * reasonable chance of continuing any sort of execution and we bail.
15221 *
15222 * See Intel spec. 15.1 "Machine-check Architecture".
15223 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
15224 *
15225 * VMX_EXIT_PML_FULL:
15226 * VMX_EXIT_VIRTUALIZED_EOI:
15227 * VMX_EXIT_APIC_WRITE:
15228 * We do not currently support any of these features and thus they are all unexpected
15229 * VM-exits.
15230 *
15231 * VMX_EXIT_GDTR_IDTR_ACCESS:
15232 * VMX_EXIT_LDTR_TR_ACCESS:
15233 * VMX_EXIT_RDRAND:
15234 * VMX_EXIT_RSM:
15235 * VMX_EXIT_VMFUNC:
15236 * VMX_EXIT_ENCLS:
15237 * VMX_EXIT_RDSEED:
15238 * VMX_EXIT_XSAVES:
15239 * VMX_EXIT_XRSTORS:
15240 * VMX_EXIT_UMWAIT:
15241 * VMX_EXIT_TPAUSE:
15242 * These VM-exits are -not- caused unconditionally by execution of the corresponding
15243 * instruction. Any VM-exit for these instructions indicate a hardware problem,
15244 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
15245 *
15246 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
15247 */
15248 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15249 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
15250 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
15251}
15252
15253
15254/**
15255 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
15256 */
15257HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15258{
15259 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15260
15261 /** @todo Optimize this: We currently drag in the whole MSR state
15262 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
15263 * MSRs required. That would require changes to IEM and possibly CPUM too.
15264 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
15265 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15266 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
15267 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
15268 switch (idMsr)
15269 {
15270 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
15271 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
15272 }
15273
15274 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15275 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
15276 AssertRCReturn(rc, rc);
15277
15278 Log4Func(("ecx=%#RX32\n", idMsr));
15279
15280#ifdef VBOX_STRICT
15281 Assert(!pVmxTransient->fIsNestedGuest);
15282 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
15283 {
15284 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
15285 && idMsr != MSR_K6_EFER)
15286 {
15287 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
15288 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15289 }
15290 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15291 {
15292 Assert(pVmcsInfo->pvMsrBitmap);
15293 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
15294 if (fMsrpm & VMXMSRPM_ALLOW_RD)
15295 {
15296 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
15297 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15298 }
15299 }
15300 }
15301#endif
15302
15303 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbExitInstr);
15304 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
15305 if (rcStrict == VINF_SUCCESS)
15306 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15307 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15308 {
15309 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15310 rcStrict = VINF_SUCCESS;
15311 }
15312 else
15313 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ || rcStrict == VINF_EM_TRIPLE_FAULT,
15314 ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
15315
15316 return rcStrict;
15317}
15318
15319
15320/**
15321 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
15322 */
15323HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15324{
15325 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15326
15327 /** @todo Optimize this: We currently drag in the whole MSR state
15328 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
15329 * MSRs required. That would require changes to IEM and possibly CPUM too.
15330 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
15331 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
15332 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
15333
15334 /*
15335 * The FS and GS base MSRs are not part of the above all-MSRs mask.
15336 * Although we don't need to fetch the base as it will be overwritten shortly, while
15337 * loading guest-state we would also load the entire segment register including limit
15338 * and attributes and thus we need to load them here.
15339 */
15340 switch (idMsr)
15341 {
15342 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
15343 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
15344 }
15345
15346 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15347 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15348 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
15349 AssertRCReturn(rc, rc);
15350
15351 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
15352
15353 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbExitInstr);
15354 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
15355
15356 if (rcStrict == VINF_SUCCESS)
15357 {
15358 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15359
15360 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
15361 if ( idMsr == MSR_IA32_APICBASE
15362 || ( idMsr >= MSR_IA32_X2APIC_START
15363 && idMsr <= MSR_IA32_X2APIC_END))
15364 {
15365 /*
15366 * We've already saved the APIC related guest-state (TPR) in post-run phase.
15367 * When full APIC register virtualization is implemented we'll have to make
15368 * sure APIC state is saved from the VMCS before IEM changes it.
15369 */
15370 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
15371 }
15372 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
15373 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
15374 else if (idMsr == MSR_K6_EFER)
15375 {
15376 /*
15377 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
15378 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
15379 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
15380 */
15381 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
15382 }
15383
15384 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
15385 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
15386 {
15387 switch (idMsr)
15388 {
15389 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
15390 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
15391 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
15392 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_FS); break;
15393 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_GS); break;
15394 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
15395 default:
15396 {
15397 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15398 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
15399 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
15400 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
15401 break;
15402 }
15403 }
15404 }
15405#ifdef VBOX_STRICT
15406 else
15407 {
15408 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
15409 switch (idMsr)
15410 {
15411 case MSR_IA32_SYSENTER_CS:
15412 case MSR_IA32_SYSENTER_EIP:
15413 case MSR_IA32_SYSENTER_ESP:
15414 case MSR_K8_FS_BASE:
15415 case MSR_K8_GS_BASE:
15416 {
15417 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
15418 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15419 }
15420
15421 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
15422 default:
15423 {
15424 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
15425 {
15426 /* EFER MSR writes are always intercepted. */
15427 if (idMsr != MSR_K6_EFER)
15428 {
15429 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
15430 idMsr));
15431 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15432 }
15433 }
15434
15435 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15436 {
15437 Assert(pVmcsInfo->pvMsrBitmap);
15438 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
15439 if (fMsrpm & VMXMSRPM_ALLOW_WR)
15440 {
15441 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
15442 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15443 }
15444 }
15445 break;
15446 }
15447 }
15448 }
15449#endif /* VBOX_STRICT */
15450 }
15451 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15452 {
15453 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15454 rcStrict = VINF_SUCCESS;
15455 }
15456 else
15457 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE || rcStrict == VINF_EM_TRIPLE_FAULT,
15458 ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
15459
15460 return rcStrict;
15461}
15462
15463
15464/**
15465 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
15466 */
15467HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15468{
15469 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15470
15471 /** @todo The guest has likely hit a contended spinlock. We might want to
15472 * poke a schedule different guest VCPU. */
15473 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15474 if (RT_SUCCESS(rc))
15475 return VINF_EM_RAW_INTERRUPT;
15476
15477 AssertMsgFailed(("hmR0VmxExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
15478 return rc;
15479}
15480
15481
15482/**
15483 * VM-exit handler for when the TPR value is lowered below the specified
15484 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
15485 */
15486HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15487{
15488 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15489 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
15490
15491 /*
15492 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
15493 * We'll re-evaluate pending interrupts and inject them before the next VM
15494 * entry so we can just continue execution here.
15495 */
15496 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
15497 return VINF_SUCCESS;
15498}
15499
15500
15501/**
15502 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
15503 * VM-exit.
15504 *
15505 * @retval VINF_SUCCESS when guest execution can continue.
15506 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
15507 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
15508 * incompatible guest state for VMX execution (real-on-v86 case).
15509 */
15510HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15511{
15512 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15513 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
15514
15515 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15516 hmR0VmxReadExitQualVmcs(pVmxTransient);
15517 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15518
15519 VBOXSTRICTRC rcStrict;
15520 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15521 uint64_t const uExitQual = pVmxTransient->uExitQual;
15522 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
15523 switch (uAccessType)
15524 {
15525 /*
15526 * MOV to CRx.
15527 */
15528 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
15529 {
15530 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15531 AssertRCReturn(rc, rc);
15532
15533 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
15534 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
15535 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15536 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15537
15538 /*
15539 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
15540 * - When nested paging isn't used.
15541 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
15542 * - We are executing in the VM debug loop.
15543 */
15544 Assert( iCrReg != 3
15545 || !pVM->hmr0.s.fNestedPaging
15546 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15547 || pVCpu->hmr0.s.fUsingDebugLoop);
15548
15549 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
15550 Assert( iCrReg != 8
15551 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15552
15553 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15554 AssertMsg( rcStrict == VINF_SUCCESS
15555 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15556
15557 /*
15558 * This is a kludge for handling switches back to real mode when we try to use
15559 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
15560 * deal with special selector values, so we have to return to ring-3 and run
15561 * there till the selector values are V86 mode compatible.
15562 *
15563 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
15564 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
15565 * this function.
15566 */
15567 if ( iCrReg == 0
15568 && rcStrict == VINF_SUCCESS
15569 && !pVM->hmr0.s.vmx.fUnrestrictedGuest
15570 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
15571 && (uOldCr0 & X86_CR0_PE)
15572 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
15573 {
15574 /** @todo Check selectors rather than returning all the time. */
15575 Assert(!pVmxTransient->fIsNestedGuest);
15576 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
15577 rcStrict = VINF_EM_RESCHEDULE_REM;
15578 }
15579 break;
15580 }
15581
15582 /*
15583 * MOV from CRx.
15584 */
15585 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
15586 {
15587 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15588 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15589
15590 /*
15591 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
15592 * - When nested paging isn't used.
15593 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
15594 * - We are executing in the VM debug loop.
15595 */
15596 Assert( iCrReg != 3
15597 || !pVM->hmr0.s.fNestedPaging
15598 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15599 || pVCpu->hmr0.s.fLeaveDone);
15600
15601 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
15602 Assert( iCrReg != 8
15603 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15604
15605 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15606 break;
15607 }
15608
15609 /*
15610 * CLTS (Clear Task-Switch Flag in CR0).
15611 */
15612 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
15613 {
15614 rcStrict = hmR0VmxExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr);
15615 break;
15616 }
15617
15618 /*
15619 * LMSW (Load Machine-Status Word into CR0).
15620 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
15621 */
15622 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
15623 {
15624 RTGCPTR GCPtrEffDst;
15625 uint8_t const cbInstr = pVmxTransient->cbExitInstr;
15626 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
15627 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
15628 if (fMemOperand)
15629 {
15630 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
15631 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
15632 }
15633 else
15634 GCPtrEffDst = NIL_RTGCPTR;
15635 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
15636 break;
15637 }
15638
15639 default:
15640 {
15641 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
15642 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
15643 }
15644 }
15645
15646 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
15647 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
15648 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15649
15650 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
15651 NOREF(pVM);
15652 return rcStrict;
15653}
15654
15655
15656/**
15657 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
15658 * VM-exit.
15659 */
15660HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15661{
15662 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15663 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
15664
15665 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15666 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15667 hmR0VmxReadExitQualVmcs(pVmxTransient);
15668 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15669 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK
15670 | CPUMCTX_EXTRN_EFER);
15671 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
15672 AssertRCReturn(rc, rc);
15673
15674 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
15675 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
15676 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
15677 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
15678 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
15679 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
15680 bool const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
15681 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
15682
15683 /*
15684 * Update exit history to see if this exit can be optimized.
15685 */
15686 VBOXSTRICTRC rcStrict;
15687 PCEMEXITREC pExitRec = NULL;
15688 if ( !fGstStepping
15689 && !fDbgStepping)
15690 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15691 !fIOString
15692 ? !fIOWrite
15693 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
15694 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
15695 : !fIOWrite
15696 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
15697 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
15698 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15699 if (!pExitRec)
15700 {
15701 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
15702 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
15703
15704 uint32_t const cbValue = s_aIOSizes[uIOSize];
15705 uint32_t const cbInstr = pVmxTransient->cbExitInstr;
15706 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
15707 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15708 if (fIOString)
15709 {
15710 /*
15711 * INS/OUTS - I/O String instruction.
15712 *
15713 * Use instruction-information if available, otherwise fall back on
15714 * interpreting the instruction.
15715 */
15716 Log4Func(("cs:rip=%#04x:%#RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15717 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
15718 bool const fInsOutsInfo = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
15719 if (fInsOutsInfo)
15720 {
15721 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15722 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
15723 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
15724 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
15725 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
15726 if (fIOWrite)
15727 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
15728 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
15729 else
15730 {
15731 /*
15732 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
15733 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
15734 * See Intel Instruction spec. for "INS".
15735 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
15736 */
15737 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
15738 }
15739 }
15740 else
15741 rcStrict = IEMExecOne(pVCpu);
15742
15743 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15744 fUpdateRipAlready = true;
15745 }
15746 else
15747 {
15748 /*
15749 * IN/OUT - I/O instruction.
15750 */
15751 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15752 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
15753 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
15754 if (fIOWrite)
15755 {
15756 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
15757 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
15758 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15759 && !pCtx->eflags.Bits.u1TF)
15760 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
15761 }
15762 else
15763 {
15764 uint32_t u32Result = 0;
15765 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
15766 if (IOM_SUCCESS(rcStrict))
15767 {
15768 /* Save result of I/O IN instr. in AL/AX/EAX. */
15769 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
15770 }
15771 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15772 && !pCtx->eflags.Bits.u1TF)
15773 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
15774 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
15775 }
15776 }
15777
15778 if (IOM_SUCCESS(rcStrict))
15779 {
15780 if (!fUpdateRipAlready)
15781 {
15782 hmR0VmxAdvanceGuestRipBy(pVCpu, cbInstr);
15783 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15784 }
15785
15786 /*
15787 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
15788 * while booting Fedora 17 64-bit guest.
15789 *
15790 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
15791 */
15792 if (fIOString)
15793 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
15794
15795 /*
15796 * If any I/O breakpoints are armed, we need to check if one triggered
15797 * and take appropriate action.
15798 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
15799 */
15800 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_DR7);
15801 AssertRCReturn(rc, rc);
15802
15803 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
15804 * execution engines about whether hyper BPs and such are pending. */
15805 uint32_t const uDr7 = pCtx->dr[7];
15806 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
15807 && X86_DR7_ANY_RW_IO(uDr7)
15808 && (pCtx->cr4 & X86_CR4_DE))
15809 || DBGFBpIsHwIoArmed(pVM)))
15810 {
15811 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
15812
15813 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
15814 VMMRZCallRing3Disable(pVCpu);
15815 HM_DISABLE_PREEMPT(pVCpu);
15816
15817 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
15818
15819 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
15820 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
15821 {
15822 /* Raise #DB. */
15823 if (fIsGuestDbgActive)
15824 ASMSetDR6(pCtx->dr[6]);
15825 if (pCtx->dr[7] != uDr7)
15826 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_DR7;
15827
15828 hmR0VmxSetPendingXcptDB(pVCpu);
15829 }
15830 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
15831 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
15832 else if ( rcStrict2 != VINF_SUCCESS
15833 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
15834 rcStrict = rcStrict2;
15835 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
15836
15837 HM_RESTORE_PREEMPT();
15838 VMMRZCallRing3Enable(pVCpu);
15839 }
15840 }
15841
15842#ifdef VBOX_STRICT
15843 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15844 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
15845 Assert(!fIOWrite);
15846 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15847 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
15848 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
15849 Assert(fIOWrite);
15850 else
15851 {
15852# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
15853 * statuses, that the VMM device and some others may return. See
15854 * IOM_SUCCESS() for guidance. */
15855 AssertMsg( RT_FAILURE(rcStrict)
15856 || rcStrict == VINF_SUCCESS
15857 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
15858 || rcStrict == VINF_EM_DBG_BREAKPOINT
15859 || rcStrict == VINF_EM_RAW_GUEST_TRAP
15860 || rcStrict == VINF_EM_RAW_TO_R3
15861 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15862# endif
15863 }
15864#endif
15865 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
15866 }
15867 else
15868 {
15869 /*
15870 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
15871 */
15872 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15873 AssertRCReturn(rc2, rc2);
15874 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &pVCpu->hm.s.StatExitIOWrite : &pVCpu->hm.s.StatExitIORead
15875 : fIOWrite ? &pVCpu->hm.s.StatExitIOStringWrite : &pVCpu->hm.s.StatExitIOStringRead);
15876 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
15877 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15878 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
15879 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
15880
15881 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15882 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15883
15884 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15885 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15886 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15887 }
15888 return rcStrict;
15889}
15890
15891
15892/**
15893 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
15894 * VM-exit.
15895 */
15896HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15897{
15898 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15899
15900 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
15901 hmR0VmxReadExitQualVmcs(pVmxTransient);
15902 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
15903 {
15904 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15905 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
15906 {
15907 uint32_t uErrCode;
15908 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
15909 {
15910 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15911 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
15912 }
15913 else
15914 uErrCode = 0;
15915
15916 RTGCUINTPTR GCPtrFaultAddress;
15917 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
15918 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
15919 else
15920 GCPtrFaultAddress = 0;
15921
15922 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15923
15924 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
15925 pVmxTransient->cbExitInstr, uErrCode, GCPtrFaultAddress);
15926
15927 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
15928 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
15929 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15930 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15931 }
15932 }
15933
15934 /* Fall back to the interpreter to emulate the task-switch. */
15935 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
15936 return VERR_EM_INTERPRETER;
15937}
15938
15939
15940/**
15941 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
15942 */
15943HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15944{
15945 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15946
15947 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15948 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
15949 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
15950 AssertRC(rc);
15951 return VINF_EM_DBG_STEPPED;
15952}
15953
15954
15955/**
15956 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
15957 */
15958HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15959{
15960 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15961 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
15962
15963 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
15964 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
15965 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15966 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15967 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15968
15969 /*
15970 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
15971 */
15972 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
15973 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15974 {
15975 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
15976 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
15977 {
15978 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
15979 return VINF_EM_RAW_INJECT_TRPM_EVENT;
15980 }
15981 }
15982 else
15983 {
15984 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
15985 return rcStrict;
15986 }
15987
15988 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
15989 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15990 hmR0VmxReadExitQualVmcs(pVmxTransient);
15991 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15992 AssertRCReturn(rc, rc);
15993
15994 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
15995 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
15996 switch (uAccessType)
15997 {
15998 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
15999 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
16000 {
16001 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
16002 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
16003 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
16004
16005 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
16006 GCPhys &= PAGE_BASE_GC_MASK;
16007 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
16008 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
16009 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
16010
16011 rcStrict = IOMR0MmioPhysHandler(pVCpu->CTX_SUFF(pVM), pVCpu,
16012 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW, GCPhys);
16013 Log4Func(("IOMMMIOPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
16014 if ( rcStrict == VINF_SUCCESS
16015 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16016 || rcStrict == VERR_PAGE_NOT_PRESENT)
16017 {
16018 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
16019 | HM_CHANGED_GUEST_APIC_TPR);
16020 rcStrict = VINF_SUCCESS;
16021 }
16022 break;
16023 }
16024
16025 default:
16026 {
16027 Log4Func(("uAccessType=%#x\n", uAccessType));
16028 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
16029 break;
16030 }
16031 }
16032
16033 if (rcStrict != VINF_SUCCESS)
16034 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
16035 return rcStrict;
16036}
16037
16038
16039/**
16040 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
16041 * VM-exit.
16042 */
16043HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16044{
16045 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16046 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16047
16048 /* We might get this VM-exit if the nested-guest is not intercepting MOV DRx accesses. */
16049 if (!pVmxTransient->fIsNestedGuest)
16050 {
16051 /* We should -not- get this VM-exit if the guest's debug registers were active. */
16052 if (pVmxTransient->fWasGuestDebugStateActive)
16053 {
16054 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
16055 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
16056 }
16057
16058 if ( !pVCpu->hm.s.fSingleInstruction
16059 && !pVmxTransient->fWasHyperDebugStateActive)
16060 {
16061 Assert(!DBGFIsStepping(pVCpu));
16062 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
16063
16064 /* Don't intercept MOV DRx any more. */
16065 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
16066 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
16067 AssertRC(rc);
16068
16069 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
16070 VMMRZCallRing3Disable(pVCpu);
16071 HM_DISABLE_PREEMPT(pVCpu);
16072
16073 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
16074 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
16075 Assert(CPUMIsGuestDebugStateActive(pVCpu));
16076
16077 HM_RESTORE_PREEMPT();
16078 VMMRZCallRing3Enable(pVCpu);
16079
16080#ifdef VBOX_WITH_STATISTICS
16081 hmR0VmxReadExitQualVmcs(pVmxTransient);
16082 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
16083 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
16084 else
16085 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
16086#endif
16087 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
16088 return VINF_SUCCESS;
16089 }
16090 }
16091
16092 /*
16093 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER MSR, CS.
16094 * The EFER MSR is always up-to-date.
16095 * Update the segment registers and DR7 from the CPU.
16096 */
16097 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16098 hmR0VmxReadExitQualVmcs(pVmxTransient);
16099 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_DR7);
16100 AssertRCReturn(rc, rc);
16101 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
16102
16103 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16104 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
16105 {
16106 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
16107 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual),
16108 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual));
16109 if (RT_SUCCESS(rc))
16110 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
16111 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
16112 }
16113 else
16114 {
16115 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
16116 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual),
16117 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual));
16118 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
16119 }
16120
16121 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
16122 if (RT_SUCCESS(rc))
16123 {
16124 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
16125 AssertRCReturn(rc2, rc2);
16126 return VINF_SUCCESS;
16127 }
16128 return rc;
16129}
16130
16131
16132/**
16133 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
16134 * Conditional VM-exit.
16135 */
16136HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16137{
16138 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16139 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16140
16141 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16142 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16143 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16144 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16145 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16146
16147 /*
16148 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
16149 */
16150 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
16151 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16152 {
16153 /*
16154 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
16155 * instruction emulation to inject the original event. Otherwise, injecting the original event
16156 * using hardware-assisted VMX would trigger the same EPT misconfig VM-exit again.
16157 */
16158 if (!pVCpu->hm.s.Event.fPending)
16159 { /* likely */ }
16160 else
16161 {
16162 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
16163#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16164 /** @todo NSTVMX: Think about how this should be handled. */
16165 if (pVmxTransient->fIsNestedGuest)
16166 return VERR_VMX_IPE_3;
16167#endif
16168 return VINF_EM_RAW_INJECT_TRPM_EVENT;
16169 }
16170 }
16171 else
16172 {
16173 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
16174 return rcStrict;
16175 }
16176
16177 /*
16178 * Get sufficient state and update the exit history entry.
16179 */
16180 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16181 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
16182 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
16183 AssertRCReturn(rc, rc);
16184
16185 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
16186 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
16187 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
16188 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
16189 if (!pExitRec)
16190 {
16191 /*
16192 * If we succeed, resume guest execution.
16193 * If we fail in interpreting the instruction because we couldn't get the guest physical address
16194 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
16195 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
16196 * weird case. See @bugref{6043}.
16197 */
16198 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16199 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16200/** @todo bird: We can probably just go straight to IOM here and assume that
16201 * it's MMIO, then fall back on PGM if that hunch didn't work out so
16202 * well. However, we need to address that aliasing workarounds that
16203 * PGMR0Trap0eHandlerNPMisconfig implements. So, some care is needed.
16204 *
16205 * Might also be interesting to see if we can get this done more or
16206 * less locklessly inside IOM. Need to consider the lookup table
16207 * updating and use a bit more carefully first (or do all updates via
16208 * rendezvous) */
16209 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
16210 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pCtx->rip, VBOXSTRICTRC_VAL(rcStrict)));
16211 if ( rcStrict == VINF_SUCCESS
16212 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16213 || rcStrict == VERR_PAGE_NOT_PRESENT)
16214 {
16215 /* Successfully handled MMIO operation. */
16216 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
16217 | HM_CHANGED_GUEST_APIC_TPR);
16218 rcStrict = VINF_SUCCESS;
16219 }
16220 }
16221 else
16222 {
16223 /*
16224 * Frequent exit or something needing probing. Call EMHistoryExec.
16225 */
16226 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
16227 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
16228
16229 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
16230 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16231
16232 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
16233 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
16234 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
16235 }
16236 return rcStrict;
16237}
16238
16239
16240/**
16241 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
16242 * VM-exit.
16243 */
16244HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16245{
16246 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16247 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16248
16249 hmR0VmxReadExitQualVmcs(pVmxTransient);
16250 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16251 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16252 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16253 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16254 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16255
16256 /*
16257 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
16258 */
16259 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
16260 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16261 {
16262 /*
16263 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
16264 * we shall resolve the nested #PF and re-inject the original event.
16265 */
16266 if (pVCpu->hm.s.Event.fPending)
16267 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflectNPF);
16268 }
16269 else
16270 {
16271 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
16272 return rcStrict;
16273 }
16274
16275 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16276 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
16277 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
16278 AssertRCReturn(rc, rc);
16279
16280 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
16281 uint64_t const uExitQual = pVmxTransient->uExitQual;
16282 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
16283
16284 RTGCUINT uErrorCode = 0;
16285 if (uExitQual & VMX_EXIT_QUAL_EPT_INSTR_FETCH)
16286 uErrorCode |= X86_TRAP_PF_ID;
16287 if (uExitQual & VMX_EXIT_QUAL_EPT_DATA_WRITE)
16288 uErrorCode |= X86_TRAP_PF_RW;
16289 if (uExitQual & VMX_EXIT_QUAL_EPT_ENTRY_PRESENT)
16290 uErrorCode |= X86_TRAP_PF_P;
16291
16292 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16293 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16294 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%#RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
16295
16296 /*
16297 * Handle the pagefault trap for the nested shadow table.
16298 */
16299 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
16300 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pCtx), GCPhys);
16301 TRPMResetTrap(pVCpu);
16302
16303 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
16304 if ( rcStrict == VINF_SUCCESS
16305 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16306 || rcStrict == VERR_PAGE_NOT_PRESENT)
16307 {
16308 /* Successfully synced our nested page tables. */
16309 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
16310 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
16311 return VINF_SUCCESS;
16312 }
16313
16314 Log4Func(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
16315 return rcStrict;
16316}
16317
16318
16319#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16320/**
16321 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
16322 */
16323HMVMX_EXIT_DECL hmR0VmxExitVmclear(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16324{
16325 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16326
16327 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16328 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16329 hmR0VmxReadExitQualVmcs(pVmxTransient);
16330 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16331 | CPUMCTX_EXTRN_HWVIRT
16332 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16333 AssertRCReturn(rc, rc);
16334
16335 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16336
16337 VMXVEXITINFO ExitInfo;
16338 RT_ZERO(ExitInfo);
16339 ExitInfo.uReason = pVmxTransient->uExitReason;
16340 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16341 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16342 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16343 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16344
16345 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
16346 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16347 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16348 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16349 {
16350 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16351 rcStrict = VINF_SUCCESS;
16352 }
16353 return rcStrict;
16354}
16355
16356
16357/**
16358 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
16359 */
16360HMVMX_EXIT_DECL hmR0VmxExitVmlaunch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16361{
16362 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16363
16364 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
16365 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
16366 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16367 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16368 AssertRCReturn(rc, rc);
16369
16370 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16371
16372 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
16373 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMLAUNCH);
16374 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
16375 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16376 {
16377 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16378 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
16379 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
16380 }
16381 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
16382 return rcStrict;
16383}
16384
16385
16386/**
16387 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
16388 */
16389HMVMX_EXIT_DECL hmR0VmxExitVmptrld(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16390{
16391 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16392
16393 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16394 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16395 hmR0VmxReadExitQualVmcs(pVmxTransient);
16396 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16397 | CPUMCTX_EXTRN_HWVIRT
16398 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16399 AssertRCReturn(rc, rc);
16400
16401 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16402
16403 VMXVEXITINFO ExitInfo;
16404 RT_ZERO(ExitInfo);
16405 ExitInfo.uReason = pVmxTransient->uExitReason;
16406 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16407 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16408 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16409 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16410
16411 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
16412 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16413 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16414 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16415 {
16416 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16417 rcStrict = VINF_SUCCESS;
16418 }
16419 return rcStrict;
16420}
16421
16422
16423/**
16424 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
16425 */
16426HMVMX_EXIT_DECL hmR0VmxExitVmptrst(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16427{
16428 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16429
16430 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16431 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16432 hmR0VmxReadExitQualVmcs(pVmxTransient);
16433 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16434 | CPUMCTX_EXTRN_HWVIRT
16435 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16436 AssertRCReturn(rc, rc);
16437
16438 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16439
16440 VMXVEXITINFO ExitInfo;
16441 RT_ZERO(ExitInfo);
16442 ExitInfo.uReason = pVmxTransient->uExitReason;
16443 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16444 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16445 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16446 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
16447
16448 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
16449 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16450 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16451 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16452 {
16453 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16454 rcStrict = VINF_SUCCESS;
16455 }
16456 return rcStrict;
16457}
16458
16459
16460/**
16461 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
16462 */
16463HMVMX_EXIT_DECL hmR0VmxExitVmread(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16464{
16465 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16466
16467 /*
16468 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
16469 * thus might not need to import the shadow VMCS state, it's safer just in case
16470 * code elsewhere dares look at unsynced VMCS fields.
16471 */
16472 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16473 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16474 hmR0VmxReadExitQualVmcs(pVmxTransient);
16475 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16476 | CPUMCTX_EXTRN_HWVIRT
16477 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16478 AssertRCReturn(rc, rc);
16479
16480 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16481
16482 VMXVEXITINFO ExitInfo;
16483 RT_ZERO(ExitInfo);
16484 ExitInfo.uReason = pVmxTransient->uExitReason;
16485 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16486 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16487 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16488 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
16489 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
16490
16491 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
16492 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16493 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16494 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16495 {
16496 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16497 rcStrict = VINF_SUCCESS;
16498 }
16499 return rcStrict;
16500}
16501
16502
16503/**
16504 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
16505 */
16506HMVMX_EXIT_DECL hmR0VmxExitVmresume(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16507{
16508 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16509
16510 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
16511 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
16512 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16513 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16514 AssertRCReturn(rc, rc);
16515
16516 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16517
16518 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
16519 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMRESUME);
16520 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
16521 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16522 {
16523 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16524 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
16525 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
16526 }
16527 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
16528 return rcStrict;
16529}
16530
16531
16532/**
16533 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
16534 */
16535HMVMX_EXIT_DECL hmR0VmxExitVmwrite(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16536{
16537 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16538
16539 /*
16540 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
16541 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
16542 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
16543 */
16544 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16545 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16546 hmR0VmxReadExitQualVmcs(pVmxTransient);
16547 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16548 | CPUMCTX_EXTRN_HWVIRT
16549 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16550 AssertRCReturn(rc, rc);
16551
16552 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16553
16554 VMXVEXITINFO ExitInfo;
16555 RT_ZERO(ExitInfo);
16556 ExitInfo.uReason = pVmxTransient->uExitReason;
16557 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16558 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16559 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16560 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
16561 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16562
16563 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
16564 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16565 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16566 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16567 {
16568 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16569 rcStrict = VINF_SUCCESS;
16570 }
16571 return rcStrict;
16572}
16573
16574
16575/**
16576 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
16577 */
16578HMVMX_EXIT_DECL hmR0VmxExitVmxoff(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16579{
16580 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16581
16582 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16583 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
16584 | CPUMCTX_EXTRN_HWVIRT
16585 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
16586 AssertRCReturn(rc, rc);
16587
16588 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16589
16590 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbExitInstr);
16591 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16592 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
16593 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16594 {
16595 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16596 rcStrict = VINF_SUCCESS;
16597 }
16598 return rcStrict;
16599}
16600
16601
16602/**
16603 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
16604 */
16605HMVMX_EXIT_DECL hmR0VmxExitVmxon(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16606{
16607 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16608
16609 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16610 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16611 hmR0VmxReadExitQualVmcs(pVmxTransient);
16612 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16613 | CPUMCTX_EXTRN_HWVIRT
16614 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16615 AssertRCReturn(rc, rc);
16616
16617 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16618
16619 VMXVEXITINFO ExitInfo;
16620 RT_ZERO(ExitInfo);
16621 ExitInfo.uReason = pVmxTransient->uExitReason;
16622 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16623 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16624 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16625 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16626
16627 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
16628 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16629 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16630 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16631 {
16632 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16633 rcStrict = VINF_SUCCESS;
16634 }
16635 return rcStrict;
16636}
16637
16638
16639/**
16640 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
16641 */
16642HMVMX_EXIT_DECL hmR0VmxExitInvvpid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16643{
16644 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16645
16646 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16647 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16648 hmR0VmxReadExitQualVmcs(pVmxTransient);
16649 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16650 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16651 AssertRCReturn(rc, rc);
16652
16653 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16654
16655 VMXVEXITINFO ExitInfo;
16656 RT_ZERO(ExitInfo);
16657 ExitInfo.uReason = pVmxTransient->uExitReason;
16658 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16659 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16660 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16661 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16662
16663 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
16664 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16665 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16666 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16667 {
16668 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16669 rcStrict = VINF_SUCCESS;
16670 }
16671 return rcStrict;
16672}
16673#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16674/** @} */
16675
16676
16677#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16678/** @name Nested-guest VM-exit handlers.
16679 * @{
16680 */
16681/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16682/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16683/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16684
16685/**
16686 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
16687 * Conditional VM-exit.
16688 */
16689HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16690{
16691 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16692
16693 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16694
16695 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
16696 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
16697 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
16698
16699 switch (uExitIntType)
16700 {
16701 /*
16702 * Physical NMIs:
16703 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
16704 */
16705 case VMX_EXIT_INT_INFO_TYPE_NMI:
16706 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
16707
16708 /*
16709 * Hardware exceptions,
16710 * Software exceptions,
16711 * Privileged software exceptions:
16712 * Figure out if the exception must be delivered to the guest or the nested-guest.
16713 */
16714 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
16715 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
16716 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
16717 {
16718 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16719 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16720 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16721 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16722
16723 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16724 bool const fIntercept = CPUMIsGuestVmxXcptInterceptSet(pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo),
16725 pVmxTransient->uExitIntErrorCode);
16726 if (fIntercept)
16727 {
16728 /* Exit qualification is required for debug and page-fault exceptions. */
16729 hmR0VmxReadExitQualVmcs(pVmxTransient);
16730
16731 /*
16732 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
16733 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
16734 * length. However, if delivery of a software interrupt, software exception or privileged
16735 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
16736 */
16737 VMXVEXITINFO ExitInfo;
16738 RT_ZERO(ExitInfo);
16739 ExitInfo.uReason = pVmxTransient->uExitReason;
16740 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16741 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16742
16743 VMXVEXITEVENTINFO ExitEventInfo;
16744 RT_ZERO(ExitEventInfo);
16745 ExitEventInfo.uExitIntInfo = pVmxTransient->uExitIntInfo;
16746 ExitEventInfo.uExitIntErrCode = pVmxTransient->uExitIntErrorCode;
16747 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16748 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16749
16750#ifdef DEBUG_ramshankar
16751 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16752 Log4Func(("exit_int_info=%#RX32 err_code=%#RX32 exit_qual=%#RX64\n", pVmxTransient->uExitIntInfo,
16753 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
16754 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
16755 {
16756 Log4Func(("idt_info=%#RX32 idt_errcode=%#RX32 cr2=%#RX64\n", pVmxTransient->uIdtVectoringInfo,
16757 pVmxTransient->uIdtVectoringErrorCode, pCtx->cr2));
16758 }
16759#endif
16760 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo);
16761 }
16762
16763 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs in hmR0VmxExitXcptPF. */
16764 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16765 return hmR0VmxExitXcpt(pVCpu, pVmxTransient);
16766 }
16767
16768 /*
16769 * Software interrupts:
16770 * VM-exits cannot be caused by software interrupts.
16771 *
16772 * External interrupts:
16773 * This should only happen when "acknowledge external interrupts on VM-exit"
16774 * control is set. However, we never set this when executing a guest or
16775 * nested-guest. For nested-guests it is emulated while injecting interrupts into
16776 * the guest.
16777 */
16778 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
16779 case VMX_EXIT_INT_INFO_TYPE_EXT_INT:
16780 default:
16781 {
16782 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
16783 return VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
16784 }
16785 }
16786}
16787
16788
16789/**
16790 * Nested-guest VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT).
16791 * Unconditional VM-exit.
16792 */
16793HMVMX_EXIT_DECL hmR0VmxExitTripleFaultNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16794{
16795 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16796 return IEMExecVmxVmexitTripleFault(pVCpu);
16797}
16798
16799
16800/**
16801 * Nested-guest VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
16802 */
16803HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16804{
16805 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16806
16807 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
16808 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16809 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16810}
16811
16812
16813/**
16814 * Nested-guest VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
16815 */
16816HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16817{
16818 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16819
16820 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
16821 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16822 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16823}
16824
16825
16826/**
16827 * Nested-guest VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH).
16828 * Unconditional VM-exit.
16829 */
16830HMVMX_EXIT_DECL hmR0VmxExitTaskSwitchNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16831{
16832 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16833
16834 hmR0VmxReadExitQualVmcs(pVmxTransient);
16835 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16836 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16837 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16838
16839 VMXVEXITINFO ExitInfo;
16840 RT_ZERO(ExitInfo);
16841 ExitInfo.uReason = pVmxTransient->uExitReason;
16842 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16843 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16844
16845 VMXVEXITEVENTINFO ExitEventInfo;
16846 RT_ZERO(ExitEventInfo);
16847 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16848 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16849 return IEMExecVmxVmexitTaskSwitch(pVCpu, &ExitInfo, &ExitEventInfo);
16850}
16851
16852
16853/**
16854 * Nested-guest VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
16855 */
16856HMVMX_EXIT_DECL hmR0VmxExitHltNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16857{
16858 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16859
16860 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_HLT_EXIT))
16861 {
16862 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16863 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16864 }
16865 return hmR0VmxExitHlt(pVCpu, pVmxTransient);
16866}
16867
16868
16869/**
16870 * Nested-guest VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
16871 */
16872HMVMX_EXIT_DECL hmR0VmxExitInvlpgNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16873{
16874 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16875
16876 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16877 {
16878 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16879 hmR0VmxReadExitQualVmcs(pVmxTransient);
16880
16881 VMXVEXITINFO ExitInfo;
16882 RT_ZERO(ExitInfo);
16883 ExitInfo.uReason = pVmxTransient->uExitReason;
16884 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16885 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16886 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16887 }
16888 return hmR0VmxExitInvlpg(pVCpu, pVmxTransient);
16889}
16890
16891
16892/**
16893 * Nested-guest VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
16894 */
16895HMVMX_EXIT_DECL hmR0VmxExitRdpmcNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16896{
16897 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16898
16899 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDPMC_EXIT))
16900 {
16901 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16902 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16903 }
16904 return hmR0VmxExitRdpmc(pVCpu, pVmxTransient);
16905}
16906
16907
16908/**
16909 * Nested-guest VM-exit handler for VMREAD (VMX_EXIT_VMREAD) and VMWRITE
16910 * (VMX_EXIT_VMWRITE). Conditional VM-exit.
16911 */
16912HMVMX_EXIT_DECL hmR0VmxExitVmreadVmwriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16913{
16914 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16915
16916 Assert( pVmxTransient->uExitReason == VMX_EXIT_VMREAD
16917 || pVmxTransient->uExitReason == VMX_EXIT_VMWRITE);
16918
16919 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16920
16921 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
16922 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16923 uint64_t u64VmcsField = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16924
16925 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
16926 if (!CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
16927 u64VmcsField &= UINT64_C(0xffffffff);
16928
16929 if (CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, pVmxTransient->uExitReason, u64VmcsField))
16930 {
16931 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16932 hmR0VmxReadExitQualVmcs(pVmxTransient);
16933
16934 VMXVEXITINFO ExitInfo;
16935 RT_ZERO(ExitInfo);
16936 ExitInfo.uReason = pVmxTransient->uExitReason;
16937 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16938 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16939 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
16940 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16941 }
16942
16943 if (pVmxTransient->uExitReason == VMX_EXIT_VMREAD)
16944 return hmR0VmxExitVmread(pVCpu, pVmxTransient);
16945 return hmR0VmxExitVmwrite(pVCpu, pVmxTransient);
16946}
16947
16948
16949/**
16950 * Nested-guest VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
16951 */
16952HMVMX_EXIT_DECL hmR0VmxExitRdtscNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16953{
16954 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16955
16956 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
16957 {
16958 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16959 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16960 }
16961
16962 return hmR0VmxExitRdtsc(pVCpu, pVmxTransient);
16963}
16964
16965
16966/**
16967 * Nested-guest VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX).
16968 * Conditional VM-exit.
16969 */
16970HMVMX_EXIT_DECL hmR0VmxExitMovCRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16971{
16972 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16973
16974 hmR0VmxReadExitQualVmcs(pVmxTransient);
16975 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16976
16977 VBOXSTRICTRC rcStrict;
16978 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual);
16979 switch (uAccessType)
16980 {
16981 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
16982 {
16983 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
16984 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
16985 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
16986 uint64_t const uNewCrX = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
16987
16988 bool fIntercept;
16989 switch (iCrReg)
16990 {
16991 case 0:
16992 case 4:
16993 fIntercept = CPUMIsGuestVmxMovToCr0Cr4InterceptSet(&pVCpu->cpum.GstCtx, iCrReg, uNewCrX);
16994 break;
16995
16996 case 3:
16997 fIntercept = CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCrX);
16998 break;
16999
17000 case 8:
17001 fIntercept = CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_CR8_LOAD_EXIT);
17002 break;
17003
17004 default:
17005 fIntercept = false;
17006 break;
17007 }
17008 if (fIntercept)
17009 {
17010 VMXVEXITINFO ExitInfo;
17011 RT_ZERO(ExitInfo);
17012 ExitInfo.uReason = pVmxTransient->uExitReason;
17013 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17014 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17015 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17016 }
17017 else
17018 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
17019 break;
17020 }
17021
17022 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
17023 {
17024 /*
17025 * CR0/CR4 reads do not cause VM-exits, the read-shadow is used (subject to masking).
17026 * CR2 reads do not cause a VM-exit.
17027 * CR3 reads cause a VM-exit depending on the "CR3 store exiting" control.
17028 * CR8 reads cause a VM-exit depending on the "CR8 store exiting" control.
17029 */
17030 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
17031 if ( iCrReg == 3
17032 || iCrReg == 8)
17033 {
17034 static const uint32_t s_auCrXReadIntercepts[] = { 0, 0, 0, VMX_PROC_CTLS_CR3_STORE_EXIT, 0,
17035 0, 0, 0, VMX_PROC_CTLS_CR8_STORE_EXIT };
17036 uint32_t const uIntercept = s_auCrXReadIntercepts[iCrReg];
17037 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uIntercept))
17038 {
17039 VMXVEXITINFO ExitInfo;
17040 RT_ZERO(ExitInfo);
17041 ExitInfo.uReason = pVmxTransient->uExitReason;
17042 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17043 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17044 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17045 }
17046 else
17047 {
17048 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
17049 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
17050 }
17051 }
17052 else
17053 {
17054 AssertMsgFailed(("MOV from CR%d VM-exit must not happen\n", iCrReg));
17055 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, iCrReg);
17056 }
17057 break;
17058 }
17059
17060 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
17061 {
17062 PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
17063 Assert(pVmcsNstGst);
17064 uint64_t const uGstHostMask = pVmcsNstGst->u64Cr0Mask.u;
17065 uint64_t const uReadShadow = pVmcsNstGst->u64Cr0ReadShadow.u;
17066 if ( (uGstHostMask & X86_CR0_TS)
17067 && (uReadShadow & X86_CR0_TS))
17068 {
17069 VMXVEXITINFO ExitInfo;
17070 RT_ZERO(ExitInfo);
17071 ExitInfo.uReason = pVmxTransient->uExitReason;
17072 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17073 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17074 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17075 }
17076 else
17077 rcStrict = hmR0VmxExitClts(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr);
17078 break;
17079 }
17080
17081 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
17082 {
17083 RTGCPTR GCPtrEffDst;
17084 uint16_t const uNewMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(pVmxTransient->uExitQual);
17085 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(pVmxTransient->uExitQual);
17086 if (fMemOperand)
17087 {
17088 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
17089 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
17090 }
17091 else
17092 GCPtrEffDst = NIL_RTGCPTR;
17093
17094 if (CPUMIsGuestVmxLmswInterceptSet(&pVCpu->cpum.GstCtx, uNewMsw))
17095 {
17096 VMXVEXITINFO ExitInfo;
17097 RT_ZERO(ExitInfo);
17098 ExitInfo.uReason = pVmxTransient->uExitReason;
17099 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17100 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
17101 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17102 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17103 }
17104 else
17105 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, uNewMsw, GCPtrEffDst);
17106 break;
17107 }
17108
17109 default:
17110 {
17111 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
17112 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
17113 }
17114 }
17115
17116 if (rcStrict == VINF_IEM_RAISED_XCPT)
17117 {
17118 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
17119 rcStrict = VINF_SUCCESS;
17120 }
17121 return rcStrict;
17122}
17123
17124
17125/**
17126 * Nested-guest VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX).
17127 * Conditional VM-exit.
17128 */
17129HMVMX_EXIT_DECL hmR0VmxExitMovDRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17130{
17131 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17132
17133 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MOV_DR_EXIT))
17134 {
17135 hmR0VmxReadExitQualVmcs(pVmxTransient);
17136 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17137
17138 VMXVEXITINFO ExitInfo;
17139 RT_ZERO(ExitInfo);
17140 ExitInfo.uReason = pVmxTransient->uExitReason;
17141 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17142 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17143 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17144 }
17145 return hmR0VmxExitMovDRx(pVCpu, pVmxTransient);
17146}
17147
17148
17149/**
17150 * Nested-guest VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR).
17151 * Conditional VM-exit.
17152 */
17153HMVMX_EXIT_DECL hmR0VmxExitIoInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17154{
17155 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17156
17157 hmR0VmxReadExitQualVmcs(pVmxTransient);
17158
17159 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
17160 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
17161 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
17162
17163 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
17164 uint8_t const cbAccess = s_aIOSizes[uIOSize];
17165 if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
17166 {
17167 /*
17168 * IN/OUT instruction:
17169 * - Provides VM-exit instruction length.
17170 *
17171 * INS/OUTS instruction:
17172 * - Provides VM-exit instruction length.
17173 * - Provides Guest-linear address.
17174 * - Optionally provides VM-exit instruction info (depends on CPU feature).
17175 */
17176 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
17177 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17178
17179 /* Make sure we don't use stale/uninitialized VMX-transient info. below. */
17180 pVmxTransient->ExitInstrInfo.u = 0;
17181 pVmxTransient->uGuestLinearAddr = 0;
17182
17183 bool const fVmxInsOutsInfo = pVM->cpum.ro.GuestFeatures.fVmxInsOutInfo;
17184 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
17185 if (fIOString)
17186 {
17187 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
17188 if (fVmxInsOutsInfo)
17189 {
17190 Assert(RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS)); /* Paranoia. */
17191 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17192 }
17193 }
17194
17195 VMXVEXITINFO ExitInfo;
17196 RT_ZERO(ExitInfo);
17197 ExitInfo.uReason = pVmxTransient->uExitReason;
17198 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17199 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17200 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17201 ExitInfo.u64GuestLinearAddr = pVmxTransient->uGuestLinearAddr;
17202 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17203 }
17204 return hmR0VmxExitIoInstr(pVCpu, pVmxTransient);
17205}
17206
17207
17208/**
17209 * Nested-guest VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
17210 */
17211HMVMX_EXIT_DECL hmR0VmxExitRdmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17212{
17213 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17214
17215 uint32_t fMsrpm;
17216 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
17217 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
17218 else
17219 fMsrpm = VMXMSRPM_EXIT_RD;
17220
17221 if (fMsrpm & VMXMSRPM_EXIT_RD)
17222 {
17223 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17224 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17225 }
17226 return hmR0VmxExitRdmsr(pVCpu, pVmxTransient);
17227}
17228
17229
17230/**
17231 * Nested-guest VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
17232 */
17233HMVMX_EXIT_DECL hmR0VmxExitWrmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17234{
17235 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17236
17237 uint32_t fMsrpm;
17238 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
17239 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvMsrBitmap), pVCpu->cpum.GstCtx.ecx);
17240 else
17241 fMsrpm = VMXMSRPM_EXIT_WR;
17242
17243 if (fMsrpm & VMXMSRPM_EXIT_WR)
17244 {
17245 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17246 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17247 }
17248 return hmR0VmxExitWrmsr(pVCpu, pVmxTransient);
17249}
17250
17251
17252/**
17253 * Nested-guest VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
17254 */
17255HMVMX_EXIT_DECL hmR0VmxExitMwaitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17256{
17257 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17258
17259 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MWAIT_EXIT))
17260 {
17261 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17262 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17263 }
17264 return hmR0VmxExitMwait(pVCpu, pVmxTransient);
17265}
17266
17267
17268/**
17269 * Nested-guest VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional
17270 * VM-exit.
17271 */
17272HMVMX_EXIT_DECL hmR0VmxExitMtfNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17273{
17274 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17275
17276 /** @todo NSTVMX: Should consider debugging nested-guests using VM debugger. */
17277 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
17278 VMXVEXITINFO ExitInfo;
17279 RT_ZERO(ExitInfo);
17280 ExitInfo.uReason = pVmxTransient->uExitReason;
17281 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
17282 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
17283}
17284
17285
17286/**
17287 * Nested-guest VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
17288 */
17289HMVMX_EXIT_DECL hmR0VmxExitMonitorNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17290{
17291 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17292
17293 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MONITOR_EXIT))
17294 {
17295 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17296 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17297 }
17298 return hmR0VmxExitMonitor(pVCpu, pVmxTransient);
17299}
17300
17301
17302/**
17303 * Nested-guest VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
17304 */
17305HMVMX_EXIT_DECL hmR0VmxExitPauseNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17306{
17307 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17308
17309 /** @todo NSTVMX: Think about this more. Does the outer guest need to intercept
17310 * PAUSE when executing a nested-guest? If it does not, we would not need
17311 * to check for the intercepts here. Just call VM-exit... */
17312
17313 /* The CPU would have already performed the necessary CPL checks for PAUSE-loop exiting. */
17314 if ( CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_PAUSE_EXIT)
17315 || CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
17316 {
17317 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17318 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17319 }
17320 return hmR0VmxExitPause(pVCpu, pVmxTransient);
17321}
17322
17323
17324/**
17325 * Nested-guest VM-exit handler for when the TPR value is lowered below the
17326 * specified threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
17327 */
17328HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThresholdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17329{
17330 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17331
17332 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_TPR_SHADOW))
17333 {
17334 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
17335 VMXVEXITINFO ExitInfo;
17336 RT_ZERO(ExitInfo);
17337 ExitInfo.uReason = pVmxTransient->uExitReason;
17338 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
17339 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
17340 }
17341 return hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient);
17342}
17343
17344
17345/**
17346 * Nested-guest VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional
17347 * VM-exit.
17348 */
17349HMVMX_EXIT_DECL hmR0VmxExitApicAccessNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17350{
17351 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17352
17353 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17354 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
17355 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
17356 hmR0VmxReadExitQualVmcs(pVmxTransient);
17357
17358 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
17359
17360 Log4Func(("at offset %#x type=%u\n", VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual),
17361 VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual)));
17362
17363 VMXVEXITINFO ExitInfo;
17364 RT_ZERO(ExitInfo);
17365 ExitInfo.uReason = pVmxTransient->uExitReason;
17366 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17367 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17368
17369 VMXVEXITEVENTINFO ExitEventInfo;
17370 RT_ZERO(ExitEventInfo);
17371 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
17372 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
17373 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
17374}
17375
17376
17377/**
17378 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
17379 * Conditional VM-exit.
17380 */
17381HMVMX_EXIT_DECL hmR0VmxExitApicWriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17382{
17383 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17384
17385 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
17386 hmR0VmxReadExitQualVmcs(pVmxTransient);
17387 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
17388}
17389
17390
17391/**
17392 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
17393 * Conditional VM-exit.
17394 */
17395HMVMX_EXIT_DECL hmR0VmxExitVirtEoiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17396{
17397 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17398
17399 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
17400 hmR0VmxReadExitQualVmcs(pVmxTransient);
17401 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
17402}
17403
17404
17405/**
17406 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
17407 */
17408HMVMX_EXIT_DECL hmR0VmxExitRdtscpNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17409{
17410 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17411
17412 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
17413 {
17414 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
17415 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17416 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17417 }
17418 return hmR0VmxExitRdtscp(pVCpu, pVmxTransient);
17419}
17420
17421
17422/**
17423 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
17424 */
17425HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17426{
17427 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17428
17429 if (CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
17430 {
17431 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17432 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17433 }
17434 return hmR0VmxExitWbinvd(pVCpu, pVmxTransient);
17435}
17436
17437
17438/**
17439 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
17440 */
17441HMVMX_EXIT_DECL hmR0VmxExitInvpcidNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17442{
17443 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17444
17445 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
17446 {
17447 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
17448 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17449 hmR0VmxReadExitQualVmcs(pVmxTransient);
17450 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17451
17452 VMXVEXITINFO ExitInfo;
17453 RT_ZERO(ExitInfo);
17454 ExitInfo.uReason = pVmxTransient->uExitReason;
17455 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17456 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17457 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17458 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17459 }
17460 return hmR0VmxExitInvpcid(pVCpu, pVmxTransient);
17461}
17462
17463
17464/**
17465 * Nested-guest VM-exit handler for invalid-guest state
17466 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
17467 */
17468HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestStateNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17469{
17470 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17471
17472 /*
17473 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
17474 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
17475 * Handle it like it's in an invalid guest state of the outer guest.
17476 *
17477 * When the fast path is implemented, this should be changed to cause the corresponding
17478 * nested-guest VM-exit.
17479 */
17480 return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
17481}
17482
17483
17484/**
17485 * Nested-guest VM-exit handler for instructions that cause VM-exits uncondtionally
17486 * and only provide the instruction length.
17487 *
17488 * Unconditional VM-exit.
17489 */
17490HMVMX_EXIT_DECL hmR0VmxExitInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17491{
17492 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17493
17494#ifdef VBOX_STRICT
17495 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
17496 switch (pVmxTransient->uExitReason)
17497 {
17498 case VMX_EXIT_ENCLS:
17499 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
17500 break;
17501
17502 case VMX_EXIT_VMFUNC:
17503 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_VMFUNC));
17504 break;
17505 }
17506#endif
17507
17508 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17509 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17510}
17511
17512
17513/**
17514 * Nested-guest VM-exit handler for instructions that provide instruction length as
17515 * well as more information.
17516 *
17517 * Unconditional VM-exit.
17518 */
17519HMVMX_EXIT_DECL hmR0VmxExitInstrWithInfoNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17520{
17521 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17522
17523#ifdef VBOX_STRICT
17524 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
17525 switch (pVmxTransient->uExitReason)
17526 {
17527 case VMX_EXIT_GDTR_IDTR_ACCESS:
17528 case VMX_EXIT_LDTR_TR_ACCESS:
17529 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
17530 break;
17531
17532 case VMX_EXIT_RDRAND:
17533 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
17534 break;
17535
17536 case VMX_EXIT_RDSEED:
17537 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
17538 break;
17539
17540 case VMX_EXIT_XSAVES:
17541 case VMX_EXIT_XRSTORS:
17542 /** @todo NSTVMX: Verify XSS-bitmap. */
17543 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
17544 break;
17545
17546 case VMX_EXIT_UMWAIT:
17547 case VMX_EXIT_TPAUSE:
17548 Assert(CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
17549 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
17550 break;
17551 }
17552#endif
17553
17554 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17555 hmR0VmxReadExitQualVmcs(pVmxTransient);
17556 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17557
17558 VMXVEXITINFO ExitInfo;
17559 RT_ZERO(ExitInfo);
17560 ExitInfo.uReason = pVmxTransient->uExitReason;
17561 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17562 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17563 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17564 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17565}
17566
17567/** @} */
17568#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
17569
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