VirtualBox

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

Last change on this file since 92493 was 92394, checked in by vboxsync, 3 years ago

VMM: HM build fix. bugref:10093

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 739.9 KB
Line 
1/* $Id: HMVMXR0.cpp 92394 2021-11-12 10:47:11Z 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_VE_XCPT_INFO_ADDR_FULL,
537 VMX_VMCS64_CTRL_VE_XCPT_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_SPPTP_FULL,
543 VMX_VMCS64_CTRL_SPPTP_HIGH,
544 VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL,
545 VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH,
546 VMX_VMCS64_CTRL_PROC_EXEC3_FULL,
547 VMX_VMCS64_CTRL_PROC_EXEC3_HIGH,
548 VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_FULL,
549 VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_HIGH,
550
551 /* 64-bit read-only data fields. */
552 VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL,
553 VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH,
554
555 /* 64-bit guest-state fields. */
556 VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL,
557 VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH,
558 VMX_VMCS64_GUEST_DEBUGCTL_FULL,
559 VMX_VMCS64_GUEST_DEBUGCTL_HIGH,
560 VMX_VMCS64_GUEST_PAT_FULL,
561 VMX_VMCS64_GUEST_PAT_HIGH,
562 VMX_VMCS64_GUEST_EFER_FULL,
563 VMX_VMCS64_GUEST_EFER_HIGH,
564 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL,
565 VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH,
566 VMX_VMCS64_GUEST_PDPTE0_FULL,
567 VMX_VMCS64_GUEST_PDPTE0_HIGH,
568 VMX_VMCS64_GUEST_PDPTE1_FULL,
569 VMX_VMCS64_GUEST_PDPTE1_HIGH,
570 VMX_VMCS64_GUEST_PDPTE2_FULL,
571 VMX_VMCS64_GUEST_PDPTE2_HIGH,
572 VMX_VMCS64_GUEST_PDPTE3_FULL,
573 VMX_VMCS64_GUEST_PDPTE3_HIGH,
574 VMX_VMCS64_GUEST_BNDCFGS_FULL,
575 VMX_VMCS64_GUEST_BNDCFGS_HIGH,
576 VMX_VMCS64_GUEST_RTIT_CTL_FULL,
577 VMX_VMCS64_GUEST_RTIT_CTL_HIGH,
578 VMX_VMCS64_GUEST_PKRS_FULL,
579 VMX_VMCS64_GUEST_PKRS_HIGH,
580
581 /* 64-bit host-state fields. */
582 VMX_VMCS64_HOST_PAT_FULL,
583 VMX_VMCS64_HOST_PAT_HIGH,
584 VMX_VMCS64_HOST_EFER_FULL,
585 VMX_VMCS64_HOST_EFER_HIGH,
586 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL,
587 VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH,
588 VMX_VMCS64_HOST_PKRS_FULL,
589 VMX_VMCS64_HOST_PKRS_HIGH,
590
591 /* 32-bit control fields. */
592 VMX_VMCS32_CTRL_PIN_EXEC,
593 VMX_VMCS32_CTRL_PROC_EXEC,
594 VMX_VMCS32_CTRL_EXCEPTION_BITMAP,
595 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK,
596 VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH,
597 VMX_VMCS32_CTRL_CR3_TARGET_COUNT,
598 VMX_VMCS32_CTRL_EXIT,
599 VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT,
600 VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT,
601 VMX_VMCS32_CTRL_ENTRY,
602 VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT,
603 VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO,
604 VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE,
605 VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH,
606 VMX_VMCS32_CTRL_TPR_THRESHOLD,
607 VMX_VMCS32_CTRL_PROC_EXEC2,
608 VMX_VMCS32_CTRL_PLE_GAP,
609 VMX_VMCS32_CTRL_PLE_WINDOW,
610
611 /* 32-bits read-only fields. */
612 VMX_VMCS32_RO_VM_INSTR_ERROR,
613 VMX_VMCS32_RO_EXIT_REASON,
614 VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO,
615 VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE,
616 VMX_VMCS32_RO_IDT_VECTORING_INFO,
617 VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE,
618 VMX_VMCS32_RO_EXIT_INSTR_LENGTH,
619 VMX_VMCS32_RO_EXIT_INSTR_INFO,
620
621 /* 32-bit guest-state fields. */
622 VMX_VMCS32_GUEST_ES_LIMIT,
623 VMX_VMCS32_GUEST_CS_LIMIT,
624 VMX_VMCS32_GUEST_SS_LIMIT,
625 VMX_VMCS32_GUEST_DS_LIMIT,
626 VMX_VMCS32_GUEST_FS_LIMIT,
627 VMX_VMCS32_GUEST_GS_LIMIT,
628 VMX_VMCS32_GUEST_LDTR_LIMIT,
629 VMX_VMCS32_GUEST_TR_LIMIT,
630 VMX_VMCS32_GUEST_GDTR_LIMIT,
631 VMX_VMCS32_GUEST_IDTR_LIMIT,
632 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
633 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
634 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
635 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
636 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
637 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS,
638 VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS,
639 VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS,
640 VMX_VMCS32_GUEST_INT_STATE,
641 VMX_VMCS32_GUEST_ACTIVITY_STATE,
642 VMX_VMCS32_GUEST_SMBASE,
643 VMX_VMCS32_GUEST_SYSENTER_CS,
644 VMX_VMCS32_PREEMPT_TIMER_VALUE,
645
646 /* 32-bit host-state fields. */
647 VMX_VMCS32_HOST_SYSENTER_CS,
648
649 /* Natural-width control fields. */
650 VMX_VMCS_CTRL_CR0_MASK,
651 VMX_VMCS_CTRL_CR4_MASK,
652 VMX_VMCS_CTRL_CR0_READ_SHADOW,
653 VMX_VMCS_CTRL_CR4_READ_SHADOW,
654 VMX_VMCS_CTRL_CR3_TARGET_VAL0,
655 VMX_VMCS_CTRL_CR3_TARGET_VAL1,
656 VMX_VMCS_CTRL_CR3_TARGET_VAL2,
657 VMX_VMCS_CTRL_CR3_TARGET_VAL3,
658
659 /* Natural-width read-only data fields. */
660 VMX_VMCS_RO_EXIT_QUALIFICATION,
661 VMX_VMCS_RO_IO_RCX,
662 VMX_VMCS_RO_IO_RSI,
663 VMX_VMCS_RO_IO_RDI,
664 VMX_VMCS_RO_IO_RIP,
665 VMX_VMCS_RO_GUEST_LINEAR_ADDR,
666
667 /* Natural-width guest-state field */
668 VMX_VMCS_GUEST_CR0,
669 VMX_VMCS_GUEST_CR3,
670 VMX_VMCS_GUEST_CR4,
671 VMX_VMCS_GUEST_ES_BASE,
672 VMX_VMCS_GUEST_CS_BASE,
673 VMX_VMCS_GUEST_SS_BASE,
674 VMX_VMCS_GUEST_DS_BASE,
675 VMX_VMCS_GUEST_FS_BASE,
676 VMX_VMCS_GUEST_GS_BASE,
677 VMX_VMCS_GUEST_LDTR_BASE,
678 VMX_VMCS_GUEST_TR_BASE,
679 VMX_VMCS_GUEST_GDTR_BASE,
680 VMX_VMCS_GUEST_IDTR_BASE,
681 VMX_VMCS_GUEST_DR7,
682 VMX_VMCS_GUEST_RSP,
683 VMX_VMCS_GUEST_RIP,
684 VMX_VMCS_GUEST_RFLAGS,
685 VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS,
686 VMX_VMCS_GUEST_SYSENTER_ESP,
687 VMX_VMCS_GUEST_SYSENTER_EIP,
688 VMX_VMCS_GUEST_S_CET,
689 VMX_VMCS_GUEST_SSP,
690 VMX_VMCS_GUEST_INTR_SSP_TABLE_ADDR,
691
692 /* Natural-width host-state fields */
693 VMX_VMCS_HOST_CR0,
694 VMX_VMCS_HOST_CR3,
695 VMX_VMCS_HOST_CR4,
696 VMX_VMCS_HOST_FS_BASE,
697 VMX_VMCS_HOST_GS_BASE,
698 VMX_VMCS_HOST_TR_BASE,
699 VMX_VMCS_HOST_GDTR_BASE,
700 VMX_VMCS_HOST_IDTR_BASE,
701 VMX_VMCS_HOST_SYSENTER_ESP,
702 VMX_VMCS_HOST_SYSENTER_EIP,
703 VMX_VMCS_HOST_RSP,
704 VMX_VMCS_HOST_RIP,
705 VMX_VMCS_HOST_S_CET,
706 VMX_VMCS_HOST_SSP,
707 VMX_VMCS_HOST_INTR_SSP_TABLE_ADDR
708};
709#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
710
711#ifdef VBOX_STRICT
712static const uint32_t g_aVmcsSegBase[] =
713{
714 VMX_VMCS_GUEST_ES_BASE,
715 VMX_VMCS_GUEST_CS_BASE,
716 VMX_VMCS_GUEST_SS_BASE,
717 VMX_VMCS_GUEST_DS_BASE,
718 VMX_VMCS_GUEST_FS_BASE,
719 VMX_VMCS_GUEST_GS_BASE
720};
721static const uint32_t g_aVmcsSegSel[] =
722{
723 VMX_VMCS16_GUEST_ES_SEL,
724 VMX_VMCS16_GUEST_CS_SEL,
725 VMX_VMCS16_GUEST_SS_SEL,
726 VMX_VMCS16_GUEST_DS_SEL,
727 VMX_VMCS16_GUEST_FS_SEL,
728 VMX_VMCS16_GUEST_GS_SEL
729};
730static const uint32_t g_aVmcsSegLimit[] =
731{
732 VMX_VMCS32_GUEST_ES_LIMIT,
733 VMX_VMCS32_GUEST_CS_LIMIT,
734 VMX_VMCS32_GUEST_SS_LIMIT,
735 VMX_VMCS32_GUEST_DS_LIMIT,
736 VMX_VMCS32_GUEST_FS_LIMIT,
737 VMX_VMCS32_GUEST_GS_LIMIT
738};
739static const uint32_t g_aVmcsSegAttr[] =
740{
741 VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS,
742 VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS,
743 VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS,
744 VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS,
745 VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS,
746 VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS
747};
748AssertCompile(RT_ELEMENTS(g_aVmcsSegSel) == X86_SREG_COUNT);
749AssertCompile(RT_ELEMENTS(g_aVmcsSegLimit) == X86_SREG_COUNT);
750AssertCompile(RT_ELEMENTS(g_aVmcsSegBase) == X86_SREG_COUNT);
751AssertCompile(RT_ELEMENTS(g_aVmcsSegAttr) == X86_SREG_COUNT);
752#endif /* VBOX_STRICT */
753
754#ifdef HMVMX_USE_FUNCTION_TABLE
755/**
756 * VMX_EXIT dispatch table.
757 */
758static const struct CLANG11NOTHROWWEIRDNESS { PFNVMXEXITHANDLER pfn; } g_aVMExitHandlers[VMX_EXIT_MAX + 1] =
759{
760 /* 0 VMX_EXIT_XCPT_OR_NMI */ { hmR0VmxExitXcptOrNmi },
761 /* 1 VMX_EXIT_EXT_INT */ { hmR0VmxExitExtInt },
762 /* 2 VMX_EXIT_TRIPLE_FAULT */ { hmR0VmxExitTripleFault },
763 /* 3 VMX_EXIT_INIT_SIGNAL */ { hmR0VmxExitErrUnexpected },
764 /* 4 VMX_EXIT_SIPI */ { hmR0VmxExitErrUnexpected },
765 /* 5 VMX_EXIT_IO_SMI */ { hmR0VmxExitErrUnexpected },
766 /* 6 VMX_EXIT_SMI */ { hmR0VmxExitErrUnexpected },
767 /* 7 VMX_EXIT_INT_WINDOW */ { hmR0VmxExitIntWindow },
768 /* 8 VMX_EXIT_NMI_WINDOW */ { hmR0VmxExitNmiWindow },
769 /* 9 VMX_EXIT_TASK_SWITCH */ { hmR0VmxExitTaskSwitch },
770 /* 10 VMX_EXIT_CPUID */ { hmR0VmxExitCpuid },
771 /* 11 VMX_EXIT_GETSEC */ { hmR0VmxExitGetsec },
772 /* 12 VMX_EXIT_HLT */ { hmR0VmxExitHlt },
773 /* 13 VMX_EXIT_INVD */ { hmR0VmxExitInvd },
774 /* 14 VMX_EXIT_INVLPG */ { hmR0VmxExitInvlpg },
775 /* 15 VMX_EXIT_RDPMC */ { hmR0VmxExitRdpmc },
776 /* 16 VMX_EXIT_RDTSC */ { hmR0VmxExitRdtsc },
777 /* 17 VMX_EXIT_RSM */ { hmR0VmxExitErrUnexpected },
778 /* 18 VMX_EXIT_VMCALL */ { hmR0VmxExitVmcall },
779#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
780 /* 19 VMX_EXIT_VMCLEAR */ { hmR0VmxExitVmclear },
781 /* 20 VMX_EXIT_VMLAUNCH */ { hmR0VmxExitVmlaunch },
782 /* 21 VMX_EXIT_VMPTRLD */ { hmR0VmxExitVmptrld },
783 /* 22 VMX_EXIT_VMPTRST */ { hmR0VmxExitVmptrst },
784 /* 23 VMX_EXIT_VMREAD */ { hmR0VmxExitVmread },
785 /* 24 VMX_EXIT_VMRESUME */ { hmR0VmxExitVmresume },
786 /* 25 VMX_EXIT_VMWRITE */ { hmR0VmxExitVmwrite },
787 /* 26 VMX_EXIT_VMXOFF */ { hmR0VmxExitVmxoff },
788 /* 27 VMX_EXIT_VMXON */ { hmR0VmxExitVmxon },
789#else
790 /* 19 VMX_EXIT_VMCLEAR */ { hmR0VmxExitSetPendingXcptUD },
791 /* 20 VMX_EXIT_VMLAUNCH */ { hmR0VmxExitSetPendingXcptUD },
792 /* 21 VMX_EXIT_VMPTRLD */ { hmR0VmxExitSetPendingXcptUD },
793 /* 22 VMX_EXIT_VMPTRST */ { hmR0VmxExitSetPendingXcptUD },
794 /* 23 VMX_EXIT_VMREAD */ { hmR0VmxExitSetPendingXcptUD },
795 /* 24 VMX_EXIT_VMRESUME */ { hmR0VmxExitSetPendingXcptUD },
796 /* 25 VMX_EXIT_VMWRITE */ { hmR0VmxExitSetPendingXcptUD },
797 /* 26 VMX_EXIT_VMXOFF */ { hmR0VmxExitSetPendingXcptUD },
798 /* 27 VMX_EXIT_VMXON */ { hmR0VmxExitSetPendingXcptUD },
799#endif
800 /* 28 VMX_EXIT_MOV_CRX */ { hmR0VmxExitMovCRx },
801 /* 29 VMX_EXIT_MOV_DRX */ { hmR0VmxExitMovDRx },
802 /* 30 VMX_EXIT_IO_INSTR */ { hmR0VmxExitIoInstr },
803 /* 31 VMX_EXIT_RDMSR */ { hmR0VmxExitRdmsr },
804 /* 32 VMX_EXIT_WRMSR */ { hmR0VmxExitWrmsr },
805 /* 33 VMX_EXIT_ERR_INVALID_GUEST_STATE */ { hmR0VmxExitErrInvalidGuestState },
806 /* 34 VMX_EXIT_ERR_MSR_LOAD */ { hmR0VmxExitErrUnexpected },
807 /* 35 UNDEFINED */ { hmR0VmxExitErrUnexpected },
808 /* 36 VMX_EXIT_MWAIT */ { hmR0VmxExitMwait },
809 /* 37 VMX_EXIT_MTF */ { hmR0VmxExitMtf },
810 /* 38 UNDEFINED */ { hmR0VmxExitErrUnexpected },
811 /* 39 VMX_EXIT_MONITOR */ { hmR0VmxExitMonitor },
812 /* 40 VMX_EXIT_PAUSE */ { hmR0VmxExitPause },
813 /* 41 VMX_EXIT_ERR_MACHINE_CHECK */ { hmR0VmxExitErrUnexpected },
814 /* 42 UNDEFINED */ { hmR0VmxExitErrUnexpected },
815 /* 43 VMX_EXIT_TPR_BELOW_THRESHOLD */ { hmR0VmxExitTprBelowThreshold },
816 /* 44 VMX_EXIT_APIC_ACCESS */ { hmR0VmxExitApicAccess },
817 /* 45 VMX_EXIT_VIRTUALIZED_EOI */ { hmR0VmxExitErrUnexpected },
818 /* 46 VMX_EXIT_GDTR_IDTR_ACCESS */ { hmR0VmxExitErrUnexpected },
819 /* 47 VMX_EXIT_LDTR_TR_ACCESS */ { hmR0VmxExitErrUnexpected },
820 /* 48 VMX_EXIT_EPT_VIOLATION */ { hmR0VmxExitEptViolation },
821 /* 49 VMX_EXIT_EPT_MISCONFIG */ { hmR0VmxExitEptMisconfig },
822 /* 50 VMX_EXIT_INVEPT */ { hmR0VmxExitSetPendingXcptUD },
823 /* 51 VMX_EXIT_RDTSCP */ { hmR0VmxExitRdtscp },
824 /* 52 VMX_EXIT_PREEMPT_TIMER */ { hmR0VmxExitPreemptTimer },
825#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
826 /* 53 VMX_EXIT_INVVPID */ { hmR0VmxExitInvvpid },
827#else
828 /* 53 VMX_EXIT_INVVPID */ { hmR0VmxExitSetPendingXcptUD },
829#endif
830 /* 54 VMX_EXIT_WBINVD */ { hmR0VmxExitWbinvd },
831 /* 55 VMX_EXIT_XSETBV */ { hmR0VmxExitXsetbv },
832 /* 56 VMX_EXIT_APIC_WRITE */ { hmR0VmxExitErrUnexpected },
833 /* 57 VMX_EXIT_RDRAND */ { hmR0VmxExitErrUnexpected },
834 /* 58 VMX_EXIT_INVPCID */ { hmR0VmxExitInvpcid },
835 /* 59 VMX_EXIT_VMFUNC */ { hmR0VmxExitErrUnexpected },
836 /* 60 VMX_EXIT_ENCLS */ { hmR0VmxExitErrUnexpected },
837 /* 61 VMX_EXIT_RDSEED */ { hmR0VmxExitErrUnexpected },
838 /* 62 VMX_EXIT_PML_FULL */ { hmR0VmxExitErrUnexpected },
839 /* 63 VMX_EXIT_XSAVES */ { hmR0VmxExitErrUnexpected },
840 /* 64 VMX_EXIT_XRSTORS */ { hmR0VmxExitErrUnexpected },
841 /* 65 UNDEFINED */ { hmR0VmxExitErrUnexpected },
842 /* 66 VMX_EXIT_SPP_EVENT */ { hmR0VmxExitErrUnexpected },
843 /* 67 VMX_EXIT_UMWAIT */ { hmR0VmxExitErrUnexpected },
844 /* 68 VMX_EXIT_TPAUSE */ { hmR0VmxExitErrUnexpected },
845 /* 69 VMX_EXIT_LOADIWKEY */ { hmR0VmxExitErrUnexpected },
846};
847#endif /* HMVMX_USE_FUNCTION_TABLE */
848
849#if defined(VBOX_STRICT) && defined(LOG_ENABLED)
850static const char * const g_apszVmxInstrErrors[HMVMX_INSTR_ERROR_MAX + 1] =
851{
852 /* 0 */ "(Not Used)",
853 /* 1 */ "VMCALL executed in VMX root operation.",
854 /* 2 */ "VMCLEAR with invalid physical address.",
855 /* 3 */ "VMCLEAR with VMXON pointer.",
856 /* 4 */ "VMLAUNCH with non-clear VMCS.",
857 /* 5 */ "VMRESUME with non-launched VMCS.",
858 /* 6 */ "VMRESUME after VMXOFF",
859 /* 7 */ "VM-entry with invalid control fields.",
860 /* 8 */ "VM-entry with invalid host state fields.",
861 /* 9 */ "VMPTRLD with invalid physical address.",
862 /* 10 */ "VMPTRLD with VMXON pointer.",
863 /* 11 */ "VMPTRLD with incorrect revision identifier.",
864 /* 12 */ "VMREAD/VMWRITE from/to unsupported VMCS component.",
865 /* 13 */ "VMWRITE to read-only VMCS component.",
866 /* 14 */ "(Not Used)",
867 /* 15 */ "VMXON executed in VMX root operation.",
868 /* 16 */ "VM-entry with invalid executive-VMCS pointer.",
869 /* 17 */ "VM-entry with non-launched executing VMCS.",
870 /* 18 */ "VM-entry with executive-VMCS pointer not VMXON pointer.",
871 /* 19 */ "VMCALL with non-clear VMCS.",
872 /* 20 */ "VMCALL with invalid VM-exit control fields.",
873 /* 21 */ "(Not Used)",
874 /* 22 */ "VMCALL with incorrect MSEG revision identifier.",
875 /* 23 */ "VMXOFF under dual monitor treatment of SMIs and SMM.",
876 /* 24 */ "VMCALL with invalid SMM-monitor features.",
877 /* 25 */ "VM-entry with invalid VM-execution control fields in executive VMCS.",
878 /* 26 */ "VM-entry with events blocked by MOV SS.",
879 /* 27 */ "(Not Used)",
880 /* 28 */ "Invalid operand to INVEPT/INVVPID."
881};
882#endif /* VBOX_STRICT && LOG_ENABLED */
883
884
885/**
886 * Checks if the given MSR is part of the lastbranch-from-IP MSR stack.
887 * @returns @c true if it's part of LBR stack, @c false otherwise.
888 *
889 * @param pVM The cross context VM structure.
890 * @param idMsr The MSR.
891 * @param pidxMsr Where to store the index of the MSR in the LBR MSR array.
892 * Optional, can be NULL.
893 *
894 * @remarks Must only be called when LBR is enabled.
895 */
896DECL_FORCE_INLINE(bool) hmR0VmxIsLbrBranchFromMsr(PCVMCC pVM, uint32_t idMsr, uint32_t *pidxMsr)
897{
898 Assert(pVM->hmr0.s.vmx.fLbr);
899 Assert(pVM->hmr0.s.vmx.idLbrFromIpMsrFirst);
900 uint32_t const cLbrStack = pVM->hmr0.s.vmx.idLbrFromIpMsrLast - pVM->hmr0.s.vmx.idLbrFromIpMsrFirst + 1;
901 uint32_t const idxMsr = idMsr - pVM->hmr0.s.vmx.idLbrFromIpMsrFirst;
902 if (idxMsr < cLbrStack)
903 {
904 if (pidxMsr)
905 *pidxMsr = idxMsr;
906 return true;
907 }
908 return false;
909}
910
911
912/**
913 * Checks if the given MSR is part of the lastbranch-to-IP MSR stack.
914 * @returns @c true if it's part of LBR stack, @c false otherwise.
915 *
916 * @param pVM The cross context VM structure.
917 * @param idMsr The MSR.
918 * @param pidxMsr Where to store the index of the MSR in the LBR MSR array.
919 * Optional, can be NULL.
920 *
921 * @remarks Must only be called when LBR is enabled and when lastbranch-to-IP MSRs
922 * are supported by the CPU (see hmR0VmxSetupLbrMsrRange).
923 */
924DECL_FORCE_INLINE(bool) hmR0VmxIsLbrBranchToMsr(PCVMCC pVM, uint32_t idMsr, uint32_t *pidxMsr)
925{
926 Assert(pVM->hmr0.s.vmx.fLbr);
927 if (pVM->hmr0.s.vmx.idLbrToIpMsrFirst)
928 {
929 uint32_t const cLbrStack = pVM->hmr0.s.vmx.idLbrToIpMsrLast - pVM->hmr0.s.vmx.idLbrToIpMsrFirst + 1;
930 uint32_t const idxMsr = idMsr - pVM->hmr0.s.vmx.idLbrToIpMsrFirst;
931 if (idxMsr < cLbrStack)
932 {
933 if (pidxMsr)
934 *pidxMsr = idxMsr;
935 return true;
936 }
937 }
938 return false;
939}
940
941
942/**
943 * Gets the CR0 guest/host mask.
944 *
945 * These bits typically does not change through the lifetime of a VM. Any bit set in
946 * this mask is owned by the host/hypervisor and would cause a VM-exit when modified
947 * by the guest.
948 *
949 * @returns The CR0 guest/host mask.
950 * @param pVCpu The cross context virtual CPU structure.
951 */
952static uint64_t hmR0VmxGetFixedCr0Mask(PCVMCPUCC pVCpu)
953{
954 /*
955 * Modifications to CR0 bits that VT-x ignores saving/restoring (CD, ET, NW) and
956 * to CR0 bits that we require for shadow paging (PG) by the guest must cause VM-exits.
957 *
958 * Furthermore, modifications to any bits that are reserved/unspecified currently
959 * by the Intel spec. must also cause a VM-exit. This prevents unpredictable behavior
960 * when future CPUs specify and use currently reserved/unspecified bits.
961 */
962 /** @todo Avoid intercepting CR0.PE with unrestricted guest execution. Fix PGM
963 * enmGuestMode to be in-sync with the current mode. See @bugref{6398}
964 * and @bugref{6944}. */
965 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
966 return ( X86_CR0_PE
967 | X86_CR0_NE
968 | (pVM->hmr0.s.fNestedPaging ? 0 : X86_CR0_WP)
969 | X86_CR0_PG
970 | VMX_EXIT_HOST_CR0_IGNORE_MASK);
971}
972
973
974/**
975 * Gets the CR4 guest/host mask.
976 *
977 * These bits typically does not change through the lifetime of a VM. Any bit set in
978 * this mask is owned by the host/hypervisor and would cause a VM-exit when modified
979 * by the guest.
980 *
981 * @returns The CR4 guest/host mask.
982 * @param pVCpu The cross context virtual CPU structure.
983 */
984static uint64_t hmR0VmxGetFixedCr4Mask(PCVMCPUCC pVCpu)
985{
986 /*
987 * We construct a mask of all CR4 bits that the guest can modify without causing
988 * a VM-exit. Then invert this mask to obtain all CR4 bits that should cause
989 * a VM-exit when the guest attempts to modify them when executing using
990 * hardware-assisted VMX.
991 *
992 * When a feature is not exposed to the guest (and may be present on the host),
993 * we want to intercept guest modifications to the bit so we can emulate proper
994 * behavior (e.g., #GP).
995 *
996 * Furthermore, only modifications to those bits that don't require immediate
997 * emulation is allowed. For e.g., PCIDE is excluded because the behavior
998 * depends on CR3 which might not always be the guest value while executing
999 * using hardware-assisted VMX.
1000 */
1001 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
1002 bool const fFsGsBase = pVM->cpum.ro.GuestFeatures.fFsGsBase;
1003 bool const fXSaveRstor = pVM->cpum.ro.GuestFeatures.fXSaveRstor;
1004 bool const fFxSaveRstor = pVM->cpum.ro.GuestFeatures.fFxSaveRstor;
1005
1006 /*
1007 * Paranoia.
1008 * Ensure features exposed to the guest are present on the host.
1009 */
1010 Assert(!fFsGsBase || pVM->cpum.ro.HostFeatures.fFsGsBase);
1011 Assert(!fXSaveRstor || pVM->cpum.ro.HostFeatures.fXSaveRstor);
1012 Assert(!fFxSaveRstor || pVM->cpum.ro.HostFeatures.fFxSaveRstor);
1013
1014 uint64_t const fGstMask = ( X86_CR4_PVI
1015 | X86_CR4_TSD
1016 | X86_CR4_DE
1017 | X86_CR4_MCE
1018 | X86_CR4_PCE
1019 | X86_CR4_OSXMMEEXCPT
1020 | (fFsGsBase ? X86_CR4_FSGSBASE : 0)
1021 | (fXSaveRstor ? X86_CR4_OSXSAVE : 0)
1022 | (fFxSaveRstor ? X86_CR4_OSFXSR : 0));
1023 return ~fGstMask;
1024}
1025
1026
1027/**
1028 * Gets the active (in use) VMCS info. object for the specified VCPU.
1029 *
1030 * This is either the guest or nested-guest VMCS info. and need not necessarily
1031 * pertain to the "current" VMCS (in the VMX definition of the term). For instance,
1032 * if the VM-entry failed due to an invalid-guest state, we may have "cleared" the
1033 * current VMCS while returning to ring-3. However, the VMCS info. object for that
1034 * VMCS would still be active and returned here so that we could dump the VMCS
1035 * fields to ring-3 for diagnostics. This function is thus only used to
1036 * distinguish between the nested-guest or guest VMCS.
1037 *
1038 * @returns The active VMCS information.
1039 * @param pVCpu The cross context virtual CPU structure.
1040 *
1041 * @thread EMT.
1042 * @remarks This function may be called with preemption or interrupts disabled!
1043 */
1044DECLINLINE(PVMXVMCSINFO) hmGetVmxActiveVmcsInfo(PVMCPUCC pVCpu)
1045{
1046 if (!pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
1047 return &pVCpu->hmr0.s.vmx.VmcsInfo;
1048 return &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1049}
1050
1051
1052/**
1053 * Returns whether the VM-exit MSR-store area differs from the VM-exit MSR-load
1054 * area.
1055 *
1056 * @returns @c true if it's different, @c false otherwise.
1057 * @param pVmcsInfo The VMCS info. object.
1058 */
1059DECL_FORCE_INLINE(bool) hmR0VmxIsSeparateExitMsrStoreAreaVmcs(PCVMXVMCSINFO pVmcsInfo)
1060{
1061 return RT_BOOL( pVmcsInfo->pvGuestMsrStore != pVmcsInfo->pvGuestMsrLoad
1062 && pVmcsInfo->pvGuestMsrStore);
1063}
1064
1065
1066/**
1067 * Sets the given Processor-based VM-execution controls.
1068 *
1069 * @param pVmxTransient The VMX-transient structure.
1070 * @param uProcCtls The Processor-based VM-execution controls to set.
1071 */
1072static void hmR0VmxSetProcCtlsVmcs(PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
1073{
1074 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1075 if ((pVmcsInfo->u32ProcCtls & uProcCtls) != uProcCtls)
1076 {
1077 pVmcsInfo->u32ProcCtls |= uProcCtls;
1078 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
1079 AssertRC(rc);
1080 }
1081}
1082
1083
1084/**
1085 * Removes the given Processor-based VM-execution controls.
1086 *
1087 * @param pVCpu The cross context virtual CPU structure.
1088 * @param pVmxTransient The VMX-transient structure.
1089 * @param uProcCtls The Processor-based VM-execution controls to remove.
1090 *
1091 * @remarks When executing a nested-guest, this will not remove any of the specified
1092 * controls if the nested hypervisor has set any one of them.
1093 */
1094static void hmR0VmxRemoveProcCtlsVmcs(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
1095{
1096 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1097 if (pVmcsInfo->u32ProcCtls & uProcCtls)
1098 {
1099#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1100 if ( !pVmxTransient->fIsNestedGuest
1101 || !CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uProcCtls))
1102#else
1103 NOREF(pVCpu);
1104 if (!pVmxTransient->fIsNestedGuest)
1105#endif
1106 {
1107 pVmcsInfo->u32ProcCtls &= ~uProcCtls;
1108 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
1109 AssertRC(rc);
1110 }
1111 }
1112}
1113
1114
1115/**
1116 * Sets the TSC offset for the current VMCS.
1117 *
1118 * @param uTscOffset The TSC offset to set.
1119 * @param pVmcsInfo The VMCS info. object.
1120 */
1121static void hmR0VmxSetTscOffsetVmcs(PVMXVMCSINFO pVmcsInfo, uint64_t uTscOffset)
1122{
1123 if (pVmcsInfo->u64TscOffset != uTscOffset)
1124 {
1125 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
1126 AssertRC(rc);
1127 pVmcsInfo->u64TscOffset = uTscOffset;
1128 }
1129}
1130
1131
1132/**
1133 * Adds one or more exceptions to the exception bitmap and commits it to the current
1134 * VMCS.
1135 *
1136 * @param pVmxTransient The VMX-transient structure.
1137 * @param uXcptMask The exception(s) to add.
1138 */
1139static void hmR0VmxAddXcptInterceptMask(PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1140{
1141 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1142 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
1143 if ((uXcptBitmap & uXcptMask) != uXcptMask)
1144 {
1145 uXcptBitmap |= uXcptMask;
1146 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
1147 AssertRC(rc);
1148 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
1149 }
1150}
1151
1152
1153/**
1154 * Adds an exception to the exception bitmap and commits it to the current VMCS.
1155 *
1156 * @param pVmxTransient The VMX-transient structure.
1157 * @param uXcpt The exception to add.
1158 */
1159static void hmR0VmxAddXcptIntercept(PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1160{
1161 Assert(uXcpt <= X86_XCPT_LAST);
1162 hmR0VmxAddXcptInterceptMask(pVmxTransient, RT_BIT_32(uXcpt));
1163}
1164
1165
1166/**
1167 * Remove one or more exceptions from the exception bitmap and commits it to the
1168 * current VMCS.
1169 *
1170 * This takes care of not removing the exception intercept if a nested-guest
1171 * requires the exception to be intercepted.
1172 *
1173 * @returns VBox status code.
1174 * @param pVCpu The cross context virtual CPU structure.
1175 * @param pVmxTransient The VMX-transient structure.
1176 * @param uXcptMask The exception(s) to remove.
1177 */
1178static int hmR0VmxRemoveXcptInterceptMask(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uXcptMask)
1179{
1180 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
1181 uint32_t u32XcptBitmap = pVmcsInfo->u32XcptBitmap;
1182 if (u32XcptBitmap & uXcptMask)
1183 {
1184#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1185 if (!pVmxTransient->fIsNestedGuest)
1186 { /* likely */ }
1187 else
1188 uXcptMask &= ~pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs.u32XcptBitmap;
1189#endif
1190#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
1191 uXcptMask &= ~( RT_BIT(X86_XCPT_BP)
1192 | RT_BIT(X86_XCPT_DE)
1193 | RT_BIT(X86_XCPT_NM)
1194 | RT_BIT(X86_XCPT_TS)
1195 | RT_BIT(X86_XCPT_UD)
1196 | RT_BIT(X86_XCPT_NP)
1197 | RT_BIT(X86_XCPT_SS)
1198 | RT_BIT(X86_XCPT_GP)
1199 | RT_BIT(X86_XCPT_PF)
1200 | RT_BIT(X86_XCPT_MF));
1201#elif defined(HMVMX_ALWAYS_TRAP_PF)
1202 uXcptMask &= ~RT_BIT(X86_XCPT_PF);
1203#endif
1204 if (uXcptMask)
1205 {
1206 /* Validate we are not removing any essential exception intercepts. */
1207 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging || !(uXcptMask & RT_BIT(X86_XCPT_PF)));
1208 NOREF(pVCpu);
1209 Assert(!(uXcptMask & RT_BIT(X86_XCPT_DB)));
1210 Assert(!(uXcptMask & RT_BIT(X86_XCPT_AC)));
1211
1212 /* Remove it from the exception bitmap. */
1213 u32XcptBitmap &= ~uXcptMask;
1214
1215 /* Commit and update the cache if necessary. */
1216 if (pVmcsInfo->u32XcptBitmap != u32XcptBitmap)
1217 {
1218 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
1219 AssertRC(rc);
1220 pVmcsInfo->u32XcptBitmap = u32XcptBitmap;
1221 }
1222 }
1223 }
1224 return VINF_SUCCESS;
1225}
1226
1227
1228/**
1229 * Remove an exceptions from the exception bitmap and commits it to the current
1230 * VMCS.
1231 *
1232 * @returns VBox status code.
1233 * @param pVCpu The cross context virtual CPU structure.
1234 * @param pVmxTransient The VMX-transient structure.
1235 * @param uXcpt The exception to remove.
1236 */
1237static int hmR0VmxRemoveXcptIntercept(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint8_t uXcpt)
1238{
1239 return hmR0VmxRemoveXcptInterceptMask(pVCpu, pVmxTransient, RT_BIT(uXcpt));
1240}
1241
1242
1243/**
1244 * Loads the VMCS specified by the VMCS info. object.
1245 *
1246 * @returns VBox status code.
1247 * @param pVmcsInfo The VMCS info. object.
1248 *
1249 * @remarks Can be called with interrupts disabled.
1250 */
1251static int hmR0VmxLoadVmcs(PVMXVMCSINFO pVmcsInfo)
1252{
1253 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1254 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1255
1256 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysVmcs);
1257 if (RT_SUCCESS(rc))
1258 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1259 return rc;
1260}
1261
1262
1263/**
1264 * Clears the VMCS specified by the VMCS info. object.
1265 *
1266 * @returns VBox status code.
1267 * @param pVmcsInfo The VMCS info. object.
1268 *
1269 * @remarks Can be called with interrupts disabled.
1270 */
1271static int hmR0VmxClearVmcs(PVMXVMCSINFO pVmcsInfo)
1272{
1273 Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
1274 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1275
1276 int rc = VMXClearVmcs(pVmcsInfo->HCPhysVmcs);
1277 if (RT_SUCCESS(rc))
1278 pVmcsInfo->fVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1279 return rc;
1280}
1281
1282
1283#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1284/**
1285 * Loads the shadow VMCS specified by the VMCS info. object.
1286 *
1287 * @returns VBox status code.
1288 * @param pVmcsInfo The VMCS info. object.
1289 *
1290 * @remarks Can be called with interrupts disabled.
1291 */
1292static int hmR0VmxLoadShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1293{
1294 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1295 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1296
1297 int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
1298 if (RT_SUCCESS(rc))
1299 pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
1300 return rc;
1301}
1302
1303
1304/**
1305 * Clears the shadow VMCS specified by the VMCS info. object.
1306 *
1307 * @returns VBox status code.
1308 * @param pVmcsInfo The VMCS info. object.
1309 *
1310 * @remarks Can be called with interrupts disabled.
1311 */
1312static int hmR0VmxClearShadowVmcs(PVMXVMCSINFO pVmcsInfo)
1313{
1314 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1315 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
1316
1317 int rc = VMXClearVmcs(pVmcsInfo->HCPhysShadowVmcs);
1318 if (RT_SUCCESS(rc))
1319 pVmcsInfo->fShadowVmcsState = VMX_V_VMCS_LAUNCH_STATE_CLEAR;
1320 return rc;
1321}
1322
1323
1324/**
1325 * Switches from and to the specified VMCSes.
1326 *
1327 * @returns VBox status code.
1328 * @param pVmcsInfoFrom The VMCS info. object we are switching from.
1329 * @param pVmcsInfoTo The VMCS info. object we are switching to.
1330 *
1331 * @remarks Called with interrupts disabled.
1332 */
1333static int hmR0VmxSwitchVmcs(PVMXVMCSINFO pVmcsInfoFrom, PVMXVMCSINFO pVmcsInfoTo)
1334{
1335 /*
1336 * Clear the VMCS we are switching out if it has not already been cleared.
1337 * This will sync any CPU internal data back to the VMCS.
1338 */
1339 if (pVmcsInfoFrom->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1340 {
1341 int rc = hmR0VmxClearVmcs(pVmcsInfoFrom);
1342 if (RT_SUCCESS(rc))
1343 {
1344 /*
1345 * The shadow VMCS, if any, would not be active at this point since we
1346 * would have cleared it while importing the virtual hardware-virtualization
1347 * state as part the VMLAUNCH/VMRESUME VM-exit. Hence, there's no need to
1348 * clear the shadow VMCS here, just assert for safety.
1349 */
1350 Assert(!pVmcsInfoFrom->pvShadowVmcs || pVmcsInfoFrom->fShadowVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR);
1351 }
1352 else
1353 return rc;
1354 }
1355
1356 /*
1357 * Clear the VMCS we are switching to if it has not already been cleared.
1358 * This will initialize the VMCS launch state to "clear" required for loading it.
1359 *
1360 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
1361 */
1362 if (pVmcsInfoTo->fVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
1363 {
1364 int rc = hmR0VmxClearVmcs(pVmcsInfoTo);
1365 if (RT_SUCCESS(rc))
1366 { /* likely */ }
1367 else
1368 return rc;
1369 }
1370
1371 /*
1372 * Finally, load the VMCS we are switching to.
1373 */
1374 return hmR0VmxLoadVmcs(pVmcsInfoTo);
1375}
1376
1377
1378/**
1379 * Switches between the guest VMCS and the nested-guest VMCS as specified by the
1380 * caller.
1381 *
1382 * @returns VBox status code.
1383 * @param pVCpu The cross context virtual CPU structure.
1384 * @param fSwitchToNstGstVmcs Whether to switch to the nested-guest VMCS (pass
1385 * true) or guest VMCS (pass false).
1386 */
1387static int hmR0VmxSwitchToGstOrNstGstVmcs(PVMCPUCC pVCpu, bool fSwitchToNstGstVmcs)
1388{
1389 /* Ensure we have synced everything from the guest-CPU context to the VMCS before switching. */
1390 HMVMX_CPUMCTX_ASSERT(pVCpu, HMVMX_CPUMCTX_EXTRN_ALL);
1391
1392 PVMXVMCSINFO pVmcsInfoFrom;
1393 PVMXVMCSINFO pVmcsInfoTo;
1394 if (fSwitchToNstGstVmcs)
1395 {
1396 pVmcsInfoFrom = &pVCpu->hmr0.s.vmx.VmcsInfo;
1397 pVmcsInfoTo = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1398 }
1399 else
1400 {
1401 pVmcsInfoFrom = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
1402 pVmcsInfoTo = &pVCpu->hmr0.s.vmx.VmcsInfo;
1403 }
1404
1405 /*
1406 * Disable interrupts to prevent being preempted while we switch the current VMCS as the
1407 * preemption hook code path acquires the current VMCS.
1408 */
1409 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1410
1411 int rc = hmR0VmxSwitchVmcs(pVmcsInfoFrom, pVmcsInfoTo);
1412 if (RT_SUCCESS(rc))
1413 {
1414 pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs = fSwitchToNstGstVmcs;
1415 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcsCopyForRing3 = fSwitchToNstGstVmcs;
1416
1417 /*
1418 * If we are switching to a VMCS that was executed on a different host CPU or was
1419 * never executed before, flag that we need to export the host state before executing
1420 * guest/nested-guest code using hardware-assisted VMX.
1421 *
1422 * This could probably be done in a preemptible context since the preemption hook
1423 * will flag the necessary change in host context. However, since preemption is
1424 * already disabled and to avoid making assumptions about host specific code in
1425 * RTMpCpuId when called with preemption enabled, we'll do this while preemption is
1426 * disabled.
1427 */
1428 if (pVmcsInfoTo->idHostCpuState == RTMpCpuId())
1429 { /* likely */ }
1430 else
1431 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE);
1432
1433 ASMSetFlags(fEFlags);
1434
1435 /*
1436 * We use a different VM-exit MSR-store areas for the guest and nested-guest. Hence,
1437 * flag that we need to update the host MSR values there. Even if we decide in the
1438 * future to share the VM-exit MSR-store area page between the guest and nested-guest,
1439 * if its content differs, we would have to update the host MSRs anyway.
1440 */
1441 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
1442 }
1443 else
1444 ASMSetFlags(fEFlags);
1445 return rc;
1446}
1447#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
1448
1449
1450/**
1451 * Updates the VM's last error record.
1452 *
1453 * If there was a VMX instruction error, reads the error data from the VMCS and
1454 * updates VCPU's last error record as well.
1455 *
1456 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1457 * Can be NULL if @a rc is not VERR_VMX_UNABLE_TO_START_VM or
1458 * VERR_VMX_INVALID_VMCS_FIELD.
1459 * @param rc The error code.
1460 */
1461static void hmR0VmxUpdateErrorRecord(PVMCPUCC pVCpu, int rc)
1462{
1463 if ( rc == VERR_VMX_INVALID_VMCS_FIELD
1464 || rc == VERR_VMX_UNABLE_TO_START_VM)
1465 {
1466 AssertPtrReturnVoid(pVCpu);
1467 VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
1468 }
1469 pVCpu->CTX_SUFF(pVM)->hm.s.ForR3.rcInit = rc;
1470}
1471
1472
1473#ifdef VBOX_STRICT
1474/**
1475 * Reads the VM-entry interruption-information field from the VMCS into the VMX
1476 * transient structure.
1477 *
1478 * @param pVmxTransient The VMX-transient structure.
1479 */
1480DECLINLINE(void) hmR0VmxReadEntryIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1481{
1482 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &pVmxTransient->uEntryIntInfo);
1483 AssertRC(rc);
1484}
1485
1486
1487/**
1488 * Reads the VM-entry exception error code field from the VMCS into
1489 * the VMX transient structure.
1490 *
1491 * @param pVmxTransient The VMX-transient structure.
1492 */
1493DECLINLINE(void) hmR0VmxReadEntryXcptErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1494{
1495 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
1496 AssertRC(rc);
1497}
1498
1499
1500/**
1501 * Reads the VM-entry exception error code field from the VMCS into
1502 * the VMX transient structure.
1503 *
1504 * @param pVmxTransient The VMX-transient structure.
1505 */
1506DECLINLINE(void) hmR0VmxReadEntryInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1507{
1508 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, &pVmxTransient->cbEntryInstr);
1509 AssertRC(rc);
1510}
1511#endif /* VBOX_STRICT */
1512
1513
1514/**
1515 * Reads the VM-exit interruption-information field from the VMCS into the VMX
1516 * transient structure.
1517 *
1518 * @param pVmxTransient The VMX-transient structure.
1519 */
1520DECLINLINE(void) hmR0VmxReadExitIntInfoVmcs(PVMXTRANSIENT pVmxTransient)
1521{
1522 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_INFO))
1523 {
1524 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1525 AssertRC(rc);
1526 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_INFO;
1527 }
1528}
1529
1530
1531/**
1532 * Reads the VM-exit interruption error code from the VMCS into the VMX
1533 * transient structure.
1534 *
1535 * @param pVmxTransient The VMX-transient structure.
1536 */
1537DECLINLINE(void) hmR0VmxReadExitIntErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1538{
1539 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE))
1540 {
1541 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1542 AssertRC(rc);
1543 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE;
1544 }
1545}
1546
1547
1548/**
1549 * Reads the VM-exit instruction length field from the VMCS into the VMX
1550 * transient structure.
1551 *
1552 * @param pVmxTransient The VMX-transient structure.
1553 */
1554DECLINLINE(void) hmR0VmxReadExitInstrLenVmcs(PVMXTRANSIENT pVmxTransient)
1555{
1556 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_LEN))
1557 {
1558 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1559 AssertRC(rc);
1560 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_LEN;
1561 }
1562}
1563
1564
1565/**
1566 * Reads the VM-exit instruction-information field from the VMCS into
1567 * the VMX transient structure.
1568 *
1569 * @param pVmxTransient The VMX-transient structure.
1570 */
1571DECLINLINE(void) hmR0VmxReadExitInstrInfoVmcs(PVMXTRANSIENT pVmxTransient)
1572{
1573 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_INSTR_INFO))
1574 {
1575 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1576 AssertRC(rc);
1577 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_INSTR_INFO;
1578 }
1579}
1580
1581
1582/**
1583 * Reads the Exit Qualification from the VMCS into the VMX transient structure.
1584 *
1585 * @param pVmxTransient The VMX-transient structure.
1586 */
1587DECLINLINE(void) hmR0VmxReadExitQualVmcs(PVMXTRANSIENT pVmxTransient)
1588{
1589 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_EXIT_QUALIFICATION))
1590 {
1591 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1592 AssertRC(rc);
1593 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION;
1594 }
1595}
1596
1597
1598/**
1599 * Reads the Guest-linear address from the VMCS into the VMX transient structure.
1600 *
1601 * @param pVmxTransient The VMX-transient structure.
1602 */
1603DECLINLINE(void) hmR0VmxReadGuestLinearAddrVmcs(PVMXTRANSIENT pVmxTransient)
1604{
1605 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_LINEAR_ADDR))
1606 {
1607 int rc = VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1608 AssertRC(rc);
1609 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_LINEAR_ADDR;
1610 }
1611}
1612
1613
1614/**
1615 * Reads the Guest-physical address from the VMCS into the VMX transient structure.
1616 *
1617 * @param pVmxTransient The VMX-transient structure.
1618 */
1619DECLINLINE(void) hmR0VmxReadGuestPhysicalAddrVmcs(PVMXTRANSIENT pVmxTransient)
1620{
1621 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PHYSICAL_ADDR))
1622 {
1623 int rc = VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1624 AssertRC(rc);
1625 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PHYSICAL_ADDR;
1626 }
1627}
1628
1629#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1630/**
1631 * Reads the Guest pending-debug exceptions from the VMCS into the VMX transient
1632 * structure.
1633 *
1634 * @param pVmxTransient The VMX-transient structure.
1635 */
1636DECLINLINE(void) hmR0VmxReadGuestPendingDbgXctps(PVMXTRANSIENT pVmxTransient)
1637{
1638 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_GUEST_PENDING_DBG_XCPTS))
1639 {
1640 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &pVmxTransient->uGuestPendingDbgXcpts);
1641 AssertRC(rc);
1642 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_GUEST_PENDING_DBG_XCPTS;
1643 }
1644}
1645#endif
1646
1647/**
1648 * Reads the IDT-vectoring information field from the VMCS into the VMX
1649 * transient structure.
1650 *
1651 * @param pVmxTransient The VMX-transient structure.
1652 *
1653 * @remarks No-long-jump zone!!!
1654 */
1655DECLINLINE(void) hmR0VmxReadIdtVectoringInfoVmcs(PVMXTRANSIENT pVmxTransient)
1656{
1657 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_INFO))
1658 {
1659 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1660 AssertRC(rc);
1661 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_INFO;
1662 }
1663}
1664
1665
1666/**
1667 * Reads the IDT-vectoring error code from the VMCS into the VMX
1668 * transient structure.
1669 *
1670 * @param pVmxTransient The VMX-transient structure.
1671 */
1672DECLINLINE(void) hmR0VmxReadIdtVectoringErrorCodeVmcs(PVMXTRANSIENT pVmxTransient)
1673{
1674 if (!(pVmxTransient->fVmcsFieldsRead & HMVMX_READ_IDT_VECTORING_ERROR_CODE))
1675 {
1676 int rc = VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1677 AssertRC(rc);
1678 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_IDT_VECTORING_ERROR_CODE;
1679 }
1680}
1681
1682#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
1683/**
1684 * Reads all relevant read-only VMCS fields into the VMX transient structure.
1685 *
1686 * @param pVmxTransient The VMX-transient structure.
1687 */
1688static void hmR0VmxReadAllRoFieldsVmcs(PVMXTRANSIENT pVmxTransient)
1689{
1690 int rc = VMXReadVmcsNw(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQual);
1691 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &pVmxTransient->cbExitInstr);
1692 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO, &pVmxTransient->ExitInstrInfo.u);
1693 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO, &pVmxTransient->uIdtVectoringInfo);
1694 rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE, &pVmxTransient->uIdtVectoringErrorCode);
1695 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &pVmxTransient->uExitIntInfo);
1696 rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
1697 rc |= VMXReadVmcsNw(VMX_VMCS_RO_GUEST_LINEAR_ADDR, &pVmxTransient->uGuestLinearAddr);
1698 rc |= VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &pVmxTransient->uGuestPhysicalAddr);
1699 AssertRC(rc);
1700 pVmxTransient->fVmcsFieldsRead |= HMVMX_READ_EXIT_QUALIFICATION
1701 | HMVMX_READ_EXIT_INSTR_LEN
1702 | HMVMX_READ_EXIT_INSTR_INFO
1703 | HMVMX_READ_IDT_VECTORING_INFO
1704 | HMVMX_READ_IDT_VECTORING_ERROR_CODE
1705 | HMVMX_READ_EXIT_INTERRUPTION_INFO
1706 | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE
1707 | HMVMX_READ_GUEST_LINEAR_ADDR
1708 | HMVMX_READ_GUEST_PHYSICAL_ADDR;
1709}
1710#endif
1711
1712/**
1713 * Enters VMX root mode operation on the current CPU.
1714 *
1715 * @returns VBox status code.
1716 * @param pHostCpu The HM physical-CPU structure.
1717 * @param pVM The cross context VM structure. Can be
1718 * NULL, after a resume.
1719 * @param HCPhysCpuPage Physical address of the VMXON region.
1720 * @param pvCpuPage Pointer to the VMXON region.
1721 */
1722static int hmR0VmxEnterRootMode(PHMPHYSCPU pHostCpu, PVMCC pVM, RTHCPHYS HCPhysCpuPage, void *pvCpuPage)
1723{
1724 Assert(pHostCpu);
1725 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
1726 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
1727 Assert(pvCpuPage);
1728 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1729
1730 if (pVM)
1731 {
1732 /* Write the VMCS revision identifier to the VMXON region. */
1733 *(uint32_t *)pvCpuPage = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
1734 }
1735
1736 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with CR4. */
1737 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1738
1739 /* Enable the VMX bit in CR4 if necessary. */
1740 RTCCUINTREG const uOldCr4 = SUPR0ChangeCR4(X86_CR4_VMXE, RTCCUINTREG_MAX);
1741
1742 /* Record whether VMXE was already prior to us enabling it above. */
1743 pHostCpu->fVmxeAlreadyEnabled = RT_BOOL(uOldCr4 & X86_CR4_VMXE);
1744
1745 /* Enter VMX root mode. */
1746 int rc = VMXEnable(HCPhysCpuPage);
1747 if (RT_FAILURE(rc))
1748 {
1749 /* Restore CR4.VMXE if it was not set prior to our attempt to set it above. */
1750 if (!pHostCpu->fVmxeAlreadyEnabled)
1751 SUPR0ChangeCR4(0 /* fOrMask */, ~(uint64_t)X86_CR4_VMXE);
1752
1753 if (pVM)
1754 pVM->hm.s.ForR3.vmx.HCPhysVmxEnableError = HCPhysCpuPage;
1755 }
1756
1757 /* Restore interrupts. */
1758 ASMSetFlags(fEFlags);
1759 return rc;
1760}
1761
1762
1763/**
1764 * Exits VMX root mode operation on the current CPU.
1765 *
1766 * @returns VBox status code.
1767 * @param pHostCpu The HM physical-CPU structure.
1768 */
1769static int hmR0VmxLeaveRootMode(PHMPHYSCPU pHostCpu)
1770{
1771 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1772
1773 /* Paranoid: Disable interrupts as, in theory, interrupts handlers might mess with CR4. */
1774 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
1775
1776 /* If we're for some reason not in VMX root mode, then don't leave it. */
1777 RTCCUINTREG const uHostCr4 = ASMGetCR4();
1778
1779 int rc;
1780 if (uHostCr4 & X86_CR4_VMXE)
1781 {
1782 /* Exit VMX root mode and clear the VMX bit in CR4. */
1783 VMXDisable();
1784
1785 /* Clear CR4.VMXE only if it was clear prior to use setting it. */
1786 if (!pHostCpu->fVmxeAlreadyEnabled)
1787 SUPR0ChangeCR4(0 /* fOrMask */, ~(uint64_t)X86_CR4_VMXE);
1788
1789 rc = VINF_SUCCESS;
1790 }
1791 else
1792 rc = VERR_VMX_NOT_IN_VMX_ROOT_MODE;
1793
1794 /* Restore interrupts. */
1795 ASMSetFlags(fEFlags);
1796 return rc;
1797}
1798
1799
1800/**
1801 * Allocates pages specified as specified by an array of VMX page allocation info
1802 * objects.
1803 *
1804 * The pages contents are zero'd after allocation.
1805 *
1806 * @returns VBox status code.
1807 * @param phMemObj Where to return the handle to the allocation.
1808 * @param paAllocInfo The pointer to the first element of the VMX
1809 * page-allocation info object array.
1810 * @param cEntries The number of elements in the @a paAllocInfo array.
1811 */
1812static int hmR0VmxPagesAllocZ(PRTR0MEMOBJ phMemObj, PVMXPAGEALLOCINFO paAllocInfo, uint32_t cEntries)
1813{
1814 *phMemObj = NIL_RTR0MEMOBJ;
1815
1816 /* Figure out how many pages to allocate. */
1817 uint32_t cPages = 0;
1818 for (uint32_t iPage = 0; iPage < cEntries; iPage++)
1819 cPages += !!paAllocInfo[iPage].fValid;
1820
1821 /* Allocate the pages. */
1822 if (cPages)
1823 {
1824 size_t const cbPages = cPages << PAGE_SHIFT;
1825 int rc = RTR0MemObjAllocPage(phMemObj, cbPages, false /* fExecutable */);
1826 if (RT_FAILURE(rc))
1827 return rc;
1828
1829 /* Zero the contents and assign each page to the corresponding VMX page-allocation entry. */
1830 void *pvFirstPage = RTR0MemObjAddress(*phMemObj);
1831 RT_BZERO(pvFirstPage, cbPages);
1832
1833 uint32_t iPage = 0;
1834 for (uint32_t i = 0; i < cEntries; i++)
1835 if (paAllocInfo[i].fValid)
1836 {
1837 RTHCPHYS const HCPhysPage = RTR0MemObjGetPagePhysAddr(*phMemObj, iPage);
1838 void *pvPage = (void *)((uintptr_t)pvFirstPage + (iPage << X86_PAGE_4K_SHIFT));
1839 Assert(HCPhysPage && HCPhysPage != NIL_RTHCPHYS);
1840 AssertPtr(pvPage);
1841
1842 Assert(paAllocInfo[iPage].pHCPhys);
1843 Assert(paAllocInfo[iPage].ppVirt);
1844 *paAllocInfo[iPage].pHCPhys = HCPhysPage;
1845 *paAllocInfo[iPage].ppVirt = pvPage;
1846
1847 /* Move to next page. */
1848 ++iPage;
1849 }
1850
1851 /* Make sure all valid (requested) pages have been assigned. */
1852 Assert(iPage == cPages);
1853 }
1854 return VINF_SUCCESS;
1855}
1856
1857
1858/**
1859 * Frees pages allocated using hmR0VmxPagesAllocZ.
1860 *
1861 * @param phMemObj Pointer to the memory object handle. Will be set to
1862 * NIL.
1863 */
1864DECL_FORCE_INLINE(void) hmR0VmxPagesFree(PRTR0MEMOBJ phMemObj)
1865{
1866 /* We can cleanup wholesale since it's all one allocation. */
1867 if (*phMemObj != NIL_RTR0MEMOBJ)
1868 {
1869 RTR0MemObjFree(*phMemObj, true /* fFreeMappings */);
1870 *phMemObj = NIL_RTR0MEMOBJ;
1871 }
1872}
1873
1874
1875/**
1876 * Initializes a VMCS info. object.
1877 *
1878 * @param pVmcsInfo The VMCS info. object.
1879 * @param pVmcsInfoShared The VMCS info. object shared with ring-3.
1880 */
1881static void hmR0VmxVmcsInfoInit(PVMXVMCSINFO pVmcsInfo, PVMXVMCSINFOSHARED pVmcsInfoShared)
1882{
1883 RT_ZERO(*pVmcsInfo);
1884 RT_ZERO(*pVmcsInfoShared);
1885
1886 pVmcsInfo->pShared = pVmcsInfoShared;
1887 Assert(pVmcsInfo->hMemObj == NIL_RTR0MEMOBJ);
1888 pVmcsInfo->HCPhysVmcs = NIL_RTHCPHYS;
1889 pVmcsInfo->HCPhysShadowVmcs = NIL_RTHCPHYS;
1890 pVmcsInfo->HCPhysMsrBitmap = NIL_RTHCPHYS;
1891 pVmcsInfo->HCPhysGuestMsrLoad = NIL_RTHCPHYS;
1892 pVmcsInfo->HCPhysGuestMsrStore = NIL_RTHCPHYS;
1893 pVmcsInfo->HCPhysHostMsrLoad = NIL_RTHCPHYS;
1894 pVmcsInfo->HCPhysVirtApic = NIL_RTHCPHYS;
1895 pVmcsInfo->HCPhysEPTP = NIL_RTHCPHYS;
1896 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
1897 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
1898 pVmcsInfo->idHostCpuExec = NIL_RTCPUID;
1899}
1900
1901
1902/**
1903 * Frees the VT-x structures for a VMCS info. object.
1904 *
1905 * @param pVmcsInfo The VMCS info. object.
1906 * @param pVmcsInfoShared The VMCS info. object shared with ring-3.
1907 */
1908static void hmR0VmxVmcsInfoFree(PVMXVMCSINFO pVmcsInfo, PVMXVMCSINFOSHARED pVmcsInfoShared)
1909{
1910 hmR0VmxPagesFree(&pVmcsInfo->hMemObj);
1911 hmR0VmxVmcsInfoInit(pVmcsInfo, pVmcsInfoShared);
1912}
1913
1914
1915/**
1916 * Allocates the VT-x structures for a VMCS info. object.
1917 *
1918 * @returns VBox status code.
1919 * @param pVCpu The cross context virtual CPU structure.
1920 * @param pVmcsInfo The VMCS info. object.
1921 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
1922 *
1923 * @remarks The caller is expected to take care of any and all allocation failures.
1924 * This function will not perform any cleanup for failures half-way
1925 * through.
1926 */
1927static int hmR0VmxAllocVmcsInfo(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
1928{
1929 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
1930
1931 bool const fMsrBitmaps = RT_BOOL(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS);
1932 bool const fShadowVmcs = !fIsNstGstVmcs ? pVM->hmr0.s.vmx.fUseVmcsShadowing : pVM->cpum.ro.GuestFeatures.fVmxVmcsShadowing;
1933 Assert(!pVM->cpum.ro.GuestFeatures.fVmxVmcsShadowing); /* VMCS shadowing is not yet exposed to the guest. */
1934 VMXPAGEALLOCINFO aAllocInfo[] =
1935 {
1936 { true, 0 /* Unused */, &pVmcsInfo->HCPhysVmcs, &pVmcsInfo->pvVmcs },
1937 { true, 0 /* Unused */, &pVmcsInfo->HCPhysGuestMsrLoad, &pVmcsInfo->pvGuestMsrLoad },
1938 { true, 0 /* Unused */, &pVmcsInfo->HCPhysHostMsrLoad, &pVmcsInfo->pvHostMsrLoad },
1939 { fMsrBitmaps, 0 /* Unused */, &pVmcsInfo->HCPhysMsrBitmap, &pVmcsInfo->pvMsrBitmap },
1940 { fShadowVmcs, 0 /* Unused */, &pVmcsInfo->HCPhysShadowVmcs, &pVmcsInfo->pvShadowVmcs },
1941 };
1942
1943 int rc = hmR0VmxPagesAllocZ(&pVmcsInfo->hMemObj, &aAllocInfo[0], RT_ELEMENTS(aAllocInfo));
1944 if (RT_FAILURE(rc))
1945 return rc;
1946
1947 /*
1948 * We use the same page for VM-entry MSR-load and VM-exit MSR store areas.
1949 * Because they contain a symmetric list of guest MSRs to load on VM-entry and store on VM-exit.
1950 */
1951 AssertCompile(RT_ELEMENTS(aAllocInfo) > 0);
1952 Assert(pVmcsInfo->HCPhysGuestMsrLoad != NIL_RTHCPHYS);
1953 pVmcsInfo->pvGuestMsrStore = pVmcsInfo->pvGuestMsrLoad;
1954 pVmcsInfo->HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrLoad;
1955
1956 /*
1957 * Get the virtual-APIC page rather than allocating them again.
1958 */
1959 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW)
1960 {
1961 if (!fIsNstGstVmcs)
1962 {
1963 if (PDMHasApic(pVM))
1964 {
1965 rc = APICGetApicPageForCpu(pVCpu, &pVmcsInfo->HCPhysVirtApic, (PRTR0PTR)&pVmcsInfo->pbVirtApic, NULL /*pR3Ptr*/);
1966 if (RT_FAILURE(rc))
1967 return rc;
1968 Assert(pVmcsInfo->pbVirtApic);
1969 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1970 }
1971 }
1972 else
1973 {
1974 pVmcsInfo->pbVirtApic = &pVCpu->cpum.GstCtx.hwvirt.vmx.abVirtApicPage[0];
1975 pVmcsInfo->HCPhysVirtApic = GVMMR0ConvertGVMPtr2HCPhys(pVM, pVmcsInfo->pbVirtApic);
1976 Assert(pVmcsInfo->HCPhysVirtApic && pVmcsInfo->HCPhysVirtApic != NIL_RTHCPHYS);
1977 }
1978 }
1979
1980 return VINF_SUCCESS;
1981}
1982
1983
1984/**
1985 * Free all VT-x structures for the VM.
1986 *
1987 * @returns IPRT status code.
1988 * @param pVM The cross context VM structure.
1989 */
1990static void hmR0VmxStructsFree(PVMCC pVM)
1991{
1992 hmR0VmxPagesFree(&pVM->hmr0.s.vmx.hMemObj);
1993#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
1994 if (pVM->hmr0.s.vmx.fUseVmcsShadowing)
1995 {
1996 RTMemFree(pVM->hmr0.s.vmx.paShadowVmcsFields);
1997 pVM->hmr0.s.vmx.paShadowVmcsFields = NULL;
1998 RTMemFree(pVM->hmr0.s.vmx.paShadowVmcsRoFields);
1999 pVM->hmr0.s.vmx.paShadowVmcsRoFields = NULL;
2000 }
2001#endif
2002
2003 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
2004 {
2005 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2006 hmR0VmxVmcsInfoFree(&pVCpu->hmr0.s.vmx.VmcsInfo, &pVCpu->hm.s.vmx.VmcsInfo);
2007#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2008 if (pVM->cpum.ro.GuestFeatures.fVmx)
2009 hmR0VmxVmcsInfoFree(&pVCpu->hmr0.s.vmx.VmcsInfoNstGst, &pVCpu->hm.s.vmx.VmcsInfoNstGst);
2010#endif
2011 }
2012}
2013
2014
2015/**
2016 * Allocate all VT-x structures for the VM.
2017 *
2018 * @returns IPRT status code.
2019 * @param pVM The cross context VM structure.
2020 *
2021 * @remarks This functions will cleanup on memory allocation failures.
2022 */
2023static int hmR0VmxStructsAlloc(PVMCC pVM)
2024{
2025 /*
2026 * Sanity check the VMCS size reported by the CPU as we assume 4KB allocations.
2027 * The VMCS size cannot be more than 4096 bytes.
2028 *
2029 * See Intel spec. Appendix A.1 "Basic VMX Information".
2030 */
2031 uint32_t const cbVmcs = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_SIZE);
2032 if (cbVmcs <= X86_PAGE_4K_SIZE)
2033 { /* likely */ }
2034 else
2035 {
2036 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_INVALID_VMCS_SIZE;
2037 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2038 }
2039
2040 /*
2041 * Allocate per-VM VT-x structures.
2042 */
2043 bool const fVirtApicAccess = RT_BOOL(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
2044 bool const fUseVmcsShadowing = pVM->hmr0.s.vmx.fUseVmcsShadowing;
2045 VMXPAGEALLOCINFO aAllocInfo[] =
2046 {
2047 { fVirtApicAccess, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysApicAccess, (PRTR0PTR)&pVM->hmr0.s.vmx.pbApicAccess },
2048 { fUseVmcsShadowing, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysVmreadBitmap, &pVM->hmr0.s.vmx.pvVmreadBitmap },
2049 { fUseVmcsShadowing, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysVmwriteBitmap, &pVM->hmr0.s.vmx.pvVmwriteBitmap },
2050#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2051 { true, 0 /* Unused */, &pVM->hmr0.s.vmx.HCPhysScratch, (PRTR0PTR)&pVM->hmr0.s.vmx.pbScratch },
2052#endif
2053 };
2054
2055 int rc = hmR0VmxPagesAllocZ(&pVM->hmr0.s.vmx.hMemObj, &aAllocInfo[0], RT_ELEMENTS(aAllocInfo));
2056 if (RT_SUCCESS(rc))
2057 {
2058#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2059 /* Allocate the shadow VMCS-fields array. */
2060 if (fUseVmcsShadowing)
2061 {
2062 Assert(!pVM->hmr0.s.vmx.cShadowVmcsFields);
2063 Assert(!pVM->hmr0.s.vmx.cShadowVmcsRoFields);
2064 pVM->hmr0.s.vmx.paShadowVmcsFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
2065 pVM->hmr0.s.vmx.paShadowVmcsRoFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
2066 if (!pVM->hmr0.s.vmx.paShadowVmcsFields || !pVM->hmr0.s.vmx.paShadowVmcsRoFields)
2067 rc = VERR_NO_MEMORY;
2068 }
2069#endif
2070
2071 /*
2072 * Allocate per-VCPU VT-x structures.
2073 */
2074 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus && RT_SUCCESS(rc); idCpu++)
2075 {
2076 /* Allocate the guest VMCS structures. */
2077 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2078 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
2079
2080#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2081 /* Allocate the nested-guest VMCS structures, when the VMX feature is exposed to the guest. */
2082 if (pVM->cpum.ro.GuestFeatures.fVmx && RT_SUCCESS(rc))
2083 rc = hmR0VmxAllocVmcsInfo(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
2084#endif
2085 }
2086 if (RT_SUCCESS(rc))
2087 return VINF_SUCCESS;
2088 }
2089 hmR0VmxStructsFree(pVM);
2090 return rc;
2091}
2092
2093
2094/**
2095 * Pre-initializes non-zero fields in VMX structures that will be allocated.
2096 *
2097 * @param pVM The cross context VM structure.
2098 */
2099static void hmR0VmxStructsInit(PVMCC pVM)
2100{
2101 /* Paranoia. */
2102 Assert(pVM->hmr0.s.vmx.pbApicAccess == NULL);
2103#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2104 Assert(pVM->hmr0.s.vmx.pbScratch == NULL);
2105#endif
2106
2107 /*
2108 * Initialize members up-front so we can cleanup en masse on allocation failures.
2109 */
2110#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2111 pVM->hmr0.s.vmx.HCPhysScratch = NIL_RTHCPHYS;
2112#endif
2113 pVM->hmr0.s.vmx.HCPhysApicAccess = NIL_RTHCPHYS;
2114 pVM->hmr0.s.vmx.HCPhysVmreadBitmap = NIL_RTHCPHYS;
2115 pVM->hmr0.s.vmx.HCPhysVmwriteBitmap = NIL_RTHCPHYS;
2116 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
2117 {
2118 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
2119 hmR0VmxVmcsInfoInit(&pVCpu->hmr0.s.vmx.VmcsInfo, &pVCpu->hm.s.vmx.VmcsInfo);
2120 hmR0VmxVmcsInfoInit(&pVCpu->hmr0.s.vmx.VmcsInfoNstGst, &pVCpu->hm.s.vmx.VmcsInfoNstGst);
2121 }
2122}
2123
2124#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2125/**
2126 * Returns whether an MSR at the given MSR-bitmap offset is intercepted or not.
2127 *
2128 * @returns @c true if the MSR is intercepted, @c false otherwise.
2129 * @param pbMsrBitmap The MSR bitmap.
2130 * @param offMsr The MSR byte offset.
2131 * @param iBit The bit offset from the byte offset.
2132 */
2133DECLINLINE(bool) hmR0VmxIsMsrBitSet(uint8_t const *pbMsrBitmap, uint16_t offMsr, int32_t iBit)
2134{
2135 Assert(offMsr + (iBit >> 3) <= X86_PAGE_4K_SIZE);
2136 return ASMBitTest(pbMsrBitmap + offMsr, iBit);
2137}
2138#endif
2139
2140/**
2141 * Sets the permission bits for the specified MSR in the given MSR bitmap.
2142 *
2143 * If the passed VMCS is a nested-guest VMCS, this function ensures that the
2144 * read/write intercept is cleared from the MSR bitmap used for hardware-assisted
2145 * VMX execution of the nested-guest, only if nested-guest is also not intercepting
2146 * the read/write access of this MSR.
2147 *
2148 * @param pVCpu The cross context virtual CPU structure.
2149 * @param pVmcsInfo The VMCS info. object.
2150 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2151 * @param idMsr The MSR value.
2152 * @param fMsrpm The MSR permissions (see VMXMSRPM_XXX). This must
2153 * include both a read -and- a write permission!
2154 *
2155 * @sa CPUMGetVmxMsrPermission.
2156 * @remarks Can be called with interrupts disabled.
2157 */
2158static void hmR0VmxSetMsrPermission(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs, uint32_t idMsr, uint32_t fMsrpm)
2159{
2160 uint8_t *pbMsrBitmap = (uint8_t *)pVmcsInfo->pvMsrBitmap;
2161 Assert(pbMsrBitmap);
2162 Assert(VMXMSRPM_IS_FLAG_VALID(fMsrpm));
2163
2164 /*
2165 * MSR-bitmap Layout:
2166 * Byte index MSR range Interpreted as
2167 * 0x000 - 0x3ff 0x00000000 - 0x00001fff Low MSR read bits.
2168 * 0x400 - 0x7ff 0xc0000000 - 0xc0001fff High MSR read bits.
2169 * 0x800 - 0xbff 0x00000000 - 0x00001fff Low MSR write bits.
2170 * 0xc00 - 0xfff 0xc0000000 - 0xc0001fff High MSR write bits.
2171 *
2172 * A bit corresponding to an MSR within the above range causes a VM-exit
2173 * if the bit is 1 on executions of RDMSR/WRMSR. If an MSR falls out of
2174 * the MSR range, it always cause a VM-exit.
2175 *
2176 * See Intel spec. 24.6.9 "MSR-Bitmap Address".
2177 */
2178 uint16_t const offBitmapRead = 0;
2179 uint16_t const offBitmapWrite = 0x800;
2180 uint16_t offMsr;
2181 int32_t iBit;
2182 if (idMsr <= UINT32_C(0x00001fff))
2183 {
2184 offMsr = 0;
2185 iBit = idMsr;
2186 }
2187 else if (idMsr - UINT32_C(0xc0000000) <= UINT32_C(0x00001fff))
2188 {
2189 offMsr = 0x400;
2190 iBit = idMsr - UINT32_C(0xc0000000);
2191 }
2192 else
2193 AssertMsgFailedReturnVoid(("Invalid MSR %#RX32\n", idMsr));
2194
2195 /*
2196 * Set the MSR read permission.
2197 */
2198 uint16_t const offMsrRead = offBitmapRead + offMsr;
2199 Assert(offMsrRead + (iBit >> 3) < offBitmapWrite);
2200 if (fMsrpm & VMXMSRPM_ALLOW_RD)
2201 {
2202#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2203 bool const fClear = !fIsNstGstVmcs ? true
2204 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap, offMsrRead, iBit);
2205#else
2206 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2207 bool const fClear = true;
2208#endif
2209 if (fClear)
2210 ASMBitClear(pbMsrBitmap + offMsrRead, iBit);
2211 }
2212 else
2213 ASMBitSet(pbMsrBitmap + offMsrRead, iBit);
2214
2215 /*
2216 * Set the MSR write permission.
2217 */
2218 uint16_t const offMsrWrite = offBitmapWrite + offMsr;
2219 Assert(offMsrWrite + (iBit >> 3) < X86_PAGE_4K_SIZE);
2220 if (fMsrpm & VMXMSRPM_ALLOW_WR)
2221 {
2222#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
2223 bool const fClear = !fIsNstGstVmcs ? true
2224 : !hmR0VmxIsMsrBitSet(pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap, offMsrWrite, iBit);
2225#else
2226 RT_NOREF2(pVCpu, fIsNstGstVmcs);
2227 bool const fClear = true;
2228#endif
2229 if (fClear)
2230 ASMBitClear(pbMsrBitmap + offMsrWrite, iBit);
2231 }
2232 else
2233 ASMBitSet(pbMsrBitmap + offMsrWrite, iBit);
2234}
2235
2236
2237/**
2238 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
2239 * area.
2240 *
2241 * @returns VBox status code.
2242 * @param pVCpu The cross context virtual CPU structure.
2243 * @param pVmcsInfo The VMCS info. object.
2244 * @param cMsrs The number of MSRs.
2245 */
2246static int hmR0VmxSetAutoLoadStoreMsrCount(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint32_t cMsrs)
2247{
2248 /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
2249 uint32_t const cMaxSupportedMsrs = VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc);
2250 if (RT_LIKELY(cMsrs < cMaxSupportedMsrs))
2251 {
2252 /* Commit the MSR counts to the VMCS and update the cache. */
2253 if (pVmcsInfo->cEntryMsrLoad != cMsrs)
2254 {
2255 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2256 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs); AssertRC(rc);
2257 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, cMsrs); AssertRC(rc);
2258 pVmcsInfo->cEntryMsrLoad = cMsrs;
2259 pVmcsInfo->cExitMsrStore = cMsrs;
2260 pVmcsInfo->cExitMsrLoad = cMsrs;
2261 }
2262 return VINF_SUCCESS;
2263 }
2264
2265 LogRel(("Auto-load/store MSR count exceeded! cMsrs=%u MaxSupported=%u\n", cMsrs, cMaxSupportedMsrs));
2266 pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
2267 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
2268}
2269
2270
2271/**
2272 * Adds a new (or updates the value of an existing) guest/host MSR
2273 * pair to be swapped during the world-switch as part of the
2274 * auto-load/store MSR area in the VMCS.
2275 *
2276 * @returns VBox status code.
2277 * @param pVCpu The cross context virtual CPU structure.
2278 * @param pVmxTransient The VMX-transient structure.
2279 * @param idMsr The MSR.
2280 * @param uGuestMsrValue Value of the guest MSR.
2281 * @param fSetReadWrite Whether to set the guest read/write access of this
2282 * MSR (thus not causing a VM-exit).
2283 * @param fUpdateHostMsr Whether to update the value of the host MSR if
2284 * necessary.
2285 */
2286static int hmR0VmxAddAutoLoadStoreMsr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t idMsr, uint64_t uGuestMsrValue,
2287 bool fSetReadWrite, bool fUpdateHostMsr)
2288{
2289 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2290 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2291 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2292 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2293 uint32_t i;
2294
2295 /* Paranoia. */
2296 Assert(pGuestMsrLoad);
2297
2298#ifndef DEBUG_bird
2299 LogFlowFunc(("pVCpu=%p idMsr=%#RX32 uGuestMsrValue=%#RX64\n", pVCpu, idMsr, uGuestMsrValue));
2300#endif
2301
2302 /* Check if the MSR already exists in the VM-entry MSR-load area. */
2303 for (i = 0; i < cMsrs; i++)
2304 {
2305 if (pGuestMsrLoad[i].u32Msr == idMsr)
2306 break;
2307 }
2308
2309 bool fAdded = false;
2310 if (i == cMsrs)
2311 {
2312 /* The MSR does not exist, bump the MSR count to make room for the new MSR. */
2313 ++cMsrs;
2314 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2315 AssertMsgRCReturn(rc, ("Insufficient space to add MSR to VM-entry MSR-load/store area %u\n", idMsr), rc);
2316
2317 /* Set the guest to read/write this MSR without causing VM-exits. */
2318 if ( fSetReadWrite
2319 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
2320 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_ALLOW_RD_WR);
2321
2322 Log4Func(("Added MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2323 fAdded = true;
2324 }
2325
2326 /* Update the MSR value for the newly added or already existing MSR. */
2327 pGuestMsrLoad[i].u32Msr = idMsr;
2328 pGuestMsrLoad[i].u64Value = uGuestMsrValue;
2329
2330 /* Create the corresponding slot in the VM-exit MSR-store area if we use a different page. */
2331 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2332 {
2333 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2334 pGuestMsrStore[i].u32Msr = idMsr;
2335 pGuestMsrStore[i].u64Value = uGuestMsrValue;
2336 }
2337
2338 /* Update the corresponding slot in the host MSR area. */
2339 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2340 Assert(pHostMsr != pVmcsInfo->pvGuestMsrLoad);
2341 Assert(pHostMsr != pVmcsInfo->pvGuestMsrStore);
2342 pHostMsr[i].u32Msr = idMsr;
2343
2344 /*
2345 * Only if the caller requests to update the host MSR value AND we've newly added the
2346 * MSR to the host MSR area do we actually update the value. Otherwise, it will be
2347 * updated by hmR0VmxUpdateAutoLoadHostMsrs().
2348 *
2349 * We do this for performance reasons since reading MSRs may be quite expensive.
2350 */
2351 if (fAdded)
2352 {
2353 if (fUpdateHostMsr)
2354 {
2355 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2356 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2357 pHostMsr[i].u64Value = ASMRdMsr(idMsr);
2358 }
2359 else
2360 {
2361 /* Someone else can do the work. */
2362 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
2363 }
2364 }
2365 return VINF_SUCCESS;
2366}
2367
2368
2369/**
2370 * Removes a guest/host MSR pair to be swapped during the world-switch from the
2371 * auto-load/store MSR area in the VMCS.
2372 *
2373 * @returns VBox status code.
2374 * @param pVCpu The cross context virtual CPU structure.
2375 * @param pVmxTransient The VMX-transient structure.
2376 * @param idMsr The MSR.
2377 */
2378static int hmR0VmxRemoveAutoLoadStoreMsr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t idMsr)
2379{
2380 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
2381 bool const fIsNstGstVmcs = pVmxTransient->fIsNestedGuest;
2382 PVMXAUTOMSR pGuestMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2383 uint32_t cMsrs = pVmcsInfo->cEntryMsrLoad;
2384
2385#ifndef DEBUG_bird
2386 LogFlowFunc(("pVCpu=%p idMsr=%#RX32\n", pVCpu, idMsr));
2387#endif
2388
2389 for (uint32_t i = 0; i < cMsrs; i++)
2390 {
2391 /* Find the MSR. */
2392 if (pGuestMsrLoad[i].u32Msr == idMsr)
2393 {
2394 /*
2395 * If it's the last MSR, we only need to reduce the MSR count.
2396 * If it's -not- the last MSR, copy the last MSR in place of it and reduce the MSR count.
2397 */
2398 if (i < cMsrs - 1)
2399 {
2400 /* Remove it from the VM-entry MSR-load area. */
2401 pGuestMsrLoad[i].u32Msr = pGuestMsrLoad[cMsrs - 1].u32Msr;
2402 pGuestMsrLoad[i].u64Value = pGuestMsrLoad[cMsrs - 1].u64Value;
2403
2404 /* Remove it from the VM-exit MSR-store area if it's in a different page. */
2405 if (hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo))
2406 {
2407 PVMXAUTOMSR pGuestMsrStore = (PVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2408 Assert(pGuestMsrStore[i].u32Msr == idMsr);
2409 pGuestMsrStore[i].u32Msr = pGuestMsrStore[cMsrs - 1].u32Msr;
2410 pGuestMsrStore[i].u64Value = pGuestMsrStore[cMsrs - 1].u64Value;
2411 }
2412
2413 /* Remove it from the VM-exit MSR-load area. */
2414 PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2415 Assert(pHostMsr[i].u32Msr == idMsr);
2416 pHostMsr[i].u32Msr = pHostMsr[cMsrs - 1].u32Msr;
2417 pHostMsr[i].u64Value = pHostMsr[cMsrs - 1].u64Value;
2418 }
2419
2420 /* Reduce the count to reflect the removed MSR and bail. */
2421 --cMsrs;
2422 break;
2423 }
2424 }
2425
2426 /* Update the VMCS if the count changed (meaning the MSR was found and removed). */
2427 if (cMsrs != pVmcsInfo->cEntryMsrLoad)
2428 {
2429 int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, pVmcsInfo, cMsrs);
2430 AssertRCReturn(rc, rc);
2431
2432 /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
2433 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2434 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, fIsNstGstVmcs, idMsr, VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR);
2435
2436 Log4Func(("Removed MSR %#RX32, cMsrs=%u\n", idMsr, cMsrs));
2437 return VINF_SUCCESS;
2438 }
2439
2440 return VERR_NOT_FOUND;
2441}
2442
2443
2444/**
2445 * Checks if the specified guest MSR is part of the VM-entry MSR-load area.
2446 *
2447 * @returns @c true if found, @c false otherwise.
2448 * @param pVmcsInfo The VMCS info. object.
2449 * @param idMsr The MSR to find.
2450 */
2451static bool hmR0VmxIsAutoLoadGuestMsr(PCVMXVMCSINFO pVmcsInfo, uint32_t idMsr)
2452{
2453 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2454 uint32_t const cMsrs = pVmcsInfo->cEntryMsrLoad;
2455 Assert(pMsrs);
2456 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
2457 for (uint32_t i = 0; i < cMsrs; i++)
2458 {
2459 if (pMsrs[i].u32Msr == idMsr)
2460 return true;
2461 }
2462 return false;
2463}
2464
2465
2466/**
2467 * Updates the value of all host MSRs in the VM-exit MSR-load area.
2468 *
2469 * @param pVCpu The cross context virtual CPU structure.
2470 * @param pVmcsInfo The VMCS info. object.
2471 *
2472 * @remarks No-long-jump zone!!!
2473 */
2474static void hmR0VmxUpdateAutoLoadHostMsrs(PCVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
2475{
2476 RT_NOREF(pVCpu);
2477 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2478
2479 PVMXAUTOMSR pHostMsrLoad = (PVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2480 uint32_t const cMsrs = pVmcsInfo->cExitMsrLoad;
2481 Assert(pHostMsrLoad);
2482 Assert(sizeof(*pHostMsrLoad) * cMsrs <= X86_PAGE_4K_SIZE);
2483 LogFlowFunc(("pVCpu=%p cMsrs=%u\n", pVCpu, cMsrs));
2484 for (uint32_t i = 0; i < cMsrs; i++)
2485 {
2486 /*
2487 * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
2488 * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
2489 */
2490 if (pHostMsrLoad[i].u32Msr == MSR_K6_EFER)
2491 pHostMsrLoad[i].u64Value = g_uHmVmxHostMsrEfer;
2492 else
2493 pHostMsrLoad[i].u64Value = ASMRdMsr(pHostMsrLoad[i].u32Msr);
2494 }
2495}
2496
2497
2498/**
2499 * Saves a set of host MSRs to allow read/write passthru access to the guest and
2500 * perform lazy restoration of the host MSRs while leaving VT-x.
2501 *
2502 * @param pVCpu The cross context virtual CPU structure.
2503 *
2504 * @remarks No-long-jump zone!!!
2505 */
2506static void hmR0VmxLazySaveHostMsrs(PVMCPUCC pVCpu)
2507{
2508 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2509
2510 /*
2511 * Note: If you're adding MSRs here, make sure to update the MSR-bitmap accesses in hmR0VmxSetupVmcsProcCtls().
2512 */
2513 if (!(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST))
2514 {
2515 Assert(!(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)); /* Guest MSRs better not be loaded now. */
2516 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2517 {
2518 pVCpu->hmr0.s.vmx.u64HostMsrLStar = ASMRdMsr(MSR_K8_LSTAR);
2519 pVCpu->hmr0.s.vmx.u64HostMsrStar = ASMRdMsr(MSR_K6_STAR);
2520 pVCpu->hmr0.s.vmx.u64HostMsrSfMask = ASMRdMsr(MSR_K8_SF_MASK);
2521 pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
2522 }
2523 pVCpu->hmr0.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_SAVED_HOST;
2524 }
2525}
2526
2527
2528/**
2529 * Checks whether the MSR belongs to the set of guest MSRs that we restore
2530 * lazily while leaving VT-x.
2531 *
2532 * @returns true if it does, false otherwise.
2533 * @param pVCpu The cross context virtual CPU structure.
2534 * @param idMsr The MSR to check.
2535 */
2536static bool hmR0VmxIsLazyGuestMsr(PCVMCPUCC pVCpu, uint32_t idMsr)
2537{
2538 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2539 {
2540 switch (idMsr)
2541 {
2542 case MSR_K8_LSTAR:
2543 case MSR_K6_STAR:
2544 case MSR_K8_SF_MASK:
2545 case MSR_K8_KERNEL_GS_BASE:
2546 return true;
2547 }
2548 }
2549 return false;
2550}
2551
2552
2553/**
2554 * Loads a set of guests MSRs to allow read/passthru to the guest.
2555 *
2556 * The name of this function is slightly confusing. This function does NOT
2557 * postpone loading, but loads the MSR right now. "hmR0VmxLazy" is simply a
2558 * common prefix for functions dealing with "lazy restoration" of the shared
2559 * MSRs.
2560 *
2561 * @param pVCpu The cross context virtual CPU structure.
2562 *
2563 * @remarks No-long-jump zone!!!
2564 */
2565static void hmR0VmxLazyLoadGuestMsrs(PVMCPUCC pVCpu)
2566{
2567 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2568 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2569
2570 Assert(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2571 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2572 {
2573 /*
2574 * If the guest MSRs are not loaded -and- if all the guest MSRs are identical
2575 * to the MSRs on the CPU (which are the saved host MSRs, see assertion above) then
2576 * we can skip a few MSR writes.
2577 *
2578 * Otherwise, it implies either 1. they're not loaded, or 2. they're loaded but the
2579 * guest MSR values in the guest-CPU context might be different to what's currently
2580 * loaded in the CPU. In either case, we need to write the new guest MSR values to the
2581 * CPU, see @bugref{8728}.
2582 */
2583 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
2584 if ( !(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2585 && pCtx->msrKERNELGSBASE == pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase
2586 && pCtx->msrLSTAR == pVCpu->hmr0.s.vmx.u64HostMsrLStar
2587 && pCtx->msrSTAR == pVCpu->hmr0.s.vmx.u64HostMsrStar
2588 && pCtx->msrSFMASK == pVCpu->hmr0.s.vmx.u64HostMsrSfMask)
2589 {
2590#ifdef VBOX_STRICT
2591 Assert(ASMRdMsr(MSR_K8_KERNEL_GS_BASE) == pCtx->msrKERNELGSBASE);
2592 Assert(ASMRdMsr(MSR_K8_LSTAR) == pCtx->msrLSTAR);
2593 Assert(ASMRdMsr(MSR_K6_STAR) == pCtx->msrSTAR);
2594 Assert(ASMRdMsr(MSR_K8_SF_MASK) == pCtx->msrSFMASK);
2595#endif
2596 }
2597 else
2598 {
2599 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pCtx->msrKERNELGSBASE);
2600 ASMWrMsr(MSR_K8_LSTAR, pCtx->msrLSTAR);
2601 ASMWrMsr(MSR_K6_STAR, pCtx->msrSTAR);
2602 /* The system call flag mask register isn't as benign and accepting of all
2603 values as the above, so mask it to avoid #GP'ing on corrupted input. */
2604 Assert(!(pCtx->msrSFMASK & ~(uint64_t)UINT32_MAX));
2605 ASMWrMsr(MSR_K8_SF_MASK, pCtx->msrSFMASK & UINT32_MAX);
2606 }
2607 }
2608 pVCpu->hmr0.s.vmx.fLazyMsrs |= VMX_LAZY_MSRS_LOADED_GUEST;
2609}
2610
2611
2612/**
2613 * Performs lazy restoration of the set of host MSRs if they were previously
2614 * loaded with guest MSR values.
2615 *
2616 * @param pVCpu The cross context virtual CPU structure.
2617 *
2618 * @remarks No-long-jump zone!!!
2619 * @remarks The guest MSRs should have been saved back into the guest-CPU
2620 * context by hmR0VmxImportGuestState()!!!
2621 */
2622static void hmR0VmxLazyRestoreHostMsrs(PVMCPUCC pVCpu)
2623{
2624 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2625 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2626
2627 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
2628 {
2629 Assert(pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_SAVED_HOST);
2630 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fAllow64BitGuests)
2631 {
2632 ASMWrMsr(MSR_K8_LSTAR, pVCpu->hmr0.s.vmx.u64HostMsrLStar);
2633 ASMWrMsr(MSR_K6_STAR, pVCpu->hmr0.s.vmx.u64HostMsrStar);
2634 ASMWrMsr(MSR_K8_SF_MASK, pVCpu->hmr0.s.vmx.u64HostMsrSfMask);
2635 ASMWrMsr(MSR_K8_KERNEL_GS_BASE, pVCpu->hmr0.s.vmx.u64HostMsrKernelGsBase);
2636 }
2637 }
2638 pVCpu->hmr0.s.vmx.fLazyMsrs &= ~(VMX_LAZY_MSRS_LOADED_GUEST | VMX_LAZY_MSRS_SAVED_HOST);
2639}
2640
2641
2642/**
2643 * Verifies that our cached values of the VMCS fields are all consistent with
2644 * what's actually present in the VMCS.
2645 *
2646 * @returns VBox status code.
2647 * @retval VINF_SUCCESS if all our caches match their respective VMCS fields.
2648 * @retval VERR_VMX_VMCS_FIELD_CACHE_INVALID if a cache field doesn't match the
2649 * VMCS content. HMCPU error-field is
2650 * updated, see VMX_VCI_XXX.
2651 * @param pVCpu The cross context virtual CPU structure.
2652 * @param pVmcsInfo The VMCS info. object.
2653 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2654 */
2655static int hmR0VmxCheckCachedVmcsCtls(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2656{
2657 const char * const pcszVmcs = fIsNstGstVmcs ? "Nested-guest VMCS" : "VMCS";
2658
2659 uint32_t u32Val;
2660 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
2661 AssertRC(rc);
2662 AssertMsgReturnStmt(pVmcsInfo->u32EntryCtls == u32Val,
2663 ("%s entry controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32EntryCtls, u32Val),
2664 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_ENTRY,
2665 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2666
2667 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT, &u32Val);
2668 AssertRC(rc);
2669 AssertMsgReturnStmt(pVmcsInfo->u32ExitCtls == u32Val,
2670 ("%s exit controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ExitCtls, u32Val),
2671 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_EXIT,
2672 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2673
2674 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, &u32Val);
2675 AssertRC(rc);
2676 AssertMsgReturnStmt(pVmcsInfo->u32PinCtls == u32Val,
2677 ("%s pin controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32PinCtls, u32Val),
2678 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PIN_EXEC,
2679 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2680
2681 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, &u32Val);
2682 AssertRC(rc);
2683 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls == u32Val,
2684 ("%s proc controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls, u32Val),
2685 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC,
2686 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2687
2688 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
2689 {
2690 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, &u32Val);
2691 AssertRC(rc);
2692 AssertMsgReturnStmt(pVmcsInfo->u32ProcCtls2 == u32Val,
2693 ("%s proc2 controls mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32ProcCtls2, u32Val),
2694 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC2,
2695 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2696 }
2697
2698 uint64_t u64Val;
2699 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TERTIARY_CTLS)
2700 {
2701 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_PROC_EXEC3_FULL, &u64Val);
2702 AssertRC(rc);
2703 AssertMsgReturnStmt(pVmcsInfo->u64ProcCtls3 == u64Val,
2704 ("%s proc3 controls mismatch: Cache=%#RX32 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64ProcCtls3, u64Val),
2705 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_PROC_EXEC3,
2706 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2707 }
2708
2709 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, &u32Val);
2710 AssertRC(rc);
2711 AssertMsgReturnStmt(pVmcsInfo->u32XcptBitmap == u32Val,
2712 ("%s exception bitmap mismatch: Cache=%#RX32 VMCS=%#RX32\n", pcszVmcs, pVmcsInfo->u32XcptBitmap, u32Val),
2713 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_XCPT_BITMAP,
2714 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2715
2716 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, &u64Val);
2717 AssertRC(rc);
2718 AssertMsgReturnStmt(pVmcsInfo->u64TscOffset == u64Val,
2719 ("%s TSC offset mismatch: Cache=%#RX64 VMCS=%#RX64\n", pcszVmcs, pVmcsInfo->u64TscOffset, u64Val),
2720 pVCpu->hm.s.u32HMError = VMX_VCI_CTRL_TSC_OFFSET,
2721 VERR_VMX_VMCS_FIELD_CACHE_INVALID);
2722
2723 NOREF(pcszVmcs);
2724 return VINF_SUCCESS;
2725}
2726
2727#ifdef VBOX_STRICT
2728
2729/**
2730 * Verifies that our cached host EFER MSR value has not changed since we cached it.
2731 *
2732 * @param pVmcsInfo The VMCS info. object.
2733 */
2734static void hmR0VmxCheckHostEferMsr(PCVMXVMCSINFO pVmcsInfo)
2735{
2736 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2737
2738 if (pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_LOAD_EFER_MSR)
2739 {
2740 uint64_t const uHostEferMsr = ASMRdMsr(MSR_K6_EFER);
2741 uint64_t const uHostEferMsrCache = g_uHmVmxHostMsrEfer;
2742 uint64_t uVmcsEferMsrVmcs;
2743 int rc = VMXReadVmcs64(VMX_VMCS64_HOST_EFER_FULL, &uVmcsEferMsrVmcs);
2744 AssertRC(rc);
2745
2746 AssertMsgReturnVoid(uHostEferMsr == uVmcsEferMsrVmcs,
2747 ("EFER Host/VMCS mismatch! host=%#RX64 vmcs=%#RX64\n", uHostEferMsr, uVmcsEferMsrVmcs));
2748 AssertMsgReturnVoid(uHostEferMsr == uHostEferMsrCache,
2749 ("EFER Host/Cache mismatch! host=%#RX64 cache=%#RX64\n", uHostEferMsr, uHostEferMsrCache));
2750 }
2751}
2752
2753
2754/**
2755 * Verifies whether the guest/host MSR pairs in the auto-load/store area in the
2756 * VMCS are correct.
2757 *
2758 * @param pVCpu The cross context virtual CPU structure.
2759 * @param pVmcsInfo The VMCS info. object.
2760 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
2761 */
2762static void hmR0VmxCheckAutoLoadStoreMsrs(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
2763{
2764 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2765
2766 /* Read the various MSR-area counts from the VMCS. */
2767 uint32_t cEntryLoadMsrs;
2768 uint32_t cExitStoreMsrs;
2769 uint32_t cExitLoadMsrs;
2770 int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, &cEntryLoadMsrs); AssertRC(rc);
2771 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, &cExitStoreMsrs); AssertRC(rc);
2772 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, &cExitLoadMsrs); AssertRC(rc);
2773
2774 /* Verify all the MSR counts are the same. */
2775 Assert(cEntryLoadMsrs == cExitStoreMsrs);
2776 Assert(cExitStoreMsrs == cExitLoadMsrs);
2777 uint32_t const cMsrs = cExitLoadMsrs;
2778
2779 /* Verify the MSR counts do not exceed the maximum count supported by the hardware. */
2780 Assert(cMsrs < VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc));
2781
2782 /* Verify the MSR counts are within the allocated page size. */
2783 Assert(sizeof(VMXAUTOMSR) * cMsrs <= X86_PAGE_4K_SIZE);
2784
2785 /* Verify the relevant contents of the MSR areas match. */
2786 PCVMXAUTOMSR pGuestMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrLoad;
2787 PCVMXAUTOMSR pGuestMsrStore = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
2788 PCVMXAUTOMSR pHostMsrLoad = (PCVMXAUTOMSR)pVmcsInfo->pvHostMsrLoad;
2789 bool const fSeparateExitMsrStorePage = hmR0VmxIsSeparateExitMsrStoreAreaVmcs(pVmcsInfo);
2790 for (uint32_t i = 0; i < cMsrs; i++)
2791 {
2792 /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
2793 if (fSeparateExitMsrStorePage)
2794 {
2795 AssertMsgReturnVoid(pGuestMsrLoad->u32Msr == pGuestMsrStore->u32Msr,
2796 ("GuestMsrLoad=%#RX32 GuestMsrStore=%#RX32 cMsrs=%u\n",
2797 pGuestMsrLoad->u32Msr, pGuestMsrStore->u32Msr, cMsrs));
2798 }
2799
2800 AssertMsgReturnVoid(pHostMsrLoad->u32Msr == pGuestMsrLoad->u32Msr,
2801 ("HostMsrLoad=%#RX32 GuestMsrLoad=%#RX32 cMsrs=%u\n",
2802 pHostMsrLoad->u32Msr, pGuestMsrLoad->u32Msr, cMsrs));
2803
2804 uint64_t const u64HostMsr = ASMRdMsr(pHostMsrLoad->u32Msr);
2805 AssertMsgReturnVoid(pHostMsrLoad->u64Value == u64HostMsr,
2806 ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
2807 pHostMsrLoad->u32Msr, pHostMsrLoad->u64Value, u64HostMsr, cMsrs));
2808
2809 /* Verify that cached host EFER MSR matches what's loaded on the CPU. */
2810 bool const fIsEferMsr = RT_BOOL(pHostMsrLoad->u32Msr == MSR_K6_EFER);
2811 AssertMsgReturnVoid(!fIsEferMsr || u64HostMsr == g_uHmVmxHostMsrEfer,
2812 ("Cached=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n", g_uHmVmxHostMsrEfer, u64HostMsr, cMsrs));
2813
2814 /* Verify that the accesses are as expected in the MSR bitmap for auto-load/store MSRs. */
2815 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
2816 {
2817 uint32_t const fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, pGuestMsrLoad->u32Msr);
2818 if (fIsEferMsr)
2819 {
2820 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_RD), ("Passthru read for EFER MSR!?\n"));
2821 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_EXIT_WR), ("Passthru write for EFER MSR!?\n"));
2822 }
2823 else
2824 {
2825 /* Verify LBR MSRs (used only for debugging) are intercepted. We don't passthru these MSRs to the guest yet. */
2826 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
2827 if ( pVM->hmr0.s.vmx.fLbr
2828 && ( hmR0VmxIsLbrBranchFromMsr(pVM, pGuestMsrLoad->u32Msr, NULL /* pidxMsr */)
2829 || hmR0VmxIsLbrBranchToMsr(pVM, pGuestMsrLoad->u32Msr, NULL /* pidxMsr */)
2830 || pGuestMsrLoad->u32Msr == pVM->hmr0.s.vmx.idLbrTosMsr))
2831 {
2832 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_MASK) == VMXMSRPM_EXIT_RD_WR,
2833 ("u32Msr=%#RX32 cMsrs=%u Passthru read/write for LBR MSRs!\n",
2834 pGuestMsrLoad->u32Msr, cMsrs));
2835 }
2836 else if (!fIsNstGstVmcs)
2837 {
2838 AssertMsgReturnVoid((fMsrpm & VMXMSRPM_MASK) == VMXMSRPM_ALLOW_RD_WR,
2839 ("u32Msr=%#RX32 cMsrs=%u No passthru read/write!\n", pGuestMsrLoad->u32Msr, cMsrs));
2840 }
2841 else
2842 {
2843 /*
2844 * A nested-guest VMCS must -also- allow read/write passthrough for the MSR for us to
2845 * execute a nested-guest with MSR passthrough.
2846 *
2847 * Check if the nested-guest MSR bitmap allows passthrough, and if so, assert that we
2848 * allow passthrough too.
2849 */
2850 void const *pvMsrBitmapNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap;
2851 Assert(pvMsrBitmapNstGst);
2852 uint32_t const fMsrpmNstGst = CPUMGetVmxMsrPermission(pvMsrBitmapNstGst, pGuestMsrLoad->u32Msr);
2853 AssertMsgReturnVoid(fMsrpm == fMsrpmNstGst,
2854 ("u32Msr=%#RX32 cMsrs=%u Permission mismatch fMsrpm=%#x fMsrpmNstGst=%#x!\n",
2855 pGuestMsrLoad->u32Msr, cMsrs, fMsrpm, fMsrpmNstGst));
2856 }
2857 }
2858 }
2859
2860 /* Move to the next MSR. */
2861 pHostMsrLoad++;
2862 pGuestMsrLoad++;
2863 pGuestMsrStore++;
2864 }
2865}
2866
2867#endif /* VBOX_STRICT */
2868
2869/**
2870 * Flushes the TLB using EPT.
2871 *
2872 * @returns VBox status code.
2873 * @param pVCpu The cross context virtual CPU structure of the calling
2874 * EMT. Can be NULL depending on @a enmTlbFlush.
2875 * @param pVmcsInfo The VMCS info. object. Can be NULL depending on @a
2876 * enmTlbFlush.
2877 * @param enmTlbFlush Type of flush.
2878 *
2879 * @remarks Caller is responsible for making sure this function is called only
2880 * when NestedPaging is supported and providing @a enmTlbFlush that is
2881 * supported by the CPU.
2882 * @remarks Can be called with interrupts disabled.
2883 */
2884static void hmR0VmxFlushEpt(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, VMXTLBFLUSHEPT enmTlbFlush)
2885{
2886 uint64_t au64Descriptor[2];
2887 if (enmTlbFlush == VMXTLBFLUSHEPT_ALL_CONTEXTS)
2888 au64Descriptor[0] = 0;
2889 else
2890 {
2891 Assert(pVCpu);
2892 Assert(pVmcsInfo);
2893 au64Descriptor[0] = pVmcsInfo->HCPhysEPTP;
2894 }
2895 au64Descriptor[1] = 0; /* MBZ. Intel spec. 33.3 "VMX Instructions" */
2896
2897 int rc = VMXR0InvEPT(enmTlbFlush, &au64Descriptor[0]);
2898 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %#RHp failed. rc=%Rrc\n", enmTlbFlush, au64Descriptor[0], rc));
2899
2900 if ( RT_SUCCESS(rc)
2901 && pVCpu)
2902 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushNestedPaging);
2903}
2904
2905
2906/**
2907 * Flushes the TLB using VPID.
2908 *
2909 * @returns VBox status code.
2910 * @param pVCpu The cross context virtual CPU structure of the calling
2911 * EMT. Can be NULL depending on @a enmTlbFlush.
2912 * @param enmTlbFlush Type of flush.
2913 * @param GCPtr Virtual address of the page to flush (can be 0 depending
2914 * on @a enmTlbFlush).
2915 *
2916 * @remarks Can be called with interrupts disabled.
2917 */
2918static void hmR0VmxFlushVpid(PVMCPUCC pVCpu, VMXTLBFLUSHVPID enmTlbFlush, RTGCPTR GCPtr)
2919{
2920 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid);
2921
2922 uint64_t au64Descriptor[2];
2923 if (enmTlbFlush == VMXTLBFLUSHVPID_ALL_CONTEXTS)
2924 {
2925 au64Descriptor[0] = 0;
2926 au64Descriptor[1] = 0;
2927 }
2928 else
2929 {
2930 AssertPtr(pVCpu);
2931 AssertMsg(pVCpu->hmr0.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hmr0.s.uCurrentAsid));
2932 AssertMsg(pVCpu->hmr0.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hmr0.s.uCurrentAsid));
2933 au64Descriptor[0] = pVCpu->hmr0.s.uCurrentAsid;
2934 au64Descriptor[1] = GCPtr;
2935 }
2936
2937 int rc = VMXR0InvVPID(enmTlbFlush, &au64Descriptor[0]);
2938 AssertMsg(rc == VINF_SUCCESS,
2939 ("VMXR0InvVPID %#x %u %RGv failed with %Rrc\n", enmTlbFlush, pVCpu ? pVCpu->hmr0.s.uCurrentAsid : 0, GCPtr, rc));
2940
2941 if ( RT_SUCCESS(rc)
2942 && pVCpu)
2943 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
2944 NOREF(rc);
2945}
2946
2947
2948/**
2949 * Invalidates a guest page by guest virtual address. Only relevant for EPT/VPID,
2950 * otherwise there is nothing really to invalidate.
2951 *
2952 * @returns VBox status code.
2953 * @param pVCpu The cross context virtual CPU structure.
2954 * @param GCVirt Guest virtual address of the page to invalidate.
2955 */
2956VMMR0DECL(int) VMXR0InvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt)
2957{
2958 AssertPtr(pVCpu);
2959 LogFlowFunc(("pVCpu=%p GCVirt=%RGv\n", pVCpu, GCVirt));
2960
2961 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TLB_FLUSH))
2962 {
2963 /*
2964 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for
2965 * the EPT case. See @bugref{6043} and @bugref{6177}.
2966 *
2967 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VM-entry in hmR0VmxFlushTLB*()
2968 * as this function maybe called in a loop with individual addresses.
2969 */
2970 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2971 if (pVM->hmr0.s.vmx.fVpid)
2972 {
2973 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
2974 {
2975 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_INDIV_ADDR, GCVirt);
2976 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
2977 }
2978 else
2979 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2980 }
2981 else if (pVM->hmr0.s.fNestedPaging)
2982 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2983 }
2984
2985 return VINF_SUCCESS;
2986}
2987
2988
2989/**
2990 * Dummy placeholder for tagged-TLB flush handling before VM-entry. Used in the
2991 * case where neither EPT nor VPID is supported by the CPU.
2992 *
2993 * @param pHostCpu The HM physical-CPU structure.
2994 * @param pVCpu The cross context virtual CPU structure.
2995 *
2996 * @remarks Called with interrupts disabled.
2997 */
2998static void hmR0VmxFlushTaggedTlbNone(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
2999{
3000 AssertPtr(pVCpu);
3001 AssertPtr(pHostCpu);
3002
3003 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
3004
3005 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3006 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3007 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3008 pVCpu->hmr0.s.fForceTLBFlush = false;
3009 return;
3010}
3011
3012
3013/**
3014 * Flushes the tagged-TLB entries for EPT+VPID CPUs as necessary.
3015 *
3016 * @param pHostCpu The HM physical-CPU structure.
3017 * @param pVCpu The cross context virtual CPU structure.
3018 * @param pVmcsInfo The VMCS info. object.
3019 *
3020 * @remarks All references to "ASID" in this function pertains to "VPID" in Intel's
3021 * nomenclature. The reason is, to avoid confusion in compare statements
3022 * since the host-CPU copies are named "ASID".
3023 *
3024 * @remarks Called with interrupts disabled.
3025 */
3026static void hmR0VmxFlushTaggedTlbBoth(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3027{
3028#ifdef VBOX_WITH_STATISTICS
3029 bool fTlbFlushed = false;
3030# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { fTlbFlushed = true; } while (0)
3031# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
3032 if (!fTlbFlushed) \
3033 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch); \
3034 } while (0)
3035#else
3036# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
3037# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
3038#endif
3039
3040 AssertPtr(pVCpu);
3041 AssertPtr(pHostCpu);
3042 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3043
3044 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3045 AssertMsg(pVM->hmr0.s.fNestedPaging && pVM->hmr0.s.vmx.fVpid,
3046 ("hmR0VmxFlushTaggedTlbBoth cannot be invoked unless NestedPaging & VPID are enabled."
3047 "fNestedPaging=%RTbool fVpid=%RTbool", pVM->hmr0.s.fNestedPaging, pVM->hmr0.s.vmx.fVpid));
3048
3049 /*
3050 * Force a TLB flush for the first world-switch if the current CPU differs from the one we
3051 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3052 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3053 * cannot reuse the current ASID anymore.
3054 */
3055 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3056 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3057 {
3058 ++pHostCpu->uCurrentAsid;
3059 if (pHostCpu->uCurrentAsid >= g_uHmMaxAsid)
3060 {
3061 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0. */
3062 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3063 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3064 }
3065
3066 pVCpu->hmr0.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3067 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3068 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3069
3070 /*
3071 * Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
3072 * invalidated. We don't need to flush-by-VPID here as flushing by EPT covers it. See @bugref{6568}.
3073 */
3074 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3075 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3076 HMVMX_SET_TAGGED_TLB_FLUSHED();
3077 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
3078 }
3079 else if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH)) /* Check for explicit TLB flushes. */
3080 {
3081 /*
3082 * Changes to the EPT paging structure by VMM requires flushing-by-EPT as the CPU
3083 * creates guest-physical (ie. only EPT-tagged) mappings while traversing the EPT
3084 * tables when EPT is in use. Flushing-by-VPID will only flush linear (only
3085 * VPID-tagged) and combined (EPT+VPID tagged) mappings but not guest-physical
3086 * mappings, see @bugref{6568}.
3087 *
3088 * See Intel spec. 28.3.2 "Creating and Using Cached Translation Information".
3089 */
3090 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3091 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3092 HMVMX_SET_TAGGED_TLB_FLUSHED();
3093 }
3094 else if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3095 {
3096 /*
3097 * The nested-guest specifies its own guest-physical address to use as the APIC-access
3098 * address which requires flushing the TLB of EPT cached structures.
3099 *
3100 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
3101 */
3102 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVM->hmr0.s.vmx.enmTlbFlushEpt);
3103 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3104 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3105 HMVMX_SET_TAGGED_TLB_FLUSHED();
3106 }
3107
3108
3109 pVCpu->hmr0.s.fForceTLBFlush = false;
3110 HMVMX_UPDATE_FLUSH_SKIPPED_STAT();
3111
3112 Assert(pVCpu->hmr0.s.idLastCpu == pHostCpu->idCpu);
3113 Assert(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes);
3114 AssertMsg(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3115 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hmr0.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3116 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < g_uHmMaxAsid,
3117 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3118 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hmr0.s.idLastCpu, pVCpu->hmr0.s.cTlbFlushes));
3119 AssertMsg(pVCpu->hmr0.s.uCurrentAsid >= 1 && pVCpu->hmr0.s.uCurrentAsid < g_uHmMaxAsid,
3120 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hmr0.s.uCurrentAsid));
3121
3122 /* Update VMCS with the VPID. */
3123 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hmr0.s.uCurrentAsid);
3124 AssertRC(rc);
3125
3126#undef HMVMX_SET_TAGGED_TLB_FLUSHED
3127}
3128
3129
3130/**
3131 * Flushes the tagged-TLB entries for EPT CPUs as necessary.
3132 *
3133 * @param pHostCpu The HM physical-CPU structure.
3134 * @param pVCpu The cross context virtual CPU structure.
3135 * @param pVmcsInfo The VMCS info. object.
3136 *
3137 * @remarks Called with interrupts disabled.
3138 */
3139static void hmR0VmxFlushTaggedTlbEpt(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
3140{
3141 AssertPtr(pVCpu);
3142 AssertPtr(pHostCpu);
3143 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3144 AssertMsg(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked without NestedPaging."));
3145 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with VPID."));
3146
3147 /*
3148 * Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
3149 * A change in the TLB flush count implies the host CPU is online after a suspend/resume.
3150 */
3151 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3152 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3153 {
3154 pVCpu->hmr0.s.fForceTLBFlush = true;
3155 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3156 }
3157
3158 /* Check for explicit TLB flushes. */
3159 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3160 {
3161 pVCpu->hmr0.s.fForceTLBFlush = true;
3162 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3163 }
3164
3165 /* Check for TLB flushes while switching to/from a nested-guest. */
3166 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3167 {
3168 pVCpu->hmr0.s.fForceTLBFlush = true;
3169 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3170 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3171 }
3172
3173 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3174 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3175
3176 if (pVCpu->hmr0.s.fForceTLBFlush)
3177 {
3178 hmR0VmxFlushEpt(pVCpu, pVmcsInfo, pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.enmTlbFlushEpt);
3179 pVCpu->hmr0.s.fForceTLBFlush = false;
3180 }
3181}
3182
3183
3184/**
3185 * Flushes the tagged-TLB entries for VPID CPUs as necessary.
3186 *
3187 * @param pHostCpu The HM physical-CPU structure.
3188 * @param pVCpu The cross context virtual CPU structure.
3189 *
3190 * @remarks Called with interrupts disabled.
3191 */
3192static void hmR0VmxFlushTaggedTlbVpid(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu)
3193{
3194 AssertPtr(pVCpu);
3195 AssertPtr(pHostCpu);
3196 Assert(pHostCpu->idCpu != NIL_RTCPUID);
3197 AssertMsg(pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fVpid, ("hmR0VmxFlushTlbVpid cannot be invoked without VPID."));
3198 AssertMsg(!pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging"));
3199
3200 /*
3201 * Force a TLB flush for the first world switch if the current CPU differs from the one we
3202 * ran on last. If the TLB flush count changed, another VM (VCPU rather) has hit the ASID
3203 * limit while flushing the TLB or the host CPU is online after a suspend/resume, so we
3204 * cannot reuse the current ASID anymore.
3205 */
3206 if ( pVCpu->hmr0.s.idLastCpu != pHostCpu->idCpu
3207 || pVCpu->hmr0.s.cTlbFlushes != pHostCpu->cTlbFlushes)
3208 {
3209 pVCpu->hmr0.s.fForceTLBFlush = true;
3210 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
3211 }
3212
3213 /* Check for explicit TLB flushes. */
3214 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
3215 {
3216 /*
3217 * If we ever support VPID flush combinations other than ALL or SINGLE-context (see
3218 * hmR0VmxSetupTaggedTlb()) we would need to explicitly flush in this case (add an
3219 * fExplicitFlush = true here and change the pHostCpu->fFlushAsidBeforeUse check below to
3220 * include fExplicitFlush's too) - an obscure corner case.
3221 */
3222 pVCpu->hmr0.s.fForceTLBFlush = true;
3223 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
3224 }
3225
3226 /* Check for TLB flushes while switching to/from a nested-guest. */
3227 if (pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb)
3228 {
3229 pVCpu->hmr0.s.fForceTLBFlush = true;
3230 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = false;
3231 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbNstGst);
3232 }
3233
3234 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3235 pVCpu->hmr0.s.idLastCpu = pHostCpu->idCpu;
3236 if (pVCpu->hmr0.s.fForceTLBFlush)
3237 {
3238 ++pHostCpu->uCurrentAsid;
3239 if (pHostCpu->uCurrentAsid >= g_uHmMaxAsid)
3240 {
3241 pHostCpu->uCurrentAsid = 1; /* Wraparound to 1; host uses 0 */
3242 pHostCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
3243 pHostCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
3244 }
3245
3246 pVCpu->hmr0.s.fForceTLBFlush = false;
3247 pVCpu->hmr0.s.cTlbFlushes = pHostCpu->cTlbFlushes;
3248 pVCpu->hmr0.s.uCurrentAsid = pHostCpu->uCurrentAsid;
3249 if (pHostCpu->fFlushAsidBeforeUse)
3250 {
3251 if (pVM->hmr0.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_SINGLE_CONTEXT)
3252 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_SINGLE_CONTEXT, 0 /* GCPtr */);
3253 else if (pVM->hmr0.s.vmx.enmTlbFlushVpid == VMXTLBFLUSHVPID_ALL_CONTEXTS)
3254 {
3255 hmR0VmxFlushVpid(pVCpu, VMXTLBFLUSHVPID_ALL_CONTEXTS, 0 /* GCPtr */);
3256 pHostCpu->fFlushAsidBeforeUse = false;
3257 }
3258 else
3259 {
3260 /* hmR0VmxSetupTaggedTlb() ensures we never get here. Paranoia. */
3261 AssertMsgFailed(("Unsupported VPID-flush context type.\n"));
3262 }
3263 }
3264 }
3265
3266 AssertMsg(pVCpu->hmr0.s.cTlbFlushes == pHostCpu->cTlbFlushes,
3267 ("Flush count mismatch for cpu %d (%u vs %u)\n", pHostCpu->idCpu, pVCpu->hmr0.s.cTlbFlushes, pHostCpu->cTlbFlushes));
3268 AssertMsg(pHostCpu->uCurrentAsid >= 1 && pHostCpu->uCurrentAsid < g_uHmMaxAsid,
3269 ("Cpu[%u] uCurrentAsid=%u cTlbFlushes=%u pVCpu->idLastCpu=%u pVCpu->cTlbFlushes=%u\n", pHostCpu->idCpu,
3270 pHostCpu->uCurrentAsid, pHostCpu->cTlbFlushes, pVCpu->hmr0.s.idLastCpu, pVCpu->hmr0.s.cTlbFlushes));
3271 AssertMsg(pVCpu->hmr0.s.uCurrentAsid >= 1 && pVCpu->hmr0.s.uCurrentAsid < g_uHmMaxAsid,
3272 ("Cpu[%u] pVCpu->uCurrentAsid=%u\n", pHostCpu->idCpu, pVCpu->hmr0.s.uCurrentAsid));
3273
3274 int rc = VMXWriteVmcs16(VMX_VMCS16_VPID, pVCpu->hmr0.s.uCurrentAsid);
3275 AssertRC(rc);
3276}
3277
3278
3279/**
3280 * Flushes the guest TLB entry based on CPU capabilities.
3281 *
3282 * @param pHostCpu The HM physical-CPU structure.
3283 * @param pVCpu The cross context virtual CPU structure.
3284 * @param pVmcsInfo The VMCS info. object.
3285 *
3286 * @remarks Called with interrupts disabled.
3287 */
3288static void hmR0VmxFlushTaggedTlb(PHMPHYSCPU pHostCpu, PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3289{
3290#ifdef HMVMX_ALWAYS_FLUSH_TLB
3291 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
3292#endif
3293 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3294 switch (pVM->hmr0.s.vmx.enmTlbFlushType)
3295 {
3296 case VMXTLBFLUSHTYPE_EPT_VPID: hmR0VmxFlushTaggedTlbBoth(pHostCpu, pVCpu, pVmcsInfo); break;
3297 case VMXTLBFLUSHTYPE_EPT: hmR0VmxFlushTaggedTlbEpt(pHostCpu, pVCpu, pVmcsInfo); break;
3298 case VMXTLBFLUSHTYPE_VPID: hmR0VmxFlushTaggedTlbVpid(pHostCpu, pVCpu); break;
3299 case VMXTLBFLUSHTYPE_NONE: hmR0VmxFlushTaggedTlbNone(pHostCpu, pVCpu); break;
3300 default:
3301 AssertMsgFailed(("Invalid flush-tag function identifier\n"));
3302 break;
3303 }
3304 /* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
3305}
3306
3307
3308/**
3309 * Sets up the appropriate tagged TLB-flush level and handler for flushing guest
3310 * TLB entries from the host TLB before VM-entry.
3311 *
3312 * @returns VBox status code.
3313 * @param pVM The cross context VM structure.
3314 */
3315static int hmR0VmxSetupTaggedTlb(PVMCC pVM)
3316{
3317 /*
3318 * Determine optimal flush type for nested paging.
3319 * We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup
3320 * unrestricted guest execution (see hmR3InitFinalizeR0()).
3321 */
3322 if (pVM->hmr0.s.fNestedPaging)
3323 {
3324 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT)
3325 {
3326 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT)
3327 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_SINGLE_CONTEXT;
3328 else if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
3329 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_ALL_CONTEXTS;
3330 else
3331 {
3332 /* Shouldn't happen. EPT is supported but no suitable flush-types supported. */
3333 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3334 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED;
3335 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3336 }
3337
3338 /* Make sure the write-back cacheable memory type for EPT is supported. */
3339 if (RT_UNLIKELY(!(g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_MEMTYPE_WB)))
3340 {
3341 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3342 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_MEM_TYPE_NOT_WB;
3343 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3344 }
3345
3346 /* EPT requires a page-walk length of 4. */
3347 if (RT_UNLIKELY(!(g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4)))
3348 {
3349 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3350 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED;
3351 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3352 }
3353 }
3354 else
3355 {
3356 /* Shouldn't happen. EPT is supported but INVEPT instruction is not supported. */
3357 pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NOT_SUPPORTED;
3358 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_EPT_INVEPT_UNAVAILABLE;
3359 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3360 }
3361 }
3362
3363 /*
3364 * Determine optimal flush type for VPID.
3365 */
3366 if (pVM->hmr0.s.vmx.fVpid)
3367 {
3368 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID)
3369 {
3370 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT)
3371 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_SINGLE_CONTEXT;
3372 else if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS)
3373 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_ALL_CONTEXTS;
3374 else
3375 {
3376 /* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
3377 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR)
3378 LogRelFunc(("Only INDIV_ADDR supported. Ignoring VPID.\n"));
3379 if (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
3380 LogRelFunc(("Only SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
3381 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3382 pVM->hmr0.s.vmx.fVpid = false;
3383 }
3384 }
3385 else
3386 {
3387 /* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
3388 Log4Func(("VPID supported without INVEPT support. Ignoring VPID.\n"));
3389 pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NOT_SUPPORTED;
3390 pVM->hmr0.s.vmx.fVpid = false;
3391 }
3392 }
3393
3394 /*
3395 * Setup the handler for flushing tagged-TLBs.
3396 */
3397 if (pVM->hmr0.s.fNestedPaging && pVM->hmr0.s.vmx.fVpid)
3398 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT_VPID;
3399 else if (pVM->hmr0.s.fNestedPaging)
3400 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_EPT;
3401 else if (pVM->hmr0.s.vmx.fVpid)
3402 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_VPID;
3403 else
3404 pVM->hmr0.s.vmx.enmTlbFlushType = VMXTLBFLUSHTYPE_NONE;
3405
3406
3407 /*
3408 * Copy out the result to ring-3.
3409 */
3410 pVM->hm.s.ForR3.vmx.fVpid = pVM->hmr0.s.vmx.fVpid;
3411 pVM->hm.s.ForR3.vmx.enmTlbFlushType = pVM->hmr0.s.vmx.enmTlbFlushType;
3412 pVM->hm.s.ForR3.vmx.enmTlbFlushEpt = pVM->hmr0.s.vmx.enmTlbFlushEpt;
3413 pVM->hm.s.ForR3.vmx.enmTlbFlushVpid = pVM->hmr0.s.vmx.enmTlbFlushVpid;
3414 return VINF_SUCCESS;
3415}
3416
3417
3418/**
3419 * Sets up the LBR MSR ranges based on the host CPU.
3420 *
3421 * @returns VBox status code.
3422 * @param pVM The cross context VM structure.
3423 */
3424static int hmR0VmxSetupLbrMsrRange(PVMCC pVM)
3425{
3426 Assert(pVM->hmr0.s.vmx.fLbr);
3427 uint32_t idLbrFromIpMsrFirst;
3428 uint32_t idLbrFromIpMsrLast;
3429 uint32_t idLbrToIpMsrFirst;
3430 uint32_t idLbrToIpMsrLast;
3431 uint32_t idLbrTosMsr;
3432
3433 /*
3434 * Determine the LBR MSRs supported for this host CPU family and model.
3435 *
3436 * See Intel spec. 17.4.8 "LBR Stack".
3437 * See Intel "Model-Specific Registers" spec.
3438 */
3439 uint32_t const uFamilyModel = (pVM->cpum.ro.HostFeatures.uFamily << 8)
3440 | pVM->cpum.ro.HostFeatures.uModel;
3441 switch (uFamilyModel)
3442 {
3443 case 0x0f01: case 0x0f02:
3444 idLbrFromIpMsrFirst = MSR_P4_LASTBRANCH_0;
3445 idLbrFromIpMsrLast = MSR_P4_LASTBRANCH_3;
3446 idLbrToIpMsrFirst = 0x0;
3447 idLbrToIpMsrLast = 0x0;
3448 idLbrTosMsr = MSR_P4_LASTBRANCH_TOS;
3449 break;
3450
3451 case 0x065c: case 0x065f: case 0x064e: case 0x065e: case 0x068e:
3452 case 0x069e: case 0x0655: case 0x0666: case 0x067a: case 0x0667:
3453 case 0x066a: case 0x066c: case 0x067d: case 0x067e:
3454 idLbrFromIpMsrFirst = MSR_LASTBRANCH_0_FROM_IP;
3455 idLbrFromIpMsrLast = MSR_LASTBRANCH_31_FROM_IP;
3456 idLbrToIpMsrFirst = MSR_LASTBRANCH_0_TO_IP;
3457 idLbrToIpMsrLast = MSR_LASTBRANCH_31_TO_IP;
3458 idLbrTosMsr = MSR_LASTBRANCH_TOS;
3459 break;
3460
3461 case 0x063d: case 0x0647: case 0x064f: case 0x0656: case 0x063c:
3462 case 0x0645: case 0x0646: case 0x063f: case 0x062a: case 0x062d:
3463 case 0x063a: case 0x063e: case 0x061a: case 0x061e: case 0x061f:
3464 case 0x062e: case 0x0625: case 0x062c: case 0x062f:
3465 idLbrFromIpMsrFirst = MSR_LASTBRANCH_0_FROM_IP;
3466 idLbrFromIpMsrLast = MSR_LASTBRANCH_15_FROM_IP;
3467 idLbrToIpMsrFirst = MSR_LASTBRANCH_0_TO_IP;
3468 idLbrToIpMsrLast = MSR_LASTBRANCH_15_TO_IP;
3469 idLbrTosMsr = MSR_LASTBRANCH_TOS;
3470 break;
3471
3472 case 0x0617: case 0x061d: case 0x060f:
3473 idLbrFromIpMsrFirst = MSR_CORE2_LASTBRANCH_0_FROM_IP;
3474 idLbrFromIpMsrLast = MSR_CORE2_LASTBRANCH_3_FROM_IP;
3475 idLbrToIpMsrFirst = MSR_CORE2_LASTBRANCH_0_TO_IP;
3476 idLbrToIpMsrLast = MSR_CORE2_LASTBRANCH_3_TO_IP;
3477 idLbrTosMsr = MSR_CORE2_LASTBRANCH_TOS;
3478 break;
3479
3480 /* Atom and related microarchitectures we don't care about:
3481 case 0x0637: case 0x064a: case 0x064c: case 0x064d: case 0x065a:
3482 case 0x065d: case 0x061c: case 0x0626: case 0x0627: case 0x0635:
3483 case 0x0636: */
3484 /* All other CPUs: */
3485 default:
3486 {
3487 LogRelFunc(("Could not determine LBR stack size for the CPU model %#x\n", uFamilyModel));
3488 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_LBR_STACK_SIZE_UNKNOWN;
3489 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3490 }
3491 }
3492
3493 /*
3494 * Validate.
3495 */
3496 uint32_t const cLbrStack = idLbrFromIpMsrLast - idLbrFromIpMsrFirst + 1;
3497 PCVMCPU pVCpu0 = VMCC_GET_CPU_0(pVM);
3498 AssertCompile( RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrFromIpMsr)
3499 == RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrToIpMsr));
3500 if (cLbrStack > RT_ELEMENTS(pVCpu0->hm.s.vmx.VmcsInfo.au64LbrFromIpMsr))
3501 {
3502 LogRelFunc(("LBR stack size of the CPU (%u) exceeds our buffer size\n", cLbrStack));
3503 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_LBR_STACK_SIZE_OVERFLOW;
3504 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3505 }
3506 NOREF(pVCpu0);
3507
3508 /*
3509 * Update the LBR info. to the VM struct. for use later.
3510 */
3511 pVM->hmr0.s.vmx.idLbrTosMsr = idLbrTosMsr;
3512
3513 pVM->hm.s.ForR3.vmx.idLbrFromIpMsrFirst = pVM->hmr0.s.vmx.idLbrFromIpMsrFirst = idLbrFromIpMsrFirst;
3514 pVM->hm.s.ForR3.vmx.idLbrFromIpMsrLast = pVM->hmr0.s.vmx.idLbrFromIpMsrLast = idLbrFromIpMsrLast;
3515
3516 pVM->hm.s.ForR3.vmx.idLbrToIpMsrFirst = pVM->hmr0.s.vmx.idLbrToIpMsrFirst = idLbrToIpMsrFirst;
3517 pVM->hm.s.ForR3.vmx.idLbrToIpMsrLast = pVM->hmr0.s.vmx.idLbrToIpMsrLast = idLbrToIpMsrLast;
3518 return VINF_SUCCESS;
3519}
3520
3521
3522#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3523/**
3524 * Sets up the shadow VMCS fields arrays.
3525 *
3526 * This function builds arrays of VMCS fields to sync the shadow VMCS later while
3527 * executing the guest.
3528 *
3529 * @returns VBox status code.
3530 * @param pVM The cross context VM structure.
3531 */
3532static int hmR0VmxSetupShadowVmcsFieldsArrays(PVMCC pVM)
3533{
3534 /*
3535 * Paranoia. Ensure we haven't exposed the VMWRITE-All VMX feature to the guest
3536 * when the host does not support it.
3537 */
3538 bool const fGstVmwriteAll = pVM->cpum.ro.GuestFeatures.fVmxVmwriteAll;
3539 if ( !fGstVmwriteAll
3540 || (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL))
3541 { /* likely. */ }
3542 else
3543 {
3544 LogRelFunc(("VMX VMWRITE-All feature exposed to the guest but host CPU does not support it!\n"));
3545 VMCC_GET_CPU_0(pVM)->hm.s.u32HMError = VMX_UFC_GST_HOST_VMWRITE_ALL;
3546 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3547 }
3548
3549 uint32_t const cVmcsFields = RT_ELEMENTS(g_aVmcsFields);
3550 uint32_t cRwFields = 0;
3551 uint32_t cRoFields = 0;
3552 for (uint32_t i = 0; i < cVmcsFields; i++)
3553 {
3554 VMXVMCSFIELD VmcsField;
3555 VmcsField.u = g_aVmcsFields[i];
3556
3557 /*
3558 * We will be writing "FULL" (64-bit) fields while syncing the shadow VMCS.
3559 * Therefore, "HIGH" (32-bit portion of 64-bit) fields must not be included
3560 * in the shadow VMCS fields array as they would be redundant.
3561 *
3562 * If the VMCS field depends on a CPU feature that is not exposed to the guest,
3563 * we must not include it in the shadow VMCS fields array. Guests attempting to
3564 * VMREAD/VMWRITE such VMCS fields would cause a VM-exit and we shall emulate
3565 * the required behavior.
3566 */
3567 if ( VmcsField.n.fAccessType == VMX_VMCSFIELD_ACCESS_FULL
3568 && CPUMIsGuestVmxVmcsFieldValid(pVM, VmcsField.u))
3569 {
3570 /*
3571 * Read-only fields are placed in a separate array so that while syncing shadow
3572 * VMCS fields later (which is more performance critical) we can avoid branches.
3573 *
3574 * However, if the guest can write to all fields (including read-only fields),
3575 * we treat it a as read/write field. Otherwise, writing to these fields would
3576 * cause a VMWRITE instruction error while syncing the shadow VMCS.
3577 */
3578 if ( fGstVmwriteAll
3579 || !VMXIsVmcsFieldReadOnly(VmcsField.u))
3580 pVM->hmr0.s.vmx.paShadowVmcsFields[cRwFields++] = VmcsField.u;
3581 else
3582 pVM->hmr0.s.vmx.paShadowVmcsRoFields[cRoFields++] = VmcsField.u;
3583 }
3584 }
3585
3586 /* Update the counts. */
3587 pVM->hmr0.s.vmx.cShadowVmcsFields = cRwFields;
3588 pVM->hmr0.s.vmx.cShadowVmcsRoFields = cRoFields;
3589 return VINF_SUCCESS;
3590}
3591
3592
3593/**
3594 * Sets up the VMREAD and VMWRITE bitmaps.
3595 *
3596 * @param pVM The cross context VM structure.
3597 */
3598static void hmR0VmxSetupVmreadVmwriteBitmaps(PVMCC pVM)
3599{
3600 /*
3601 * By default, ensure guest attempts to access any VMCS fields cause VM-exits.
3602 */
3603 uint32_t const cbBitmap = X86_PAGE_4K_SIZE;
3604 uint8_t *pbVmreadBitmap = (uint8_t *)pVM->hmr0.s.vmx.pvVmreadBitmap;
3605 uint8_t *pbVmwriteBitmap = (uint8_t *)pVM->hmr0.s.vmx.pvVmwriteBitmap;
3606 ASMMemFill32(pbVmreadBitmap, cbBitmap, UINT32_C(0xffffffff));
3607 ASMMemFill32(pbVmwriteBitmap, cbBitmap, UINT32_C(0xffffffff));
3608
3609 /*
3610 * Skip intercepting VMREAD/VMWRITE to guest read/write fields in the
3611 * VMREAD and VMWRITE bitmaps.
3612 */
3613 {
3614 uint32_t const *paShadowVmcsFields = pVM->hmr0.s.vmx.paShadowVmcsFields;
3615 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
3616 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
3617 {
3618 uint32_t const uVmcsField = paShadowVmcsFields[i];
3619 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3620 Assert(uVmcsField >> 3 < cbBitmap);
3621 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3622 ASMBitClear(pbVmwriteBitmap + (uVmcsField >> 3), uVmcsField & 7);
3623 }
3624 }
3625
3626 /*
3627 * Skip intercepting VMREAD for guest read-only fields in the VMREAD bitmap
3628 * if the host supports VMWRITE to all supported VMCS fields.
3629 */
3630 if (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL)
3631 {
3632 uint32_t const *paShadowVmcsRoFields = pVM->hmr0.s.vmx.paShadowVmcsRoFields;
3633 uint32_t const cShadowVmcsRoFields = pVM->hmr0.s.vmx.cShadowVmcsRoFields;
3634 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
3635 {
3636 uint32_t const uVmcsField = paShadowVmcsRoFields[i];
3637 Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
3638 Assert(uVmcsField >> 3 < cbBitmap);
3639 ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
3640 }
3641 }
3642}
3643#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
3644
3645
3646/**
3647 * Sets up the virtual-APIC page address for the VMCS.
3648 *
3649 * @param pVmcsInfo The VMCS info. object.
3650 */
3651DECLINLINE(void) hmR0VmxSetupVmcsVirtApicAddr(PCVMXVMCSINFO pVmcsInfo)
3652{
3653 RTHCPHYS const HCPhysVirtApic = pVmcsInfo->HCPhysVirtApic;
3654 Assert(HCPhysVirtApic != NIL_RTHCPHYS);
3655 Assert(!(HCPhysVirtApic & 0xfff)); /* Bits 11:0 MBZ. */
3656 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
3657 AssertRC(rc);
3658}
3659
3660
3661/**
3662 * Sets up the MSR-bitmap address for the VMCS.
3663 *
3664 * @param pVmcsInfo The VMCS info. object.
3665 */
3666DECLINLINE(void) hmR0VmxSetupVmcsMsrBitmapAddr(PCVMXVMCSINFO pVmcsInfo)
3667{
3668 RTHCPHYS const HCPhysMsrBitmap = pVmcsInfo->HCPhysMsrBitmap;
3669 Assert(HCPhysMsrBitmap != NIL_RTHCPHYS);
3670 Assert(!(HCPhysMsrBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3671 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_MSR_BITMAP_FULL, HCPhysMsrBitmap);
3672 AssertRC(rc);
3673}
3674
3675
3676/**
3677 * Sets up the APIC-access page address for the VMCS.
3678 *
3679 * @param pVCpu The cross context virtual CPU structure.
3680 */
3681DECLINLINE(void) hmR0VmxSetupVmcsApicAccessAddr(PVMCPUCC pVCpu)
3682{
3683 RTHCPHYS const HCPhysApicAccess = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysApicAccess;
3684 Assert(HCPhysApicAccess != NIL_RTHCPHYS);
3685 Assert(!(HCPhysApicAccess & 0xfff)); /* Bits 11:0 MBZ. */
3686 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
3687 AssertRC(rc);
3688}
3689
3690#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
3691
3692/**
3693 * Sets up the VMREAD bitmap address for the VMCS.
3694 *
3695 * @param pVCpu The cross context virtual CPU structure.
3696 */
3697DECLINLINE(void) hmR0VmxSetupVmcsVmreadBitmapAddr(PVMCPUCC pVCpu)
3698{
3699 RTHCPHYS const HCPhysVmreadBitmap = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysVmreadBitmap;
3700 Assert(HCPhysVmreadBitmap != NIL_RTHCPHYS);
3701 Assert(!(HCPhysVmreadBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3702 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL, HCPhysVmreadBitmap);
3703 AssertRC(rc);
3704}
3705
3706
3707/**
3708 * Sets up the VMWRITE bitmap address for the VMCS.
3709 *
3710 * @param pVCpu The cross context virtual CPU structure.
3711 */
3712DECLINLINE(void) hmR0VmxSetupVmcsVmwriteBitmapAddr(PVMCPUCC pVCpu)
3713{
3714 RTHCPHYS const HCPhysVmwriteBitmap = pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.HCPhysVmwriteBitmap;
3715 Assert(HCPhysVmwriteBitmap != NIL_RTHCPHYS);
3716 Assert(!(HCPhysVmwriteBitmap & 0xfff)); /* Bits 11:0 MBZ. */
3717 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL, HCPhysVmwriteBitmap);
3718 AssertRC(rc);
3719}
3720
3721#endif
3722
3723/**
3724 * Sets up the VM-entry MSR load, VM-exit MSR-store and VM-exit MSR-load addresses
3725 * in the VMCS.
3726 *
3727 * @returns VBox status code.
3728 * @param pVmcsInfo The VMCS info. object.
3729 */
3730DECLINLINE(int) hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(PVMXVMCSINFO pVmcsInfo)
3731{
3732 RTHCPHYS const HCPhysGuestMsrLoad = pVmcsInfo->HCPhysGuestMsrLoad;
3733 Assert(HCPhysGuestMsrLoad != NIL_RTHCPHYS);
3734 Assert(!(HCPhysGuestMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3735
3736 RTHCPHYS const HCPhysGuestMsrStore = pVmcsInfo->HCPhysGuestMsrStore;
3737 Assert(HCPhysGuestMsrStore != NIL_RTHCPHYS);
3738 Assert(!(HCPhysGuestMsrStore & 0xf)); /* Bits 3:0 MBZ. */
3739
3740 RTHCPHYS const HCPhysHostMsrLoad = pVmcsInfo->HCPhysHostMsrLoad;
3741 Assert(HCPhysHostMsrLoad != NIL_RTHCPHYS);
3742 Assert(!(HCPhysHostMsrLoad & 0xf)); /* Bits 3:0 MBZ. */
3743
3744 int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL, HCPhysGuestMsrLoad); AssertRC(rc);
3745 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL, HCPhysGuestMsrStore); AssertRC(rc);
3746 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL, HCPhysHostMsrLoad); AssertRC(rc);
3747 return VINF_SUCCESS;
3748}
3749
3750
3751/**
3752 * Sets up MSR permissions in the MSR bitmap of a VMCS info. object.
3753 *
3754 * @param pVCpu The cross context virtual CPU structure.
3755 * @param pVmcsInfo The VMCS info. object.
3756 */
3757static void hmR0VmxSetupVmcsMsrPermissions(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3758{
3759 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS);
3760
3761 /*
3762 * By default, ensure guest attempts to access any MSR cause VM-exits.
3763 * This shall later be relaxed for specific MSRs as necessary.
3764 *
3765 * Note: For nested-guests, the entire bitmap will be merged prior to
3766 * executing the nested-guest using hardware-assisted VMX and hence there
3767 * is no need to perform this operation. See hmR0VmxMergeMsrBitmapNested.
3768 */
3769 Assert(pVmcsInfo->pvMsrBitmap);
3770 ASMMemFill32(pVmcsInfo->pvMsrBitmap, X86_PAGE_4K_SIZE, UINT32_C(0xffffffff));
3771
3772 /*
3773 * The guest can access the following MSRs (read, write) without causing
3774 * VM-exits; they are loaded/stored automatically using fields in the VMCS.
3775 */
3776 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3777 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_CS, VMXMSRPM_ALLOW_RD_WR);
3778 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_ESP, VMXMSRPM_ALLOW_RD_WR);
3779 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SYSENTER_EIP, VMXMSRPM_ALLOW_RD_WR);
3780 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3781 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_FS_BASE, VMXMSRPM_ALLOW_RD_WR);
3782
3783 /*
3784 * The IA32_PRED_CMD and IA32_FLUSH_CMD MSRs are write-only and has no state
3785 * associated with then. We never need to intercept access (writes need to be
3786 * executed without causing a VM-exit, reads will #GP fault anyway).
3787 *
3788 * The IA32_SPEC_CTRL MSR is read/write and has state. We allow the guest to
3789 * read/write them. We swap the guest/host MSR value using the
3790 * auto-load/store MSR area.
3791 */
3792 if (pVM->cpum.ro.GuestFeatures.fIbpb)
3793 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_PRED_CMD, VMXMSRPM_ALLOW_RD_WR);
3794 if (pVM->cpum.ro.GuestFeatures.fFlushCmd)
3795 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_FLUSH_CMD, VMXMSRPM_ALLOW_RD_WR);
3796 if (pVM->cpum.ro.GuestFeatures.fIbrs)
3797 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_IA32_SPEC_CTRL, VMXMSRPM_ALLOW_RD_WR);
3798
3799 /*
3800 * Allow full read/write access for the following MSRs (mandatory for VT-x)
3801 * required for 64-bit guests.
3802 */
3803 if (pVM->hmr0.s.fAllow64BitGuests)
3804 {
3805 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_LSTAR, VMXMSRPM_ALLOW_RD_WR);
3806 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K6_STAR, VMXMSRPM_ALLOW_RD_WR);
3807 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_SF_MASK, VMXMSRPM_ALLOW_RD_WR);
3808 hmR0VmxSetMsrPermission(pVCpu, pVmcsInfo, false, MSR_K8_KERNEL_GS_BASE, VMXMSRPM_ALLOW_RD_WR);
3809 }
3810
3811 /*
3812 * IA32_EFER MSR is always intercepted, see @bugref{9180#c37}.
3813 */
3814#ifdef VBOX_STRICT
3815 Assert(pVmcsInfo->pvMsrBitmap);
3816 uint32_t const fMsrpmEfer = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, MSR_K6_EFER);
3817 Assert(fMsrpmEfer == VMXMSRPM_EXIT_RD_WR);
3818#endif
3819}
3820
3821
3822/**
3823 * Sets up pin-based VM-execution controls in the VMCS.
3824 *
3825 * @returns VBox status code.
3826 * @param pVCpu The cross context virtual CPU structure.
3827 * @param pVmcsInfo The VMCS info. object.
3828 */
3829static int hmR0VmxSetupVmcsPinCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3830{
3831 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3832 uint32_t fVal = g_HmMsrs.u.vmx.PinCtls.n.allowed0; /* Bits set here must always be set. */
3833 uint32_t const fZap = g_HmMsrs.u.vmx.PinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
3834
3835 fVal |= VMX_PIN_CTLS_EXT_INT_EXIT /* External interrupts cause a VM-exit. */
3836 | VMX_PIN_CTLS_NMI_EXIT; /* Non-maskable interrupts (NMIs) cause a VM-exit. */
3837
3838 if (g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_VIRT_NMI)
3839 fVal |= VMX_PIN_CTLS_VIRT_NMI; /* Use virtual NMIs and virtual-NMI blocking features. */
3840
3841 /* Enable the VMX-preemption timer. */
3842 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
3843 {
3844 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_PREEMPT_TIMER);
3845 fVal |= VMX_PIN_CTLS_PREEMPT_TIMER;
3846 }
3847
3848#if 0
3849 /* Enable posted-interrupt processing. */
3850 if (pVM->hm.s.fPostedIntrs)
3851 {
3852 Assert(g_HmMsrs.u.vmx.PinCtls.n.allowed1 & VMX_PIN_CTLS_POSTED_INT);
3853 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT);
3854 fVal |= VMX_PIN_CTLS_POSTED_INT;
3855 }
3856#endif
3857
3858 if ((fVal & fZap) != fVal)
3859 {
3860 LogRelFunc(("Invalid pin-based VM-execution controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3861 g_HmMsrs.u.vmx.PinCtls.n.allowed0, fVal, fZap));
3862 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PIN_EXEC;
3863 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3864 }
3865
3866 /* Commit it to the VMCS and update our cache. */
3867 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, fVal);
3868 AssertRC(rc);
3869 pVmcsInfo->u32PinCtls = fVal;
3870
3871 return VINF_SUCCESS;
3872}
3873
3874
3875/**
3876 * Sets up secondary processor-based VM-execution controls in the VMCS.
3877 *
3878 * @returns VBox status code.
3879 * @param pVCpu The cross context virtual CPU structure.
3880 * @param pVmcsInfo The VMCS info. object.
3881 */
3882static int hmR0VmxSetupVmcsProcCtls2(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3883{
3884 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3885 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls2.n.allowed0; /* Bits set here must be set in the VMCS. */
3886 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3887
3888 /* WBINVD causes a VM-exit. */
3889 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_WBINVD_EXIT)
3890 fVal |= VMX_PROC_CTLS2_WBINVD_EXIT;
3891
3892 /* Enable EPT (aka nested-paging). */
3893 if (pVM->hmr0.s.fNestedPaging)
3894 fVal |= VMX_PROC_CTLS2_EPT;
3895
3896 /* Enable the INVPCID instruction if we expose it to the guest and is supported
3897 by the hardware. Without this, guest executing INVPCID would cause a #UD. */
3898 if ( pVM->cpum.ro.GuestFeatures.fInvpcid
3899 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_INVPCID))
3900 fVal |= VMX_PROC_CTLS2_INVPCID;
3901
3902 /* Enable VPID. */
3903 if (pVM->hmr0.s.vmx.fVpid)
3904 fVal |= VMX_PROC_CTLS2_VPID;
3905
3906 /* Enable unrestricted guest execution. */
3907 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
3908 fVal |= VMX_PROC_CTLS2_UNRESTRICTED_GUEST;
3909
3910#if 0
3911 if (pVM->hm.s.fVirtApicRegs)
3912 {
3913 /* Enable APIC-register virtualization. */
3914 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT);
3915 fVal |= VMX_PROC_CTLS2_APIC_REG_VIRT;
3916
3917 /* Enable virtual-interrupt delivery. */
3918 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY);
3919 fVal |= VMX_PROC_CTLS2_VIRT_INTR_DELIVERY;
3920 }
3921#endif
3922
3923 /* Virtualize-APIC accesses if supported by the CPU. The virtual-APIC page is
3924 where the TPR shadow resides. */
3925 /** @todo VIRT_X2APIC support, it's mutually exclusive with this. So must be
3926 * done dynamically. */
3927 if (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
3928 {
3929 fVal |= VMX_PROC_CTLS2_VIRT_APIC_ACCESS;
3930 hmR0VmxSetupVmcsApicAccessAddr(pVCpu);
3931 }
3932
3933 /* Enable the RDTSCP instruction if we expose it to the guest and is supported
3934 by the hardware. Without this, guest executing RDTSCP would cause a #UD. */
3935 if ( pVM->cpum.ro.GuestFeatures.fRdTscP
3936 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_RDTSCP))
3937 fVal |= VMX_PROC_CTLS2_RDTSCP;
3938
3939 /* Enable Pause-Loop exiting. */
3940 if ( (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT)
3941 && pVM->hm.s.vmx.cPleGapTicks
3942 && pVM->hm.s.vmx.cPleWindowTicks)
3943 {
3944 fVal |= VMX_PROC_CTLS2_PAUSE_LOOP_EXIT;
3945
3946 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, pVM->hm.s.vmx.cPleGapTicks); AssertRC(rc);
3947 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, pVM->hm.s.vmx.cPleWindowTicks); AssertRC(rc);
3948 }
3949
3950 if ((fVal & fZap) != fVal)
3951 {
3952 LogRelFunc(("Invalid secondary processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
3953 g_HmMsrs.u.vmx.ProcCtls2.n.allowed0, fVal, fZap));
3954 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC2;
3955 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3956 }
3957
3958 /* Commit it to the VMCS and update our cache. */
3959 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, fVal);
3960 AssertRC(rc);
3961 pVmcsInfo->u32ProcCtls2 = fVal;
3962
3963 return VINF_SUCCESS;
3964}
3965
3966
3967/**
3968 * Sets up processor-based VM-execution controls in the VMCS.
3969 *
3970 * @returns VBox status code.
3971 * @param pVCpu The cross context virtual CPU structure.
3972 * @param pVmcsInfo The VMCS info. object.
3973 */
3974static int hmR0VmxSetupVmcsProcCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
3975{
3976 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3977 uint32_t fVal = g_HmMsrs.u.vmx.ProcCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
3978 uint32_t const fZap = g_HmMsrs.u.vmx.ProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
3979
3980 fVal |= VMX_PROC_CTLS_HLT_EXIT /* HLT causes a VM-exit. */
3981 | VMX_PROC_CTLS_USE_TSC_OFFSETTING /* Use TSC-offsetting. */
3982 | VMX_PROC_CTLS_MOV_DR_EXIT /* MOV DRx causes a VM-exit. */
3983 | VMX_PROC_CTLS_UNCOND_IO_EXIT /* All IO instructions cause a VM-exit. */
3984 | VMX_PROC_CTLS_RDPMC_EXIT /* RDPMC causes a VM-exit. */
3985 | VMX_PROC_CTLS_MONITOR_EXIT /* MONITOR causes a VM-exit. */
3986 | VMX_PROC_CTLS_MWAIT_EXIT; /* MWAIT causes a VM-exit. */
3987
3988 /* We toggle VMX_PROC_CTLS_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
3989 if ( !(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MOV_DR_EXIT)
3990 || (g_HmMsrs.u.vmx.ProcCtls.n.allowed0 & VMX_PROC_CTLS_MOV_DR_EXIT))
3991 {
3992 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_MOV_DRX_EXIT;
3993 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
3994 }
3995
3996 /* Without nested paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
3997 if (!pVM->hmr0.s.fNestedPaging)
3998 {
3999 Assert(!pVM->hmr0.s.vmx.fUnrestrictedGuest);
4000 fVal |= VMX_PROC_CTLS_INVLPG_EXIT
4001 | VMX_PROC_CTLS_CR3_LOAD_EXIT
4002 | VMX_PROC_CTLS_CR3_STORE_EXIT;
4003 }
4004
4005 /* Use TPR shadowing if supported by the CPU. */
4006 if ( PDMHasApic(pVM)
4007 && (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
4008 {
4009 fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* CR8 reads from the Virtual-APIC page. */
4010 /* CR8 writes cause a VM-exit based on TPR threshold. */
4011 Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
4012 Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
4013 hmR0VmxSetupVmcsVirtApicAddr(pVmcsInfo);
4014 }
4015 else
4016 {
4017 /* Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is
4018 invalid on 32-bit Intel CPUs. Set this control only for 64-bit guests. */
4019 if (pVM->hmr0.s.fAllow64BitGuests)
4020 fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT /* CR8 reads cause a VM-exit. */
4021 | VMX_PROC_CTLS_CR8_LOAD_EXIT; /* CR8 writes cause a VM-exit. */
4022 }
4023
4024 /* Use MSR-bitmaps if supported by the CPU. */
4025 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4026 {
4027 fVal |= VMX_PROC_CTLS_USE_MSR_BITMAPS;
4028 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
4029 }
4030
4031 /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
4032 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
4033 fVal |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
4034
4035 if ((fVal & fZap) != fVal)
4036 {
4037 LogRelFunc(("Invalid processor-based VM-execution controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
4038 g_HmMsrs.u.vmx.ProcCtls.n.allowed0, fVal, fZap));
4039 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_PROC_EXEC;
4040 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4041 }
4042
4043 /* Commit it to the VMCS and update our cache. */
4044 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, fVal);
4045 AssertRC(rc);
4046 pVmcsInfo->u32ProcCtls = fVal;
4047
4048 /* Set up MSR permissions that don't change through the lifetime of the VM. */
4049 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4050 hmR0VmxSetupVmcsMsrPermissions(pVCpu, pVmcsInfo);
4051
4052 /* Set up secondary processor-based VM-execution controls if the CPU supports it. */
4053 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
4054 return hmR0VmxSetupVmcsProcCtls2(pVCpu, pVmcsInfo);
4055
4056 /* Sanity check, should not really happen. */
4057 if (RT_LIKELY(!pVM->hmr0.s.vmx.fUnrestrictedGuest))
4058 { /* likely */ }
4059 else
4060 {
4061 pVCpu->hm.s.u32HMError = VMX_UFC_INVALID_UX_COMBO;
4062 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
4063 }
4064
4065 /* Old CPUs without secondary processor-based VM-execution controls would end up here. */
4066 return VINF_SUCCESS;
4067}
4068
4069
4070/**
4071 * Sets up miscellaneous (everything other than Pin, Processor and secondary
4072 * Processor-based VM-execution) control fields in the VMCS.
4073 *
4074 * @returns VBox status code.
4075 * @param pVCpu The cross context virtual CPU structure.
4076 * @param pVmcsInfo The VMCS info. object.
4077 */
4078static int hmR0VmxSetupVmcsMiscCtls(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4079{
4080#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4081 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUseVmcsShadowing)
4082 {
4083 hmR0VmxSetupVmcsVmreadBitmapAddr(pVCpu);
4084 hmR0VmxSetupVmcsVmwriteBitmapAddr(pVCpu);
4085 }
4086#endif
4087
4088 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
4089 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
4090 AssertRC(rc);
4091
4092 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
4093 if (RT_SUCCESS(rc))
4094 {
4095 uint64_t const u64Cr0Mask = hmR0VmxGetFixedCr0Mask(pVCpu);
4096 uint64_t const u64Cr4Mask = hmR0VmxGetFixedCr4Mask(pVCpu);
4097
4098 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask); AssertRC(rc);
4099 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask); AssertRC(rc);
4100
4101 pVmcsInfo->u64Cr0Mask = u64Cr0Mask;
4102 pVmcsInfo->u64Cr4Mask = u64Cr4Mask;
4103
4104 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fLbr)
4105 {
4106 rc = VMXWriteVmcsNw(VMX_VMCS64_GUEST_DEBUGCTL_FULL, MSR_IA32_DEBUGCTL_LBR);
4107 AssertRC(rc);
4108 }
4109 return VINF_SUCCESS;
4110 }
4111 else
4112 LogRelFunc(("Failed to initialize VMCS auto-load/store MSR addresses. rc=%Rrc\n", rc));
4113 return rc;
4114}
4115
4116
4117/**
4118 * Sets up the initial exception bitmap in the VMCS based on static conditions.
4119 *
4120 * We shall setup those exception intercepts that don't change during the
4121 * lifetime of the VM here. The rest are done dynamically while loading the
4122 * guest state.
4123 *
4124 * @param pVCpu The cross context virtual CPU structure.
4125 * @param pVmcsInfo The VMCS info. object.
4126 */
4127static void hmR0VmxSetupVmcsXcptBitmap(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
4128{
4129 /*
4130 * The following exceptions are always intercepted:
4131 *
4132 * #AC - To prevent the guest from hanging the CPU and for dealing with
4133 * split-lock detecting host configs.
4134 * #DB - To maintain the DR6 state even when intercepting DRx reads/writes and
4135 * recursive #DBs can cause a CPU hang.
4136 * #PF - To sync our shadow page tables when nested-paging is not used.
4137 */
4138 bool const fNestedPaging = pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging;
4139 uint32_t const uXcptBitmap = RT_BIT(X86_XCPT_AC)
4140 | RT_BIT(X86_XCPT_DB)
4141 | (fNestedPaging ? 0 : RT_BIT(X86_XCPT_PF));
4142
4143 /* Commit it to the VMCS. */
4144 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
4145 AssertRC(rc);
4146
4147 /* Update our cache of the exception bitmap. */
4148 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
4149}
4150
4151
4152#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4153/**
4154 * Sets up the VMCS for executing a nested-guest using hardware-assisted VMX.
4155 *
4156 * @returns VBox status code.
4157 * @param pVmcsInfo The VMCS info. object.
4158 */
4159static int hmR0VmxSetupVmcsCtlsNested(PVMXVMCSINFO pVmcsInfo)
4160{
4161 Assert(pVmcsInfo->u64VmcsLinkPtr == NIL_RTHCPHYS);
4162 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
4163 AssertRC(rc);
4164
4165 rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVmcsInfo);
4166 if (RT_SUCCESS(rc))
4167 {
4168 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_MSR_BITMAPS)
4169 hmR0VmxSetupVmcsMsrBitmapAddr(pVmcsInfo);
4170
4171 /* Paranoia - We've not yet initialized these, they shall be done while merging the VMCS. */
4172 Assert(!pVmcsInfo->u64Cr0Mask);
4173 Assert(!pVmcsInfo->u64Cr4Mask);
4174 return VINF_SUCCESS;
4175 }
4176 LogRelFunc(("Failed to set up the VMCS link pointer in the nested-guest VMCS. rc=%Rrc\n", rc));
4177 return rc;
4178}
4179#endif
4180
4181
4182/**
4183 * Sets pfnStartVm to the best suited variant.
4184 *
4185 * This must be called whenever anything changes relative to the hmR0VmXStartVm
4186 * variant selection:
4187 * - pVCpu->hm.s.fLoadSaveGuestXcr0
4188 * - HM_WSF_IBPB_ENTRY in pVCpu->hmr0.s.fWorldSwitcher
4189 * - HM_WSF_IBPB_EXIT in pVCpu->hmr0.s.fWorldSwitcher
4190 * - Perhaps: CPUMIsGuestFPUStateActive() (windows only)
4191 * - Perhaps: CPUMCTX.fXStateMask (windows only)
4192 *
4193 * We currently ASSUME that neither HM_WSF_IBPB_ENTRY nor HM_WSF_IBPB_EXIT
4194 * cannot be changed at runtime.
4195 */
4196static void hmR0VmxUpdateStartVmFunction(PVMCPUCC pVCpu)
4197{
4198 static const struct CLANGWORKAROUND { PFNHMVMXSTARTVM pfn; } s_aHmR0VmxStartVmFunctions[] =
4199 {
4200 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4201 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4202 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4203 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit },
4204 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4205 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4206 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4207 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit },
4208 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4209 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4210 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4211 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit },
4212 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4213 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4214 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4215 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit },
4216 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4217 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4218 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4219 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit },
4220 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4221 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4222 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4223 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit },
4224 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4225 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4226 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4227 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit },
4228 { hmR0VmxStartVm_SansXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4229 { hmR0VmxStartVm_WithXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4230 { hmR0VmxStartVm_SansXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4231 { hmR0VmxStartVm_WithXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit },
4232 };
4233 uintptr_t const idx = (pVCpu->hmr0.s.fLoadSaveGuestXcr0 ? 1 : 0)
4234 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_IBPB_ENTRY ? 2 : 0)
4235 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_L1D_ENTRY ? 4 : 0)
4236 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_MDS_ENTRY ? 8 : 0)
4237 | (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_IBPB_EXIT ? 16 : 0);
4238 PFNHMVMXSTARTVM const pfnStartVm = s_aHmR0VmxStartVmFunctions[idx].pfn;
4239 if (pVCpu->hmr0.s.vmx.pfnStartVm != pfnStartVm)
4240 pVCpu->hmr0.s.vmx.pfnStartVm = pfnStartVm;
4241}
4242
4243
4244/**
4245 * Selector FNHMSVMVMRUN implementation.
4246 */
4247static DECLCALLBACK(int) hmR0VmxStartVmSelector(PVMXVMCSINFO pVmcsInfo, PVMCPUCC pVCpu, bool fResume)
4248{
4249 hmR0VmxUpdateStartVmFunction(pVCpu);
4250 return pVCpu->hmr0.s.vmx.pfnStartVm(pVmcsInfo, pVCpu, fResume);
4251}
4252
4253
4254/**
4255 * Sets up the VMCS for executing a guest (or nested-guest) using hardware-assisted
4256 * VMX.
4257 *
4258 * @returns VBox status code.
4259 * @param pVCpu The cross context virtual CPU structure.
4260 * @param pVmcsInfo The VMCS info. object.
4261 * @param fIsNstGstVmcs Whether this is a nested-guest VMCS.
4262 */
4263static int hmR0VmxSetupVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, bool fIsNstGstVmcs)
4264{
4265 Assert(pVmcsInfo->pvVmcs);
4266 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4267
4268 /* Set the CPU specified revision identifier at the beginning of the VMCS structure. */
4269 *(uint32_t *)pVmcsInfo->pvVmcs = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
4270 const char * const pszVmcs = fIsNstGstVmcs ? "nested-guest VMCS" : "guest VMCS";
4271
4272 LogFlowFunc(("\n"));
4273
4274 /*
4275 * Initialize the VMCS using VMCLEAR before loading the VMCS.
4276 * See Intel spec. 31.6 "Preparation And Launching A Virtual Machine".
4277 */
4278 int rc = hmR0VmxClearVmcs(pVmcsInfo);
4279 if (RT_SUCCESS(rc))
4280 {
4281 rc = hmR0VmxLoadVmcs(pVmcsInfo);
4282 if (RT_SUCCESS(rc))
4283 {
4284 /*
4285 * Initialize the hardware-assisted VMX execution handler for guest and nested-guest VMCS.
4286 * The host is always 64-bit since we no longer support 32-bit hosts.
4287 * Currently we have just a single handler for all guest modes as well, see @bugref{6208#c73}.
4288 */
4289 if (!fIsNstGstVmcs)
4290 {
4291 rc = hmR0VmxSetupVmcsPinCtls(pVCpu, pVmcsInfo);
4292 if (RT_SUCCESS(rc))
4293 {
4294 rc = hmR0VmxSetupVmcsProcCtls(pVCpu, pVmcsInfo);
4295 if (RT_SUCCESS(rc))
4296 {
4297 rc = hmR0VmxSetupVmcsMiscCtls(pVCpu, pVmcsInfo);
4298 if (RT_SUCCESS(rc))
4299 {
4300 hmR0VmxSetupVmcsXcptBitmap(pVCpu, pVmcsInfo);
4301#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4302 /*
4303 * If a shadow VMCS is allocated for the VMCS info. object, initialize the
4304 * VMCS revision ID and shadow VMCS indicator bit. Also, clear the VMCS
4305 * making it fit for use when VMCS shadowing is later enabled.
4306 */
4307 if (pVmcsInfo->pvShadowVmcs)
4308 {
4309 VMXVMCSREVID VmcsRevId;
4310 VmcsRevId.u = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID);
4311 VmcsRevId.n.fIsShadowVmcs = 1;
4312 *(uint32_t *)pVmcsInfo->pvShadowVmcs = VmcsRevId.u;
4313 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
4314 if (RT_SUCCESS(rc))
4315 { /* likely */ }
4316 else
4317 LogRelFunc(("Failed to initialize shadow VMCS. rc=%Rrc\n", rc));
4318 }
4319#endif
4320 }
4321 else
4322 LogRelFunc(("Failed to setup miscellaneous controls. rc=%Rrc\n", rc));
4323 }
4324 else
4325 LogRelFunc(("Failed to setup processor-based VM-execution controls. rc=%Rrc\n", rc));
4326 }
4327 else
4328 LogRelFunc(("Failed to setup pin-based controls. rc=%Rrc\n", rc));
4329 }
4330 else
4331 {
4332#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4333 rc = hmR0VmxSetupVmcsCtlsNested(pVmcsInfo);
4334 if (RT_SUCCESS(rc))
4335 { /* likely */ }
4336 else
4337 LogRelFunc(("Failed to initialize nested-guest VMCS. rc=%Rrc\n", rc));
4338#else
4339 AssertFailed();
4340#endif
4341 }
4342 }
4343 else
4344 LogRelFunc(("Failed to load the %s. rc=%Rrc\n", rc, pszVmcs));
4345 }
4346 else
4347 LogRelFunc(("Failed to clear the %s. rc=%Rrc\n", rc, pszVmcs));
4348
4349 /* Sync any CPU internal VMCS data back into our VMCS in memory. */
4350 if (RT_SUCCESS(rc))
4351 {
4352 rc = hmR0VmxClearVmcs(pVmcsInfo);
4353 if (RT_SUCCESS(rc))
4354 { /* likely */ }
4355 else
4356 LogRelFunc(("Failed to clear the %s post setup. rc=%Rrc\n", rc, pszVmcs));
4357 }
4358
4359 /*
4360 * Update the last-error record both for failures and success, so we
4361 * can propagate the status code back to ring-3 for diagnostics.
4362 */
4363 hmR0VmxUpdateErrorRecord(pVCpu, rc);
4364 NOREF(pszVmcs);
4365 return rc;
4366}
4367
4368
4369/**
4370 * Does global VT-x initialization (called during module initialization).
4371 *
4372 * @returns VBox status code.
4373 */
4374VMMR0DECL(int) VMXR0GlobalInit(void)
4375{
4376#ifdef HMVMX_USE_FUNCTION_TABLE
4377 AssertCompile(VMX_EXIT_MAX + 1 == RT_ELEMENTS(g_aVMExitHandlers));
4378# ifdef VBOX_STRICT
4379 for (unsigned i = 0; i < RT_ELEMENTS(g_aVMExitHandlers); i++)
4380 Assert(g_aVMExitHandlers[i].pfn);
4381# endif
4382#endif
4383 return VINF_SUCCESS;
4384}
4385
4386
4387/**
4388 * Does global VT-x termination (called during module termination).
4389 */
4390VMMR0DECL(void) VMXR0GlobalTerm()
4391{
4392 /* Nothing to do currently. */
4393}
4394
4395
4396/**
4397 * Sets up and activates VT-x on the current CPU.
4398 *
4399 * @returns VBox status code.
4400 * @param pHostCpu The HM physical-CPU structure.
4401 * @param pVM The cross context VM structure. Can be
4402 * NULL after a host resume operation.
4403 * @param pvCpuPage Pointer to the VMXON region (can be NULL if @a
4404 * fEnabledByHost is @c true).
4405 * @param HCPhysCpuPage Physical address of the VMXON region (can be 0 if
4406 * @a fEnabledByHost is @c true).
4407 * @param fEnabledByHost Set if SUPR0EnableVTx() or similar was used to
4408 * enable VT-x on the host.
4409 * @param pHwvirtMsrs Pointer to the hardware-virtualization MSRs.
4410 */
4411VMMR0DECL(int) VMXR0EnableCpu(PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
4412 PCSUPHWVIRTMSRS pHwvirtMsrs)
4413{
4414 AssertPtr(pHostCpu);
4415 AssertPtr(pHwvirtMsrs);
4416 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4417
4418 /* Enable VT-x if it's not already enabled by the host. */
4419 if (!fEnabledByHost)
4420 {
4421 int rc = hmR0VmxEnterRootMode(pHostCpu, pVM, HCPhysCpuPage, pvCpuPage);
4422 if (RT_FAILURE(rc))
4423 return rc;
4424 }
4425
4426 /*
4427 * Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been
4428 * using EPTPs) so we don't retain any stale guest-physical mappings which won't get
4429 * invalidated when flushing by VPID.
4430 */
4431 if (pHwvirtMsrs->u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS)
4432 {
4433 hmR0VmxFlushEpt(NULL /* pVCpu */, NULL /* pVmcsInfo */, VMXTLBFLUSHEPT_ALL_CONTEXTS);
4434 pHostCpu->fFlushAsidBeforeUse = false;
4435 }
4436 else
4437 pHostCpu->fFlushAsidBeforeUse = true;
4438
4439 /* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}. */
4440 ++pHostCpu->cTlbFlushes;
4441
4442 return VINF_SUCCESS;
4443}
4444
4445
4446/**
4447 * Deactivates VT-x on the current CPU.
4448 *
4449 * @returns VBox status code.
4450 * @param pHostCpu The HM physical-CPU structure.
4451 * @param pvCpuPage Pointer to the VMXON region.
4452 * @param HCPhysCpuPage Physical address of the VMXON region.
4453 *
4454 * @remarks This function should never be called when SUPR0EnableVTx() or
4455 * similar was used to enable VT-x on the host.
4456 */
4457VMMR0DECL(int) VMXR0DisableCpu(PHMPHYSCPU pHostCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
4458{
4459 RT_NOREF2(pvCpuPage, HCPhysCpuPage);
4460
4461 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4462 return hmR0VmxLeaveRootMode(pHostCpu);
4463}
4464
4465
4466/**
4467 * Does per-VM VT-x initialization.
4468 *
4469 * @returns VBox status code.
4470 * @param pVM The cross context VM structure.
4471 */
4472VMMR0DECL(int) VMXR0InitVM(PVMCC pVM)
4473{
4474 AssertPtr(pVM);
4475 LogFlowFunc(("pVM=%p\n", pVM));
4476
4477 hmR0VmxStructsInit(pVM);
4478 int rc = hmR0VmxStructsAlloc(pVM);
4479 if (RT_FAILURE(rc))
4480 {
4481 LogRelFunc(("Failed to allocated VMX structures. rc=%Rrc\n", rc));
4482 return rc;
4483 }
4484
4485 /* Setup the crash dump page. */
4486#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4487 strcpy((char *)pVM->hmr0.s.vmx.pbScratch, "SCRATCH Magic");
4488 *(uint64_t *)(pVM->hmr0.s.vmx.pbScratch + 16) = UINT64_C(0xdeadbeefdeadbeef);
4489#endif
4490 return VINF_SUCCESS;
4491}
4492
4493
4494/**
4495 * Does per-VM VT-x termination.
4496 *
4497 * @returns VBox status code.
4498 * @param pVM The cross context VM structure.
4499 */
4500VMMR0DECL(int) VMXR0TermVM(PVMCC pVM)
4501{
4502 AssertPtr(pVM);
4503 LogFlowFunc(("pVM=%p\n", pVM));
4504
4505#ifdef VBOX_WITH_CRASHDUMP_MAGIC
4506 if (pVM->hmr0.s.vmx.pbScratch)
4507 RT_BZERO(pVM->hmr0.s.vmx.pbScratch, X86_PAGE_4K_SIZE);
4508#endif
4509 hmR0VmxStructsFree(pVM);
4510 return VINF_SUCCESS;
4511}
4512
4513
4514/**
4515 * Sets up the VM for execution using hardware-assisted VMX.
4516 * This function is only called once per-VM during initialization.
4517 *
4518 * @returns VBox status code.
4519 * @param pVM The cross context VM structure.
4520 */
4521VMMR0DECL(int) VMXR0SetupVM(PVMCC pVM)
4522{
4523 AssertPtr(pVM);
4524 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
4525
4526 LogFlowFunc(("pVM=%p\n", pVM));
4527
4528 /*
4529 * At least verify if VMX is enabled, since we can't check if we're in VMX root mode or not
4530 * without causing a #GP.
4531 */
4532 RTCCUINTREG const uHostCr4 = ASMGetCR4();
4533 if (RT_LIKELY(uHostCr4 & X86_CR4_VMXE))
4534 { /* likely */ }
4535 else
4536 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
4537
4538 /*
4539 * Check that nested paging is supported if enabled and copy over the flag to the
4540 * ring-0 only structure.
4541 */
4542 bool const fNestedPaging = pVM->hm.s.fNestedPagingCfg;
4543 AssertReturn( !fNestedPaging
4544 || (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_EPT), /** @todo use a ring-0 copy of ProcCtls2.n.allowed1 */
4545 VERR_INCOMPATIBLE_CONFIG);
4546 pVM->hmr0.s.fNestedPaging = fNestedPaging;
4547 pVM->hmr0.s.fAllow64BitGuests = pVM->hm.s.fAllow64BitGuestsCfg;
4548
4549 /*
4550 * Without unrestricted guest execution, pRealModeTSS and pNonPagingModeEPTPageTable *must*
4551 * always be allocated. We no longer support the highly unlikely case of unrestricted guest
4552 * without pRealModeTSS, see hmR3InitFinalizeR0Intel().
4553 */
4554 bool const fUnrestrictedGuest = pVM->hm.s.vmx.fUnrestrictedGuestCfg;
4555 AssertReturn( !fUnrestrictedGuest
4556 || ( (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST)
4557 && fNestedPaging),
4558 VERR_INCOMPATIBLE_CONFIG);
4559 if ( !fUnrestrictedGuest
4560 && ( !pVM->hm.s.vmx.pNonPagingModeEPTPageTable
4561 || !pVM->hm.s.vmx.pRealModeTSS))
4562 {
4563 LogRelFunc(("Invalid real-on-v86 state.\n"));
4564 return VERR_INTERNAL_ERROR;
4565 }
4566 pVM->hmr0.s.vmx.fUnrestrictedGuest = fUnrestrictedGuest;
4567
4568 /* Initialize these always, see hmR3InitFinalizeR0().*/
4569 pVM->hm.s.ForR3.vmx.enmTlbFlushEpt = pVM->hmr0.s.vmx.enmTlbFlushEpt = VMXTLBFLUSHEPT_NONE;
4570 pVM->hm.s.ForR3.vmx.enmTlbFlushVpid = pVM->hmr0.s.vmx.enmTlbFlushVpid = VMXTLBFLUSHVPID_NONE;
4571
4572 /* Setup the tagged-TLB flush handlers. */
4573 int rc = hmR0VmxSetupTaggedTlb(pVM);
4574 if (RT_FAILURE(rc))
4575 {
4576 LogRelFunc(("Failed to setup tagged TLB. rc=%Rrc\n", rc));
4577 return rc;
4578 }
4579
4580 /* Determine LBR capabilities. */
4581 pVM->hmr0.s.vmx.fLbr = pVM->hm.s.vmx.fLbrCfg;
4582 if (pVM->hmr0.s.vmx.fLbr)
4583 {
4584 rc = hmR0VmxSetupLbrMsrRange(pVM);
4585 if (RT_FAILURE(rc))
4586 {
4587 LogRelFunc(("Failed to setup LBR MSR range. rc=%Rrc\n", rc));
4588 return rc;
4589 }
4590 }
4591
4592#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4593 /* Setup the shadow VMCS fields array and VMREAD/VMWRITE bitmaps. */
4594 if (pVM->hmr0.s.vmx.fUseVmcsShadowing)
4595 {
4596 rc = hmR0VmxSetupShadowVmcsFieldsArrays(pVM);
4597 if (RT_SUCCESS(rc))
4598 hmR0VmxSetupVmreadVmwriteBitmaps(pVM);
4599 else
4600 {
4601 LogRelFunc(("Failed to setup shadow VMCS fields arrays. rc=%Rrc\n", rc));
4602 return rc;
4603 }
4604 }
4605#endif
4606
4607 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
4608 {
4609 PVMCPUCC pVCpu = VMCC_GET_CPU(pVM, idCpu);
4610 Log4Func(("pVCpu=%p idCpu=%RU32\n", pVCpu, pVCpu->idCpu));
4611
4612 pVCpu->hmr0.s.vmx.pfnStartVm = hmR0VmxStartVmSelector;
4613
4614 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfo, false /* fIsNstGstVmcs */);
4615 if (RT_SUCCESS(rc))
4616 {
4617#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4618 if (pVM->cpum.ro.GuestFeatures.fVmx)
4619 {
4620 rc = hmR0VmxSetupVmcs(pVCpu, &pVCpu->hmr0.s.vmx.VmcsInfoNstGst, true /* fIsNstGstVmcs */);
4621 if (RT_SUCCESS(rc))
4622 { /* likely */ }
4623 else
4624 {
4625 LogRelFunc(("Nested-guest VMCS setup failed. rc=%Rrc\n", rc));
4626 return rc;
4627 }
4628 }
4629#endif
4630 }
4631 else
4632 {
4633 LogRelFunc(("VMCS setup failed. rc=%Rrc\n", rc));
4634 return rc;
4635 }
4636 }
4637
4638 return VINF_SUCCESS;
4639}
4640
4641
4642/**
4643 * Saves the host control registers (CR0, CR3, CR4) into the host-state area in
4644 * the VMCS.
4645 * @returns CR4 for passing along to hmR0VmxExportHostSegmentRegs.
4646 */
4647static uint64_t hmR0VmxExportHostControlRegs(void)
4648{
4649 int rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR0, ASMGetCR0()); AssertRC(rc);
4650 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR3, ASMGetCR3()); AssertRC(rc);
4651 uint64_t uHostCr4 = ASMGetCR4();
4652 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_CR4, uHostCr4); AssertRC(rc);
4653 return uHostCr4;
4654}
4655
4656
4657/**
4658 * Saves the host segment registers and GDTR, IDTR, (TR, GS and FS bases) into
4659 * the host-state area in the VMCS.
4660 *
4661 * @returns VBox status code.
4662 * @param pVCpu The cross context virtual CPU structure.
4663 * @param uHostCr4 The host CR4 value.
4664 */
4665static int hmR0VmxExportHostSegmentRegs(PVMCPUCC pVCpu, uint64_t uHostCr4)
4666{
4667 /*
4668 * If we've executed guest code using hardware-assisted VMX, the host-state bits
4669 * will be messed up. We should -not- save the messed up state without restoring
4670 * the original host-state, see @bugref{7240}.
4671 *
4672 * This apparently can happen (most likely the FPU changes), deal with it rather than
4673 * asserting. Was observed booting Solaris 10u10 32-bit guest.
4674 */
4675 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
4676 {
4677 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hmr0.s.vmx.fRestoreHostFlags,
4678 pVCpu->idCpu));
4679 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
4680 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
4681 }
4682
4683 /*
4684 * Get all the host info.
4685 * ASSUME it is safe to use rdfsbase and friends if the CR4.FSGSBASE bit is set
4686 * without also checking the cpuid bit.
4687 */
4688 uint32_t fRestoreHostFlags;
4689#if RT_INLINE_ASM_EXTERNAL
4690 if (uHostCr4 & X86_CR4_FSGSBASE)
4691 {
4692 hmR0VmxExportHostSegmentRegsAsmHlp(&pVCpu->hmr0.s.vmx.RestoreHost, true /*fHaveFsGsBase*/);
4693 fRestoreHostFlags = VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE;
4694 }
4695 else
4696 {
4697 hmR0VmxExportHostSegmentRegsAsmHlp(&pVCpu->hmr0.s.vmx.RestoreHost, false /*fHaveFsGsBase*/);
4698 fRestoreHostFlags = 0;
4699 }
4700 RTSEL uSelES = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelES;
4701 RTSEL uSelDS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelDS;
4702 RTSEL uSelFS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelFS;
4703 RTSEL uSelGS = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelGS;
4704#else
4705 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR = ASMGetTR();
4706 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS = ASMGetSS();
4707 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS = ASMGetCS();
4708 ASMGetGDTR((PRTGDTR)&pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr);
4709 ASMGetIDTR((PRTIDTR)&pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr);
4710 if (uHostCr4 & X86_CR4_FSGSBASE)
4711 {
4712 pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase = ASMGetFSBase();
4713 pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase = ASMGetGSBase();
4714 fRestoreHostFlags = VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE;
4715 }
4716 else
4717 {
4718 pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase = ASMRdMsr(MSR_K8_FS_BASE);
4719 pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase = ASMRdMsr(MSR_K8_GS_BASE);
4720 fRestoreHostFlags = 0;
4721 }
4722 RTSEL uSelES, uSelDS, uSelFS, uSelGS;
4723 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelDS = uSelDS = ASMGetDS();
4724 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelES = uSelES = ASMGetES();
4725 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelFS = uSelFS = ASMGetFS();
4726 pVCpu->hmr0.s.vmx.RestoreHost.uHostSelGS = uSelGS = ASMGetGS();
4727#endif
4728
4729 /*
4730 * Determine if the host segment registers are suitable for VT-x. Otherwise use zero to
4731 * gain VM-entry and restore them before we get preempted.
4732 *
4733 * See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
4734 */
4735 RTSEL const uSelAll = uSelFS | uSelGS | uSelES | uSelDS;
4736 if (uSelAll & (X86_SEL_RPL | X86_SEL_LDT))
4737 {
4738 if (!(uSelAll & X86_SEL_LDT))
4739 {
4740#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_uVmcsVar) \
4741 do { \
4742 (a_uVmcsVar) = pVCpu->hmr0.s.vmx.RestoreHost.uHostSel##a_Seg; \
4743 if ((a_uVmcsVar) & X86_SEL_RPL) \
4744 { \
4745 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4746 (a_uVmcsVar) = 0; \
4747 } \
4748 } while (0)
4749 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4750 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4751 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4752 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4753#undef VMXLOCAL_ADJUST_HOST_SEG
4754 }
4755 else
4756 {
4757#define VMXLOCAL_ADJUST_HOST_SEG(a_Seg, a_uVmcsVar) \
4758 do { \
4759 (a_uVmcsVar) = pVCpu->hmr0.s.vmx.RestoreHost.uHostSel##a_Seg; \
4760 if ((a_uVmcsVar) & (X86_SEL_RPL | X86_SEL_LDT)) \
4761 { \
4762 if (!((a_uVmcsVar) & X86_SEL_LDT)) \
4763 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4764 else \
4765 { \
4766 uint32_t const fAttr = ASMGetSegAttr(a_uVmcsVar); \
4767 if ((fAttr & X86_DESC_P) && fAttr != UINT32_MAX) \
4768 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_##a_Seg; \
4769 } \
4770 (a_uVmcsVar) = 0; \
4771 } \
4772 } while (0)
4773 VMXLOCAL_ADJUST_HOST_SEG(DS, uSelDS);
4774 VMXLOCAL_ADJUST_HOST_SEG(ES, uSelES);
4775 VMXLOCAL_ADJUST_HOST_SEG(FS, uSelFS);
4776 VMXLOCAL_ADJUST_HOST_SEG(GS, uSelGS);
4777#undef VMXLOCAL_ADJUST_HOST_SEG
4778 }
4779 }
4780
4781 /* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
4782 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);
4783 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);
4784 Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS & X86_SEL_RPL)); Assert(!(pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS & X86_SEL_LDT));
4785 Assert(!(uSelDS & X86_SEL_RPL)); Assert(!(uSelDS & X86_SEL_LDT));
4786 Assert(!(uSelES & X86_SEL_RPL)); Assert(!(uSelES & X86_SEL_LDT));
4787 Assert(!(uSelFS & X86_SEL_RPL)); Assert(!(uSelFS & X86_SEL_LDT));
4788 Assert(!(uSelGS & X86_SEL_RPL)); Assert(!(uSelGS & X86_SEL_LDT));
4789
4790 /*
4791 * Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps
4792 * them to the maximum limit (0xffff) on every VM-exit.
4793 */
4794 if (pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb != 0xffff)
4795 fRestoreHostFlags |= VMX_RESTORE_HOST_GDTR;
4796
4797 /*
4798 * IDT limit is effectively capped at 0xfff. (See Intel spec. 6.14.1 "64-Bit Mode IDT" and
4799 * Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit
4800 * as 0xfff, VT-x bloating the limit to 0xffff shouldn't cause any different CPU behavior.
4801 * However, several hosts either insists on 0xfff being the limit (Windows Patch Guard) or
4802 * uses the limit for other purposes (darwin puts the CPU ID in there but botches sidt
4803 * alignment in at least one consumer). So, we're only allowing the IDTR.LIMIT to be left
4804 * at 0xffff on hosts where we are sure it won't cause trouble.
4805 */
4806#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
4807 if (pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.cb < 0x0fff)
4808#else
4809 if (pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.cb != 0xffff)
4810#endif
4811 fRestoreHostFlags |= VMX_RESTORE_HOST_IDTR;
4812
4813 /*
4814 * Host TR base. Verify that TR selector doesn't point past the GDT. Masking off the TI
4815 * and RPL bits is effectively what the CPU does for "scaling by 8". TI is always 0 and
4816 * RPL should be too in most cases.
4817 */
4818 RTSEL const uSelTR = pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR;
4819 AssertMsgReturn((uSelTR | X86_SEL_RPL_LDT) <= pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb,
4820 ("TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb),
4821 VERR_VMX_INVALID_HOST_STATE);
4822
4823 PCX86DESCHC pDesc = (PCX86DESCHC)(pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.uAddr + (uSelTR & X86_SEL_MASK));
4824 uintptr_t const uTRBase = X86DESC64_BASE(pDesc);
4825
4826 /*
4827 * VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on
4828 * all VM-exits. The type is the same for 64-bit busy TSS[1]. The limit needs manual
4829 * restoration if the host has something else. Task switching is not supported in 64-bit
4830 * mode[2], but the limit still matters as IOPM is supported in 64-bit mode. Restoring the
4831 * limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
4832 *
4833 * [1] See Intel spec. 3.5 "System Descriptor Types".
4834 * [2] See Intel spec. 7.2.3 "TSS Descriptor in 64-bit mode".
4835 */
4836 Assert(pDesc->System.u4Type == 11);
4837 if ( pDesc->System.u16LimitLow != 0x67
4838 || pDesc->System.u4LimitHigh)
4839 {
4840 fRestoreHostFlags |= VMX_RESTORE_HOST_SEL_TR;
4841
4842 /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */
4843 if (g_fHmHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY)
4844 fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY;
4845 if (g_fHmHostKernelFeatures & SUPKERNELFEATURES_GDT_NEED_WRITABLE)
4846 {
4847 /* The GDT is read-only but the writable GDT is available. */
4848 fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_NEED_WRITABLE;
4849 pVCpu->hmr0.s.vmx.RestoreHost.HostGdtrRw.cb = pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.cb;
4850 int rc = SUPR0GetCurrentGdtRw(&pVCpu->hmr0.s.vmx.RestoreHost.HostGdtrRw.uAddr);
4851 AssertRCReturn(rc, rc);
4852 }
4853 }
4854
4855 pVCpu->hmr0.s.vmx.fRestoreHostFlags = fRestoreHostFlags;
4856
4857 /*
4858 * Do all the VMCS updates in one block to assist nested virtualization.
4859 */
4860 int rc;
4861 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_CS_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelCS); AssertRC(rc);
4862 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_SS_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelSS); AssertRC(rc);
4863 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_DS_SEL, uSelDS); AssertRC(rc);
4864 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_ES_SEL, uSelES); AssertRC(rc);
4865 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_FS_SEL, uSelFS); AssertRC(rc);
4866 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_GS_SEL, uSelGS); AssertRC(rc);
4867 rc = VMXWriteVmcs16(VMX_VMCS16_HOST_TR_SEL, pVCpu->hmr0.s.vmx.RestoreHost.uHostSelTR); AssertRC(rc);
4868 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GDTR_BASE, pVCpu->hmr0.s.vmx.RestoreHost.HostGdtr.uAddr); AssertRC(rc);
4869 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_IDTR_BASE, pVCpu->hmr0.s.vmx.RestoreHost.HostIdtr.uAddr); AssertRC(rc);
4870 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_TR_BASE, uTRBase); AssertRC(rc);
4871 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_FS_BASE, pVCpu->hmr0.s.vmx.RestoreHost.uHostFSBase); AssertRC(rc);
4872 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_GS_BASE, pVCpu->hmr0.s.vmx.RestoreHost.uHostGSBase); AssertRC(rc);
4873
4874 return VINF_SUCCESS;
4875}
4876
4877
4878/**
4879 * Exports certain host MSRs in the VM-exit MSR-load area and some in the
4880 * host-state area of the VMCS.
4881 *
4882 * These MSRs will be automatically restored on the host after every successful
4883 * VM-exit.
4884 *
4885 * @param pVCpu The cross context virtual CPU structure.
4886 *
4887 * @remarks No-long-jump zone!!!
4888 */
4889static void hmR0VmxExportHostMsrs(PVMCPUCC pVCpu)
4890{
4891 AssertPtr(pVCpu);
4892
4893 /*
4894 * Save MSRs that we restore lazily (due to preemption or transition to ring-3)
4895 * rather than swapping them on every VM-entry.
4896 */
4897 hmR0VmxLazySaveHostMsrs(pVCpu);
4898
4899 /*
4900 * Host Sysenter MSRs.
4901 */
4902 int rc = VMXWriteVmcs32(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS)); AssertRC(rc);
4903 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP)); AssertRC(rc);
4904 rc = VMXWriteVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP)); AssertRC(rc);
4905
4906 /*
4907 * Host EFER MSR.
4908 *
4909 * If the CPU supports the newer VMCS controls for managing EFER, use it. Otherwise it's
4910 * done as part of auto-load/store MSR area in the VMCS, see hmR0VmxExportGuestMsrs().
4911 */
4912 if (g_fHmVmxSupportsVmcsEfer)
4913 {
4914 rc = VMXWriteVmcs64(VMX_VMCS64_HOST_EFER_FULL, g_uHmVmxHostMsrEfer);
4915 AssertRC(rc);
4916 }
4917
4918 /** @todo IA32_PERF_GLOBALCTRL, IA32_PAT also see
4919 * hmR0VmxExportGuestEntryExitCtls(). */
4920}
4921
4922
4923/**
4924 * Figures out if we need to swap the EFER MSR which is particularly expensive.
4925 *
4926 * We check all relevant bits. For now, that's everything besides LMA/LME, as
4927 * these two bits are handled by VM-entry, see hmR0VMxExportGuestEntryExitCtls().
4928 *
4929 * @returns true if we need to load guest EFER, false otherwise.
4930 * @param pVCpu The cross context virtual CPU structure.
4931 * @param pVmxTransient The VMX-transient structure.
4932 *
4933 * @remarks Requires EFER, CR4.
4934 * @remarks No-long-jump zone!!!
4935 */
4936static bool hmR0VmxShouldSwapEferMsr(PCVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
4937{
4938#ifdef HMVMX_ALWAYS_SWAP_EFER
4939 RT_NOREF2(pVCpu, pVmxTransient);
4940 return true;
4941#else
4942 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
4943 uint64_t const u64HostEfer = g_uHmVmxHostMsrEfer;
4944 uint64_t const u64GuestEfer = pCtx->msrEFER;
4945
4946# ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4947 /*
4948 * For nested-guests, we shall honor swapping the EFER MSR when requested by
4949 * the nested-guest.
4950 */
4951 if ( pVmxTransient->fIsNestedGuest
4952 && ( CPUMIsGuestVmxEntryCtlsSet(pCtx, VMX_ENTRY_CTLS_LOAD_EFER_MSR)
4953 || CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_SAVE_EFER_MSR)
4954 || CPUMIsGuestVmxExitCtlsSet(pCtx, VMX_EXIT_CTLS_LOAD_EFER_MSR)))
4955 return true;
4956# else
4957 RT_NOREF(pVmxTransient);
4958#endif
4959
4960 /*
4961 * For 64-bit guests, if EFER.SCE bit differs, we need to swap the EFER MSR
4962 * to ensure that the guest's SYSCALL behaviour isn't broken, see @bugref{7386}.
4963 */
4964 if ( CPUMIsGuestInLongModeEx(pCtx)
4965 && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
4966 return true;
4967
4968 /*
4969 * If the guest uses PAE and EFER.NXE bit differs, we need to swap the EFER MSR
4970 * as it affects guest paging. 64-bit paging implies CR4.PAE as well.
4971 *
4972 * See Intel spec. 4.5 "IA-32e Paging".
4973 * See Intel spec. 4.1.1 "Three Paging Modes".
4974 *
4975 * Verify that we always intercept CR4.PAE and CR0.PG bits, so we don't need to
4976 * import CR4 and CR0 from the VMCS here as those bits are always up to date.
4977 */
4978 Assert(hmR0VmxGetFixedCr4Mask(pVCpu) & X86_CR4_PAE);
4979 Assert(hmR0VmxGetFixedCr0Mask(pVCpu) & X86_CR0_PG);
4980 if ( (pCtx->cr4 & X86_CR4_PAE)
4981 && (pCtx->cr0 & X86_CR0_PG))
4982 {
4983 /*
4984 * If nested paging is not used, verify that the guest paging mode matches the
4985 * shadow paging mode which is/will be placed in the VMCS (which is what will
4986 * actually be used while executing the guest and not the CR4 shadow value).
4987 */
4988 AssertMsg( pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging
4989 || pVCpu->hm.s.enmShadowMode == PGMMODE_PAE
4990 || pVCpu->hm.s.enmShadowMode == PGMMODE_PAE_NX
4991 || pVCpu->hm.s.enmShadowMode == PGMMODE_AMD64
4992 || pVCpu->hm.s.enmShadowMode == PGMMODE_AMD64_NX,
4993 ("enmShadowMode=%u\n", pVCpu->hm.s.enmShadowMode));
4994 if ((u64GuestEfer & MSR_K6_EFER_NXE) != (u64HostEfer & MSR_K6_EFER_NXE))
4995 {
4996 /* Verify that the host is NX capable. */
4997 Assert(pVCpu->CTX_SUFF(pVM)->cpum.ro.HostFeatures.fNoExecute);
4998 return true;
4999 }
5000 }
5001
5002 return false;
5003#endif
5004}
5005
5006
5007/**
5008 * Exports the guest state with appropriate VM-entry and VM-exit controls in the
5009 * VMCS.
5010 *
5011 * This is typically required when the guest changes paging mode.
5012 *
5013 * @returns VBox status code.
5014 * @param pVCpu The cross context virtual CPU structure.
5015 * @param pVmxTransient The VMX-transient structure.
5016 *
5017 * @remarks Requires EFER.
5018 * @remarks No-long-jump zone!!!
5019 */
5020static int hmR0VmxExportGuestEntryExitCtls(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5021{
5022 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS)
5023 {
5024 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5025 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5026
5027 /*
5028 * VM-entry controls.
5029 */
5030 {
5031 uint32_t fVal = g_HmMsrs.u.vmx.EntryCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
5032 uint32_t const fZap = g_HmMsrs.u.vmx.EntryCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
5033
5034 /*
5035 * Load the guest debug controls (DR7 and IA32_DEBUGCTL MSR) on VM-entry.
5036 * The first VT-x capable CPUs only supported the 1-setting of this bit.
5037 *
5038 * For nested-guests, this is a mandatory VM-entry control. It's also
5039 * required because we do not want to leak host bits to the nested-guest.
5040 */
5041 fVal |= VMX_ENTRY_CTLS_LOAD_DEBUG;
5042
5043 /*
5044 * Set if the guest is in long mode. This will set/clear the EFER.LMA bit on VM-entry.
5045 *
5046 * For nested-guests, the "IA-32e mode guest" control we initialize with what is
5047 * required to get the nested-guest working with hardware-assisted VMX execution.
5048 * It depends on the nested-guest's IA32_EFER.LMA bit. Remember, a nested hypervisor
5049 * can skip intercepting changes to the EFER MSR. This is why it needs to be done
5050 * here rather than while merging the guest VMCS controls.
5051 */
5052 if (CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
5053 {
5054 Assert(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LME);
5055 fVal |= VMX_ENTRY_CTLS_IA32E_MODE_GUEST;
5056 }
5057 else
5058 Assert(!(fVal & VMX_ENTRY_CTLS_IA32E_MODE_GUEST));
5059
5060 /*
5061 * If the CPU supports the newer VMCS controls for managing guest/host EFER, use it.
5062 *
5063 * For nested-guests, we use the "load IA32_EFER" if the hardware supports it,
5064 * regardless of whether the nested-guest VMCS specifies it because we are free to
5065 * load whatever MSRs we require and we do not need to modify the guest visible copy
5066 * of the VM-entry MSR load area.
5067 */
5068 if ( g_fHmVmxSupportsVmcsEfer
5069 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
5070 fVal |= VMX_ENTRY_CTLS_LOAD_EFER_MSR;
5071 else
5072 Assert(!(fVal & VMX_ENTRY_CTLS_LOAD_EFER_MSR));
5073
5074 /*
5075 * The following should -not- be set (since we're not in SMM mode):
5076 * - VMX_ENTRY_CTLS_ENTRY_TO_SMM
5077 * - VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON
5078 */
5079
5080 /** @todo VMX_ENTRY_CTLS_LOAD_PERF_MSR,
5081 * VMX_ENTRY_CTLS_LOAD_PAT_MSR. */
5082
5083 if ((fVal & fZap) == fVal)
5084 { /* likely */ }
5085 else
5086 {
5087 Log4Func(("Invalid VM-entry controls combo! Cpu=%#RX32 fVal=%#RX32 fZap=%#RX32\n",
5088 g_HmMsrs.u.vmx.EntryCtls.n.allowed0, fVal, fZap));
5089 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_ENTRY;
5090 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
5091 }
5092
5093 /* Commit it to the VMCS. */
5094 if (pVmcsInfo->u32EntryCtls != fVal)
5095 {
5096 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY, fVal);
5097 AssertRC(rc);
5098 pVmcsInfo->u32EntryCtls = fVal;
5099 }
5100 }
5101
5102 /*
5103 * VM-exit controls.
5104 */
5105 {
5106 uint32_t fVal = g_HmMsrs.u.vmx.ExitCtls.n.allowed0; /* Bits set here must be set in the VMCS. */
5107 uint32_t const fZap = g_HmMsrs.u.vmx.ExitCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
5108
5109 /*
5110 * Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only
5111 * supported the 1-setting of this bit.
5112 *
5113 * For nested-guests, we set the "save debug controls" as the converse
5114 * "load debug controls" is mandatory for nested-guests anyway.
5115 */
5116 fVal |= VMX_EXIT_CTLS_SAVE_DEBUG;
5117
5118 /*
5119 * Set the host long mode active (EFER.LMA) bit (which Intel calls
5120 * "Host address-space size") if necessary. On VM-exit, VT-x sets both the
5121 * host EFER.LMA and EFER.LME bit to this value. See assertion in
5122 * hmR0VmxExportHostMsrs().
5123 *
5124 * For nested-guests, we always set this bit as we do not support 32-bit
5125 * hosts.
5126 */
5127 fVal |= VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE;
5128
5129 /*
5130 * If the VMCS EFER MSR fields are supported by the hardware, we use it.
5131 *
5132 * For nested-guests, we should use the "save IA32_EFER" control if we also
5133 * used the "load IA32_EFER" control while exporting VM-entry controls.
5134 */
5135 if ( g_fHmVmxSupportsVmcsEfer
5136 && hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
5137 {
5138 fVal |= VMX_EXIT_CTLS_SAVE_EFER_MSR
5139 | VMX_EXIT_CTLS_LOAD_EFER_MSR;
5140 }
5141
5142 /*
5143 * Enable saving of the VMX-preemption timer value on VM-exit.
5144 * For nested-guests, currently not exposed/used.
5145 */
5146 /** @todo r=bird: Measure performance hit because of this vs. always rewriting
5147 * the timer value. */
5148 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
5149 {
5150 Assert(g_HmMsrs.u.vmx.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER);
5151 fVal |= VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER;
5152 }
5153
5154 /* Don't acknowledge external interrupts on VM-exit. We want to let the host do that. */
5155 Assert(!(fVal & VMX_EXIT_CTLS_ACK_EXT_INT));
5156
5157 /** @todo VMX_EXIT_CTLS_LOAD_PERF_MSR,
5158 * VMX_EXIT_CTLS_SAVE_PAT_MSR,
5159 * VMX_EXIT_CTLS_LOAD_PAT_MSR. */
5160
5161 if ((fVal & fZap) == fVal)
5162 { /* likely */ }
5163 else
5164 {
5165 Log4Func(("Invalid VM-exit controls combo! cpu=%#RX32 fVal=%#RX32 fZap=%R#X32\n",
5166 g_HmMsrs.u.vmx.ExitCtls.n.allowed0, fVal, fZap));
5167 pVCpu->hm.s.u32HMError = VMX_UFC_CTRL_EXIT;
5168 return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
5169 }
5170
5171 /* Commit it to the VMCS. */
5172 if (pVmcsInfo->u32ExitCtls != fVal)
5173 {
5174 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT, fVal);
5175 AssertRC(rc);
5176 pVmcsInfo->u32ExitCtls = fVal;
5177 }
5178 }
5179
5180 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
5181 }
5182 return VINF_SUCCESS;
5183}
5184
5185
5186/**
5187 * Sets the TPR threshold in the VMCS.
5188 *
5189 * @param pVmcsInfo The VMCS info. object.
5190 * @param u32TprThreshold The TPR threshold (task-priority class only).
5191 */
5192DECLINLINE(void) hmR0VmxApicSetTprThreshold(PVMXVMCSINFO pVmcsInfo, uint32_t u32TprThreshold)
5193{
5194 Assert(!(u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)); /* Bits 31:4 MBZ. */
5195 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
5196 RT_NOREF(pVmcsInfo);
5197 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
5198 AssertRC(rc);
5199}
5200
5201
5202/**
5203 * Exports the guest APIC TPR state into the VMCS.
5204 *
5205 * @param pVCpu The cross context virtual CPU structure.
5206 * @param pVmxTransient The VMX-transient structure.
5207 *
5208 * @remarks No-long-jump zone!!!
5209 */
5210static void hmR0VmxExportGuestApicTpr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5211{
5212 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_APIC_TPR)
5213 {
5214 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_APIC_TPR);
5215
5216 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5217 if (!pVmxTransient->fIsNestedGuest)
5218 {
5219 if ( PDMHasApic(pVCpu->CTX_SUFF(pVM))
5220 && APICIsEnabled(pVCpu))
5221 {
5222 /*
5223 * Setup TPR shadowing.
5224 */
5225 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
5226 {
5227 bool fPendingIntr = false;
5228 uint8_t u8Tpr = 0;
5229 uint8_t u8PendingIntr = 0;
5230 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, &u8PendingIntr);
5231 AssertRC(rc);
5232
5233 /*
5234 * If there are interrupts pending but masked by the TPR, instruct VT-x to
5235 * cause a TPR-below-threshold VM-exit when the guest lowers its TPR below the
5236 * priority of the pending interrupt so we can deliver the interrupt. If there
5237 * are no interrupts pending, set threshold to 0 to not cause any
5238 * TPR-below-threshold VM-exits.
5239 */
5240 uint32_t u32TprThreshold = 0;
5241 if (fPendingIntr)
5242 {
5243 /* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR
5244 (which is the Task-Priority Class). */
5245 const uint8_t u8PendingPriority = u8PendingIntr >> 4;
5246 const uint8_t u8TprPriority = u8Tpr >> 4;
5247 if (u8PendingPriority <= u8TprPriority)
5248 u32TprThreshold = u8PendingPriority;
5249 }
5250
5251 hmR0VmxApicSetTprThreshold(pVmcsInfo, u32TprThreshold);
5252 }
5253 }
5254 }
5255 /* else: the TPR threshold has already been updated while merging the nested-guest VMCS. */
5256 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
5257 }
5258}
5259
5260
5261/**
5262 * Gets the guest interruptibility-state and updates related force-flags.
5263 *
5264 * @returns Guest's interruptibility-state.
5265 * @param pVCpu The cross context virtual CPU structure.
5266 *
5267 * @remarks No-long-jump zone!!!
5268 */
5269static uint32_t hmR0VmxGetGuestIntrStateAndUpdateFFs(PVMCPUCC pVCpu)
5270{
5271 /*
5272 * Check if we should inhibit interrupt delivery due to instructions like STI and MOV SS.
5273 */
5274 uint32_t fIntrState = 0;
5275 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
5276 {
5277 /* If inhibition is active, RIP and RFLAGS should've been imported from the VMCS already. */
5278 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
5279
5280 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5281 if (pCtx->rip == EMGetInhibitInterruptsPC(pVCpu))
5282 {
5283 if (pCtx->eflags.Bits.u1IF)
5284 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
5285 else
5286 fIntrState = VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS;
5287 }
5288 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
5289 {
5290 /*
5291 * We can clear the inhibit force flag as even if we go back to the recompiler
5292 * without executing guest code in VT-x, the flag's condition to be cleared is
5293 * met and thus the cleared state is correct.
5294 */
5295 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
5296 }
5297 }
5298
5299 /*
5300 * Check if we should inhibit NMI delivery.
5301 */
5302 if (CPUMIsGuestNmiBlocking(pVCpu))
5303 fIntrState |= VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI;
5304
5305 /*
5306 * Validate.
5307 */
5308#ifdef VBOX_STRICT
5309 /* We don't support block-by-SMI yet.*/
5310 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI));
5311
5312 /* Block-by-STI must not be set when interrupts are disabled. */
5313 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
5314 {
5315 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
5316 Assert(pVCpu->cpum.GstCtx.eflags.u & X86_EFL_IF);
5317 }
5318#endif
5319
5320 return fIntrState;
5321}
5322
5323
5324/**
5325 * Exports the exception intercepts required for guest execution in the VMCS.
5326 *
5327 * @param pVCpu The cross context virtual CPU structure.
5328 * @param pVmxTransient The VMX-transient structure.
5329 *
5330 * @remarks No-long-jump zone!!!
5331 */
5332static void hmR0VmxExportGuestXcptIntercepts(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5333{
5334 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_XCPT_INTERCEPTS)
5335 {
5336 /* When executing a nested-guest, we do not need to trap GIM hypercalls by intercepting #UD. */
5337 if ( !pVmxTransient->fIsNestedGuest
5338 && pVCpu->hm.s.fGIMTrapXcptUD)
5339 hmR0VmxAddXcptIntercept(pVmxTransient, X86_XCPT_UD);
5340 else
5341 hmR0VmxRemoveXcptIntercept(pVCpu, pVmxTransient, X86_XCPT_UD);
5342
5343 /* Other exception intercepts are handled elsewhere, e.g. while exporting guest CR0. */
5344 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_XCPT_INTERCEPTS);
5345 }
5346}
5347
5348
5349/**
5350 * Exports the guest's RIP into the guest-state area in the VMCS.
5351 *
5352 * @param pVCpu The cross context virtual CPU structure.
5353 *
5354 * @remarks No-long-jump zone!!!
5355 */
5356static void hmR0VmxExportGuestRip(PVMCPUCC pVCpu)
5357{
5358 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RIP)
5359 {
5360 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP);
5361
5362 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RIP, pVCpu->cpum.GstCtx.rip);
5363 AssertRC(rc);
5364
5365 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RIP);
5366 Log4Func(("rip=%#RX64\n", pVCpu->cpum.GstCtx.rip));
5367 }
5368}
5369
5370
5371/**
5372 * Exports the guest's RSP into the guest-state area in the VMCS.
5373 *
5374 * @param pVCpu The cross context virtual CPU structure.
5375 *
5376 * @remarks No-long-jump zone!!!
5377 */
5378static void hmR0VmxExportGuestRsp(PVMCPUCC pVCpu)
5379{
5380 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RSP)
5381 {
5382 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RSP);
5383
5384 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RSP, pVCpu->cpum.GstCtx.rsp);
5385 AssertRC(rc);
5386
5387 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RSP);
5388 Log4Func(("rsp=%#RX64\n", pVCpu->cpum.GstCtx.rsp));
5389 }
5390}
5391
5392
5393/**
5394 * Exports the guest's RFLAGS into the guest-state area in the VMCS.
5395 *
5396 * @param pVCpu The cross context virtual CPU structure.
5397 * @param pVmxTransient The VMX-transient structure.
5398 *
5399 * @remarks No-long-jump zone!!!
5400 */
5401static void hmR0VmxExportGuestRflags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5402{
5403 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_RFLAGS)
5404 {
5405 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
5406
5407 /* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
5408 Let us assert it as such and use 32-bit VMWRITE. */
5409 Assert(!RT_HI_U32(pVCpu->cpum.GstCtx.rflags.u64));
5410 X86EFLAGS fEFlags = pVCpu->cpum.GstCtx.eflags;
5411 Assert(fEFlags.u32 & X86_EFL_RA1_MASK);
5412 Assert(!(fEFlags.u32 & ~(X86_EFL_1 | X86_EFL_LIVE_MASK)));
5413
5414 /*
5415 * If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so
5416 * we can restore them on VM-exit. Modify the real-mode guest's eflags so that VT-x
5417 * can run the real-mode guest code under Virtual 8086 mode.
5418 */
5419 PVMXVMCSINFOSHARED pVmcsInfo = pVmxTransient->pVmcsInfo->pShared;
5420 if (pVmcsInfo->RealMode.fRealOnV86Active)
5421 {
5422 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
5423 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
5424 Assert(!pVmxTransient->fIsNestedGuest);
5425 pVmcsInfo->RealMode.Eflags.u32 = fEFlags.u32; /* Save the original eflags of the real-mode guest. */
5426 fEFlags.Bits.u1VM = 1; /* Set the Virtual 8086 mode bit. */
5427 fEFlags.Bits.u2IOPL = 0; /* Change IOPL to 0, otherwise certain instructions won't fault. */
5428 }
5429
5430 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_RFLAGS, fEFlags.u32);
5431 AssertRC(rc);
5432
5433 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_RFLAGS);
5434 Log4Func(("eflags=%#RX32\n", fEFlags.u32));
5435 }
5436}
5437
5438
5439#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5440/**
5441 * Copies the nested-guest VMCS to the shadow VMCS.
5442 *
5443 * @returns VBox status code.
5444 * @param pVCpu The cross context virtual CPU structure.
5445 * @param pVmcsInfo The VMCS info. object.
5446 *
5447 * @remarks No-long-jump zone!!!
5448 */
5449static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5450{
5451 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
5452 PCVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
5453
5454 /*
5455 * Disable interrupts so we don't get preempted while the shadow VMCS is the
5456 * current VMCS, as we may try saving guest lazy MSRs.
5457 *
5458 * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
5459 * calling the import VMCS code which is currently performing the guest MSR reads
5460 * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
5461 * and the rest of the VMX leave session machinery.
5462 */
5463 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
5464
5465 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5466 if (RT_SUCCESS(rc))
5467 {
5468 /*
5469 * Copy all guest read/write VMCS fields.
5470 *
5471 * We don't check for VMWRITE failures here for performance reasons and
5472 * because they are not expected to fail, barring irrecoverable conditions
5473 * like hardware errors.
5474 */
5475 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
5476 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5477 {
5478 uint64_t u64Val;
5479 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsFields[i];
5480 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5481 VMXWriteVmcs64(uVmcsField, u64Val);
5482 }
5483
5484 /*
5485 * If the host CPU supports writing all VMCS fields, copy the guest read-only
5486 * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
5487 */
5488 if (g_HmMsrs.u.vmx.u64Misc & VMX_MISC_VMWRITE_ALL)
5489 {
5490 uint32_t const cShadowVmcsRoFields = pVM->hmr0.s.vmx.cShadowVmcsRoFields;
5491 for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
5492 {
5493 uint64_t u64Val;
5494 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsRoFields[i];
5495 IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
5496 VMXWriteVmcs64(uVmcsField, u64Val);
5497 }
5498 }
5499
5500 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5501 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5502 }
5503
5504 ASMSetFlags(fEFlags);
5505 return rc;
5506}
5507
5508
5509/**
5510 * Copies the shadow VMCS to the nested-guest VMCS.
5511 *
5512 * @returns VBox status code.
5513 * @param pVCpu The cross context virtual CPU structure.
5514 * @param pVmcsInfo The VMCS info. object.
5515 *
5516 * @remarks Called with interrupts disabled.
5517 */
5518static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
5519{
5520 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
5521 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
5522 PVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
5523
5524 int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
5525 if (RT_SUCCESS(rc))
5526 {
5527 /*
5528 * Copy guest read/write fields from the shadow VMCS.
5529 * Guest read-only fields cannot be modified, so no need to copy them.
5530 *
5531 * We don't check for VMREAD failures here for performance reasons and
5532 * because they are not expected to fail, barring irrecoverable conditions
5533 * like hardware errors.
5534 */
5535 uint32_t const cShadowVmcsFields = pVM->hmr0.s.vmx.cShadowVmcsFields;
5536 for (uint32_t i = 0; i < cShadowVmcsFields; i++)
5537 {
5538 uint64_t u64Val;
5539 uint32_t const uVmcsField = pVM->hmr0.s.vmx.paShadowVmcsFields[i];
5540 VMXReadVmcs64(uVmcsField, &u64Val);
5541 IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
5542 }
5543
5544 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
5545 rc |= hmR0VmxLoadVmcs(pVmcsInfo);
5546 }
5547 return rc;
5548}
5549
5550
5551/**
5552 * Enables VMCS shadowing for the given VMCS info. object.
5553 *
5554 * @param pVmcsInfo The VMCS info. object.
5555 *
5556 * @remarks No-long-jump zone!!!
5557 */
5558static void hmR0VmxEnableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5559{
5560 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5561 if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
5562 {
5563 Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
5564 uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
5565 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5566 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs); AssertRC(rc);
5567 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5568 pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
5569 Log4Func(("Enabled\n"));
5570 }
5571}
5572
5573
5574/**
5575 * Disables VMCS shadowing for the given VMCS info. object.
5576 *
5577 * @param pVmcsInfo The VMCS info. object.
5578 *
5579 * @remarks No-long-jump zone!!!
5580 */
5581static void hmR0VmxDisableVmcsShadowing(PVMXVMCSINFO pVmcsInfo)
5582{
5583 /*
5584 * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
5585 * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
5586 * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
5587 * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
5588 *
5589 * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
5590 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
5591 */
5592 uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
5593 if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
5594 {
5595 uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
5596 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2); AssertRC(rc);
5597 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS); AssertRC(rc);
5598 pVmcsInfo->u32ProcCtls2 = uProcCtls2;
5599 pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
5600 Log4Func(("Disabled\n"));
5601 }
5602}
5603#endif
5604
5605
5606/**
5607 * Exports the guest hardware-virtualization state.
5608 *
5609 * @returns VBox status code.
5610 * @param pVCpu The cross context virtual CPU structure.
5611 * @param pVmxTransient The VMX-transient structure.
5612 *
5613 * @remarks No-long-jump zone!!!
5614 */
5615static int hmR0VmxExportGuestHwvirtState(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5616{
5617 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
5618 {
5619#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
5620 /*
5621 * Check if the VMX feature is exposed to the guest and if the host CPU supports
5622 * VMCS shadowing.
5623 */
5624 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUseVmcsShadowing)
5625 {
5626 /*
5627 * If the nested hypervisor has loaded a current VMCS and is in VMX root mode,
5628 * copy the nested hypervisor's current VMCS into the shadow VMCS and enable
5629 * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
5630 *
5631 * We check for VMX root mode here in case the guest executes VMXOFF without
5632 * clearing the current VMCS pointer and our VMXOFF instruction emulation does
5633 * not clear the current VMCS pointer.
5634 */
5635 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5636 if ( CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
5637 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
5638 && CPUMIsGuestVmxCurrentVmcsValid(&pVCpu->cpum.GstCtx))
5639 {
5640 /* Paranoia. */
5641 Assert(!pVmxTransient->fIsNestedGuest);
5642
5643 /*
5644 * For performance reasons, also check if the nested hypervisor's current VMCS
5645 * was newly loaded or modified before copying it to the shadow VMCS.
5646 */
5647 if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
5648 {
5649 int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
5650 AssertRCReturn(rc, rc);
5651 pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
5652 }
5653 hmR0VmxEnableVmcsShadowing(pVmcsInfo);
5654 }
5655 else
5656 hmR0VmxDisableVmcsShadowing(pVmcsInfo);
5657 }
5658#else
5659 NOREF(pVmxTransient);
5660#endif
5661 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
5662 }
5663 return VINF_SUCCESS;
5664}
5665
5666
5667/**
5668 * Exports the guest CR0 control register into the guest-state area in the VMCS.
5669 *
5670 * The guest FPU state is always pre-loaded hence we don't need to bother about
5671 * sharing FPU related CR0 bits between the guest and host.
5672 *
5673 * @returns VBox status code.
5674 * @param pVCpu The cross context virtual CPU structure.
5675 * @param pVmxTransient The VMX-transient structure.
5676 *
5677 * @remarks No-long-jump zone!!!
5678 */
5679static int hmR0VmxExportGuestCR0(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5680{
5681 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR0)
5682 {
5683 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5684 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5685
5686 uint64_t fSetCr0 = g_HmMsrs.u.vmx.u64Cr0Fixed0;
5687 uint64_t const fZapCr0 = g_HmMsrs.u.vmx.u64Cr0Fixed1;
5688 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
5689 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
5690 else
5691 Assert((fSetCr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG));
5692
5693 if (!pVmxTransient->fIsNestedGuest)
5694 {
5695 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5696 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5697 uint64_t const u64ShadowCr0 = u64GuestCr0;
5698 Assert(!RT_HI_U32(u64GuestCr0));
5699
5700 /*
5701 * Setup VT-x's view of the guest CR0.
5702 */
5703 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
5704 if (pVM->hmr0.s.fNestedPaging)
5705 {
5706 if (CPUMIsGuestPagingEnabled(pVCpu))
5707 {
5708 /* The guest has paging enabled, let it access CR3 without causing a VM-exit if supported. */
5709 uProcCtls &= ~( VMX_PROC_CTLS_CR3_LOAD_EXIT
5710 | VMX_PROC_CTLS_CR3_STORE_EXIT);
5711 }
5712 else
5713 {
5714 /* The guest doesn't have paging enabled, make CR3 access cause a VM-exit to update our shadow. */
5715 uProcCtls |= VMX_PROC_CTLS_CR3_LOAD_EXIT
5716 | VMX_PROC_CTLS_CR3_STORE_EXIT;
5717 }
5718
5719 /* If we have unrestricted guest execution, we never have to intercept CR3 reads. */
5720 if (pVM->hmr0.s.vmx.fUnrestrictedGuest)
5721 uProcCtls &= ~VMX_PROC_CTLS_CR3_STORE_EXIT;
5722 }
5723 else
5724 {
5725 /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
5726 u64GuestCr0 |= X86_CR0_WP;
5727 }
5728
5729 /*
5730 * Guest FPU bits.
5731 *
5732 * Since we pre-load the guest FPU always before VM-entry there is no need to track lazy state
5733 * using CR0.TS.
5734 *
5735 * Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be
5736 * set on the first CPUs to support VT-x and no mention of with regards to UX in VM-entry checks.
5737 */
5738 u64GuestCr0 |= X86_CR0_NE;
5739
5740 /* If CR0.NE isn't set, we need to intercept #MF exceptions and report them to the guest differently. */
5741 bool const fInterceptMF = !(u64ShadowCr0 & X86_CR0_NE);
5742
5743 /*
5744 * Update exception intercepts.
5745 */
5746 uint32_t uXcptBitmap = pVmcsInfo->u32XcptBitmap;
5747 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
5748 {
5749 Assert(PDMVmmDevHeapIsEnabled(pVM));
5750 Assert(pVM->hm.s.vmx.pRealModeTSS);
5751 uXcptBitmap |= HMVMX_REAL_MODE_XCPT_MASK;
5752 }
5753 else
5754 {
5755 /* For now, cleared here as mode-switches can happen outside HM/VT-x. See @bugref{7626#c11}. */
5756 uXcptBitmap &= ~HMVMX_REAL_MODE_XCPT_MASK;
5757 if (fInterceptMF)
5758 uXcptBitmap |= RT_BIT(X86_XCPT_MF);
5759 }
5760
5761 /* Additional intercepts for debugging, define these yourself explicitly. */
5762#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
5763 uXcptBitmap |= 0
5764 | RT_BIT(X86_XCPT_BP)
5765 | RT_BIT(X86_XCPT_DE)
5766 | RT_BIT(X86_XCPT_NM)
5767 | RT_BIT(X86_XCPT_TS)
5768 | RT_BIT(X86_XCPT_UD)
5769 | RT_BIT(X86_XCPT_NP)
5770 | RT_BIT(X86_XCPT_SS)
5771 | RT_BIT(X86_XCPT_GP)
5772 | RT_BIT(X86_XCPT_PF)
5773 | RT_BIT(X86_XCPT_MF)
5774 ;
5775#elif defined(HMVMX_ALWAYS_TRAP_PF)
5776 uXcptBitmap |= RT_BIT(X86_XCPT_PF);
5777#endif
5778 if (pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv)
5779 uXcptBitmap |= RT_BIT(X86_XCPT_GP);
5780 Assert(pVM->hmr0.s.fNestedPaging || (uXcptBitmap & RT_BIT(X86_XCPT_PF)));
5781
5782 /* Apply the hardware specified CR0 fixed bits and enable caching. */
5783 u64GuestCr0 |= fSetCr0;
5784 u64GuestCr0 &= fZapCr0;
5785 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5786
5787 /* Commit the CR0 and related fields to the guest VMCS. */
5788 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5789 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5790 if (uProcCtls != pVmcsInfo->u32ProcCtls)
5791 {
5792 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
5793 AssertRC(rc);
5794 }
5795 if (uXcptBitmap != pVmcsInfo->u32XcptBitmap)
5796 {
5797 rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, uXcptBitmap);
5798 AssertRC(rc);
5799 }
5800
5801 /* Update our caches. */
5802 pVmcsInfo->u32ProcCtls = uProcCtls;
5803 pVmcsInfo->u32XcptBitmap = uXcptBitmap;
5804
5805 Log4Func(("cr0=%#RX64 shadow=%#RX64 set=%#RX64 zap=%#RX64\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5806 }
5807 else
5808 {
5809 /*
5810 * With nested-guests, we may have extended the guest/host mask here since we
5811 * merged in the outer guest's mask. Thus, the merged mask can include more bits
5812 * (to read from the nested-guest CR0 read-shadow) than the nested hypervisor
5813 * originally supplied. We must copy those bits from the nested-guest CR0 into
5814 * the nested-guest CR0 read-shadow.
5815 */
5816 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
5817 uint64_t u64GuestCr0 = pVCpu->cpum.GstCtx.cr0;
5818 uint64_t const u64ShadowCr0 = CPUMGetGuestVmxMaskedCr0(&pVCpu->cpum.GstCtx, pVmcsInfo->u64Cr0Mask);
5819 Assert(!RT_HI_U32(u64GuestCr0));
5820 Assert(u64GuestCr0 & X86_CR0_NE);
5821
5822 /* Apply the hardware specified CR0 fixed bits and enable caching. */
5823 u64GuestCr0 |= fSetCr0;
5824 u64GuestCr0 &= fZapCr0;
5825 u64GuestCr0 &= ~(uint64_t)(X86_CR0_CD | X86_CR0_NW);
5826
5827 /* Commit the CR0 and CR0 read-shadow to the nested-guest VMCS. */
5828 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR0, u64GuestCr0); AssertRC(rc);
5829 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, u64ShadowCr0); AssertRC(rc);
5830
5831 Log4Func(("cr0=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr0, u64ShadowCr0, fSetCr0, fZapCr0));
5832 }
5833
5834 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR0);
5835 }
5836
5837 return VINF_SUCCESS;
5838}
5839
5840
5841/**
5842 * Exports the guest control registers (CR3, CR4) into the guest-state area
5843 * in the VMCS.
5844 *
5845 * @returns VBox strict status code.
5846 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
5847 * without unrestricted guest access and the VMMDev is not presently
5848 * mapped (e.g. EFI32).
5849 *
5850 * @param pVCpu The cross context virtual CPU structure.
5851 * @param pVmxTransient The VMX-transient structure.
5852 *
5853 * @remarks No-long-jump zone!!!
5854 */
5855static VBOXSTRICTRC hmR0VmxExportGuestCR3AndCR4(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
5856{
5857 int rc = VINF_SUCCESS;
5858 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
5859
5860 /*
5861 * Guest CR2.
5862 * It's always loaded in the assembler code. Nothing to do here.
5863 */
5864
5865 /*
5866 * Guest CR3.
5867 */
5868 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR3)
5869 {
5870 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR3);
5871
5872 if (pVM->hmr0.s.fNestedPaging)
5873 {
5874 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5875 pVmcsInfo->HCPhysEPTP = PGMGetHyperCR3(pVCpu);
5876
5877 /* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
5878 Assert(pVmcsInfo->HCPhysEPTP != NIL_RTHCPHYS);
5879 Assert(!(pVmcsInfo->HCPhysEPTP & UINT64_C(0xfff0000000000000)));
5880 Assert(!(pVmcsInfo->HCPhysEPTP & 0xfff));
5881
5882 /* VMX_EPT_MEMTYPE_WB support is already checked in hmR0VmxSetupTaggedTlb(). */
5883 pVmcsInfo->HCPhysEPTP |= RT_BF_MAKE(VMX_BF_EPTP_MEMTYPE, VMX_EPTP_MEMTYPE_WB)
5884 | RT_BF_MAKE(VMX_BF_EPTP_PAGE_WALK_LENGTH, VMX_EPTP_PAGE_WALK_LENGTH_4);
5885
5886 /* Validate. See Intel spec. 26.2.1 "Checks on VMX Controls" */
5887 AssertMsg( ((pVmcsInfo->HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
5888 && ((pVmcsInfo->HCPhysEPTP >> 7) & 0x1f) == 0, /* Bits 7:11 MBZ. */
5889 ("EPTP %#RX64\n", pVmcsInfo->HCPhysEPTP));
5890 AssertMsg( !((pVmcsInfo->HCPhysEPTP >> 6) & 0x01) /* Bit 6 (EPT accessed & dirty bit). */
5891 || (g_HmMsrs.u.vmx.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_ACCESS_DIRTY),
5892 ("EPTP accessed/dirty bit not supported by CPU but set %#RX64\n", pVmcsInfo->HCPhysEPTP));
5893
5894 rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, pVmcsInfo->HCPhysEPTP);
5895 AssertRC(rc);
5896
5897 uint64_t u64GuestCr3;
5898 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5899 if ( pVM->hmr0.s.vmx.fUnrestrictedGuest
5900 || CPUMIsGuestPagingEnabledEx(pCtx))
5901 {
5902 /* If the guest is in PAE mode, pass the PDPEs to VT-x using the VMCS fields. */
5903 if (CPUMIsGuestInPAEModeEx(pCtx))
5904 {
5905 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, pCtx->aPaePdpes[0].u); AssertRC(rc);
5906 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, pCtx->aPaePdpes[1].u); AssertRC(rc);
5907 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, pCtx->aPaePdpes[2].u); AssertRC(rc);
5908 rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, pCtx->aPaePdpes[3].u); AssertRC(rc);
5909 }
5910
5911 /*
5912 * The guest's view of its CR3 is unblemished with nested paging when the
5913 * guest is using paging or we have unrestricted guest execution to handle
5914 * the guest when it's not using paging.
5915 */
5916 u64GuestCr3 = pCtx->cr3;
5917 }
5918 else
5919 {
5920 /*
5921 * The guest is not using paging, but the CPU (VT-x) has to. While the guest
5922 * thinks it accesses physical memory directly, we use our identity-mapped
5923 * page table to map guest-linear to guest-physical addresses. EPT takes care
5924 * of translating it to host-physical addresses.
5925 */
5926 RTGCPHYS GCPhys;
5927 Assert(pVM->hm.s.vmx.pNonPagingModeEPTPageTable);
5928
5929 /* We obtain it here every time as the guest could have relocated this PCI region. */
5930 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
5931 if (RT_SUCCESS(rc))
5932 { /* likely */ }
5933 else if (rc == VERR_PDM_DEV_HEAP_R3_TO_GCPHYS)
5934 {
5935 Log4Func(("VERR_PDM_DEV_HEAP_R3_TO_GCPHYS -> VINF_EM_RESCHEDULE_REM\n"));
5936 return VINF_EM_RESCHEDULE_REM; /* We cannot execute now, switch to REM/IEM till the guest maps in VMMDev. */
5937 }
5938 else
5939 AssertMsgFailedReturn(("%Rrc\n", rc), rc);
5940
5941 u64GuestCr3 = GCPhys;
5942 }
5943
5944 Log4Func(("guest_cr3=%#RX64 (GstN)\n", u64GuestCr3));
5945 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, u64GuestCr3);
5946 AssertRC(rc);
5947 }
5948 else
5949 {
5950 Assert(!pVmxTransient->fIsNestedGuest);
5951 /* Non-nested paging case, just use the hypervisor's CR3. */
5952 RTHCPHYS const HCPhysGuestCr3 = PGMGetHyperCR3(pVCpu);
5953
5954 Log4Func(("guest_cr3=%#RX64 (HstN)\n", HCPhysGuestCr3));
5955 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR3, HCPhysGuestCr3);
5956 AssertRC(rc);
5957 }
5958
5959 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR3);
5960 }
5961
5962 /*
5963 * Guest CR4.
5964 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
5965 */
5966 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CR4)
5967 {
5968 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
5969 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
5970
5971 uint64_t const fSetCr4 = g_HmMsrs.u.vmx.u64Cr4Fixed0;
5972 uint64_t const fZapCr4 = g_HmMsrs.u.vmx.u64Cr4Fixed1;
5973
5974 /*
5975 * With nested-guests, we may have extended the guest/host mask here (since we
5976 * merged in the outer guest's mask, see hmR0VmxMergeVmcsNested). This means, the
5977 * mask can include more bits (to read from the nested-guest CR4 read-shadow) than
5978 * the nested hypervisor originally supplied. Thus, we should, in essence, copy
5979 * those bits from the nested-guest CR4 into the nested-guest CR4 read-shadow.
5980 */
5981 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
5982 uint64_t u64GuestCr4 = pCtx->cr4;
5983 uint64_t const u64ShadowCr4 = !pVmxTransient->fIsNestedGuest
5984 ? pCtx->cr4
5985 : CPUMGetGuestVmxMaskedCr4(pCtx, pVmcsInfo->u64Cr4Mask);
5986 Assert(!RT_HI_U32(u64GuestCr4));
5987
5988 /*
5989 * Setup VT-x's view of the guest CR4.
5990 *
5991 * If we're emulating real-mode using virtual-8086 mode, we want to redirect software
5992 * interrupts to the 8086 program interrupt handler. Clear the VME bit (the interrupt
5993 * redirection bitmap is already all 0, see hmR3InitFinalizeR0())
5994 *
5995 * See Intel spec. 20.2 "Software Interrupt Handling Methods While in Virtual-8086 Mode".
5996 */
5997 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
5998 {
5999 Assert(pVM->hm.s.vmx.pRealModeTSS);
6000 Assert(PDMVmmDevHeapIsEnabled(pVM));
6001 u64GuestCr4 &= ~(uint64_t)X86_CR4_VME;
6002 }
6003
6004 if (pVM->hmr0.s.fNestedPaging)
6005 {
6006 if ( !CPUMIsGuestPagingEnabledEx(pCtx)
6007 && !pVM->hmr0.s.vmx.fUnrestrictedGuest)
6008 {
6009 /* We use 4 MB pages in our identity mapping page table when the guest doesn't have paging. */
6010 u64GuestCr4 |= X86_CR4_PSE;
6011 /* Our identity mapping is a 32-bit page directory. */
6012 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
6013 }
6014 /* else use guest CR4.*/
6015 }
6016 else
6017 {
6018 Assert(!pVmxTransient->fIsNestedGuest);
6019
6020 /*
6021 * The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
6022 * paging mode and thus we need to adjust VT-x's view of CR4 depending on our shadow page tables.
6023 */
6024 switch (pVCpu->hm.s.enmShadowMode)
6025 {
6026 case PGMMODE_REAL: /* Real-mode. */
6027 case PGMMODE_PROTECTED: /* Protected mode without paging. */
6028 case PGMMODE_32_BIT: /* 32-bit paging. */
6029 {
6030 u64GuestCr4 &= ~(uint64_t)X86_CR4_PAE;
6031 break;
6032 }
6033
6034 case PGMMODE_PAE: /* PAE paging. */
6035 case PGMMODE_PAE_NX: /* PAE paging with NX. */
6036 {
6037 u64GuestCr4 |= X86_CR4_PAE;
6038 break;
6039 }
6040
6041 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
6042 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
6043 {
6044#ifdef VBOX_WITH_64_BITS_GUESTS
6045 /* For our assumption in hmR0VmxShouldSwapEferMsr. */
6046 Assert(u64GuestCr4 & X86_CR4_PAE);
6047 break;
6048#endif
6049 }
6050 default:
6051 AssertFailed();
6052 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
6053 }
6054 }
6055
6056 /* Apply the hardware specified CR4 fixed bits (mainly CR4.VMXE). */
6057 u64GuestCr4 |= fSetCr4;
6058 u64GuestCr4 &= fZapCr4;
6059
6060 /* Commit the CR4 and CR4 read-shadow to the guest VMCS. */
6061 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_CR4, u64GuestCr4); AssertRC(rc);
6062 rc = VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, u64ShadowCr4); AssertRC(rc);
6063
6064 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
6065 bool const fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
6066 if (fLoadSaveGuestXcr0 != pVCpu->hmr0.s.fLoadSaveGuestXcr0)
6067 {
6068 pVCpu->hmr0.s.fLoadSaveGuestXcr0 = fLoadSaveGuestXcr0;
6069 hmR0VmxUpdateStartVmFunction(pVCpu);
6070 }
6071
6072 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CR4);
6073
6074 Log4Func(("cr4=%#RX64 shadow=%#RX64 (set=%#RX64 zap=%#RX64)\n", u64GuestCr4, u64ShadowCr4, fSetCr4, fZapCr4));
6075 }
6076 return rc;
6077}
6078
6079
6080/**
6081 * Exports the guest debug registers into the guest-state area in the VMCS.
6082 * The guest debug bits are partially shared with the host (e.g. DR6, DR0-3).
6083 *
6084 * This also sets up whether \#DB and MOV DRx accesses cause VM-exits.
6085 *
6086 * @returns VBox status code.
6087 * @param pVCpu The cross context virtual CPU structure.
6088 * @param pVmxTransient The VMX-transient structure.
6089 *
6090 * @remarks No-long-jump zone!!!
6091 */
6092static int hmR0VmxExportSharedDebugState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
6093{
6094 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
6095
6096 /** @todo NSTVMX: Figure out what we want to do with nested-guest instruction
6097 * stepping. */
6098 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6099 if (pVmxTransient->fIsNestedGuest)
6100 {
6101 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, CPUMGetGuestDR7(pVCpu));
6102 AssertRC(rc);
6103
6104 /*
6105 * We don't want to always intercept MOV DRx for nested-guests as it causes
6106 * problems when the nested hypervisor isn't intercepting them, see @bugref{10080}.
6107 * Instead, they are strictly only requested when the nested hypervisor intercepts
6108 * them -- handled while merging VMCS controls.
6109 *
6110 * If neither the outer nor the nested-hypervisor is intercepting MOV DRx,
6111 * then the nested-guest debug state should be actively loaded on the host so that
6112 * nested-guest reads its own debug registers without causing VM-exits.
6113 */
6114 if ( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT)
6115 && !CPUMIsGuestDebugStateActive(pVCpu))
6116 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
6117 return VINF_SUCCESS;
6118 }
6119
6120#ifdef VBOX_STRICT
6121 /* Validate. Intel spec. 26.3.1.1 "Checks on Guest Controls Registers, Debug Registers, MSRs" */
6122 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
6123 {
6124 /* Validate. Intel spec. 17.2 "Debug Registers", recompiler paranoia checks. */
6125 Assert((pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0);
6126 Assert((pVCpu->cpum.GstCtx.dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
6127 }
6128#endif
6129
6130 bool fSteppingDB = false;
6131 bool fInterceptMovDRx = false;
6132 uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
6133 if (pVCpu->hm.s.fSingleInstruction)
6134 {
6135 /* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
6136 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_MONITOR_TRAP_FLAG)
6137 {
6138 uProcCtls |= VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
6139 Assert(fSteppingDB == false);
6140 }
6141 else
6142 {
6143 pVCpu->cpum.GstCtx.eflags.u32 |= X86_EFL_TF;
6144 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_RFLAGS;
6145 pVCpu->hmr0.s.fClearTrapFlag = true;
6146 fSteppingDB = true;
6147 }
6148 }
6149
6150 uint64_t u64GuestDr7;
6151 if ( fSteppingDB
6152 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
6153 {
6154 /*
6155 * Use the combined guest and host DRx values found in the hypervisor register set
6156 * because the hypervisor debugger has breakpoints active or someone is single stepping
6157 * on the host side without a monitor trap flag.
6158 *
6159 * Note! DBGF expects a clean DR6 state before executing guest code.
6160 */
6161 if (!CPUMIsHyperDebugStateActive(pVCpu))
6162 {
6163 CPUMR0LoadHyperDebugState(pVCpu, true /* include DR6 */);
6164 Assert(CPUMIsHyperDebugStateActive(pVCpu));
6165 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
6166 }
6167
6168 /* Update DR7 with the hypervisor value (other DRx registers are handled by CPUM one way or another). */
6169 u64GuestDr7 = CPUMGetHyperDR7(pVCpu);
6170 pVCpu->hmr0.s.fUsingHyperDR7 = true;
6171 fInterceptMovDRx = true;
6172 }
6173 else
6174 {
6175 /*
6176 * If the guest has enabled debug registers, we need to load them prior to
6177 * executing guest code so they'll trigger at the right time.
6178 */
6179 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
6180 if (pVCpu->cpum.GstCtx.dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
6181 {
6182 if (!CPUMIsGuestDebugStateActive(pVCpu))
6183 {
6184 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
6185 Assert(CPUMIsGuestDebugStateActive(pVCpu));
6186 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
6187 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
6188 }
6189 Assert(!fInterceptMovDRx);
6190 }
6191 else if (!CPUMIsGuestDebugStateActive(pVCpu))
6192 {
6193 /*
6194 * If no debugging enabled, we'll lazy load DR0-3. Unlike on AMD-V, we
6195 * must intercept #DB in order to maintain a correct DR6 guest value, and
6196 * because we need to intercept it to prevent nested #DBs from hanging the
6197 * CPU, we end up always having to intercept it. See hmR0VmxSetupVmcsXcptBitmap().
6198 */
6199 fInterceptMovDRx = true;
6200 }
6201
6202 /* Update DR7 with the actual guest value. */
6203 u64GuestDr7 = pVCpu->cpum.GstCtx.dr[7];
6204 pVCpu->hmr0.s.fUsingHyperDR7 = false;
6205 }
6206
6207 if (fInterceptMovDRx)
6208 uProcCtls |= VMX_PROC_CTLS_MOV_DR_EXIT;
6209 else
6210 uProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
6211
6212 /*
6213 * Update the processor-based VM-execution controls with the MOV-DRx intercepts and the
6214 * monitor-trap flag and update our cache.
6215 */
6216 if (uProcCtls != pVmcsInfo->u32ProcCtls)
6217 {
6218 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
6219 AssertRC(rc);
6220 pVmcsInfo->u32ProcCtls = uProcCtls;
6221 }
6222
6223 /*
6224 * Update guest DR7.
6225 */
6226 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, u64GuestDr7);
6227 AssertRC(rc);
6228
6229 /*
6230 * If we have forced EFLAGS.TF to be set because we're single-stepping in the hypervisor debugger,
6231 * we need to clear interrupt inhibition if any as otherwise it causes a VM-entry failure.
6232 *
6233 * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
6234 */
6235 if (fSteppingDB)
6236 {
6237 Assert(pVCpu->hm.s.fSingleInstruction);
6238 Assert(pVCpu->cpum.GstCtx.eflags.Bits.u1TF);
6239
6240 uint32_t fIntrState = 0;
6241 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
6242 AssertRC(rc);
6243
6244 if (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
6245 {
6246 fIntrState &= ~(VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
6247 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
6248 AssertRC(rc);
6249 }
6250 }
6251
6252 return VINF_SUCCESS;
6253}
6254
6255
6256#ifdef VBOX_STRICT
6257/**
6258 * Strict function to validate segment registers.
6259 *
6260 * @param pVCpu The cross context virtual CPU structure.
6261 * @param pVmcsInfo The VMCS info. object.
6262 *
6263 * @remarks Will import guest CR0 on strict builds during validation of
6264 * segments.
6265 */
6266static void hmR0VmxValidateSegmentRegs(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo)
6267{
6268 /*
6269 * Validate segment registers. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
6270 *
6271 * The reason we check for attribute value 0 in this function and not just the unusable bit is
6272 * because hmR0VmxExportGuestSegReg() only updates the VMCS' copy of the value with the
6273 * unusable bit and doesn't change the guest-context value.
6274 */
6275 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6276 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6277 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR0);
6278 if ( !pVM->hmr0.s.vmx.fUnrestrictedGuest
6279 && ( !CPUMIsGuestInRealModeEx(pCtx)
6280 && !CPUMIsGuestInV86ModeEx(pCtx)))
6281 {
6282 /* Protected mode checks */
6283 /* CS */
6284 Assert(pCtx->cs.Attr.n.u1Present);
6285 Assert(!(pCtx->cs.Attr.u & 0xf00));
6286 Assert(!(pCtx->cs.Attr.u & 0xfffe0000));
6287 Assert( (pCtx->cs.u32Limit & 0xfff) == 0xfff
6288 || !(pCtx->cs.Attr.n.u1Granularity));
6289 Assert( !(pCtx->cs.u32Limit & 0xfff00000)
6290 || (pCtx->cs.Attr.n.u1Granularity));
6291 /* CS cannot be loaded with NULL in protected mode. */
6292 Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS? */
6293 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
6294 Assert(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl);
6295 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
6296 Assert(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl);
6297 else
6298 AssertMsgFailed(("Invalid CS Type %#x\n", pCtx->cs.Attr.n.u2Dpl));
6299 /* SS */
6300 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
6301 Assert(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL));
6302 if ( !(pCtx->cr0 & X86_CR0_PE)
6303 || pCtx->cs.Attr.n.u4Type == 3)
6304 {
6305 Assert(!pCtx->ss.Attr.n.u2Dpl);
6306 }
6307 if (pCtx->ss.Attr.u && !(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
6308 {
6309 Assert((pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL));
6310 Assert(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7);
6311 Assert(pCtx->ss.Attr.n.u1Present);
6312 Assert(!(pCtx->ss.Attr.u & 0xf00));
6313 Assert(!(pCtx->ss.Attr.u & 0xfffe0000));
6314 Assert( (pCtx->ss.u32Limit & 0xfff) == 0xfff
6315 || !(pCtx->ss.Attr.n.u1Granularity));
6316 Assert( !(pCtx->ss.u32Limit & 0xfff00000)
6317 || (pCtx->ss.Attr.n.u1Granularity));
6318 }
6319 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSegReg(). */
6320 if (pCtx->ds.Attr.u && !(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
6321 {
6322 Assert(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6323 Assert(pCtx->ds.Attr.n.u1Present);
6324 Assert(pCtx->ds.Attr.n.u4Type > 11 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL));
6325 Assert(!(pCtx->ds.Attr.u & 0xf00));
6326 Assert(!(pCtx->ds.Attr.u & 0xfffe0000));
6327 Assert( (pCtx->ds.u32Limit & 0xfff) == 0xfff
6328 || !(pCtx->ds.Attr.n.u1Granularity));
6329 Assert( !(pCtx->ds.u32Limit & 0xfff00000)
6330 || (pCtx->ds.Attr.n.u1Granularity));
6331 Assert( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6332 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ));
6333 }
6334 if (pCtx->es.Attr.u && !(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
6335 {
6336 Assert(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6337 Assert(pCtx->es.Attr.n.u1Present);
6338 Assert(pCtx->es.Attr.n.u4Type > 11 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL));
6339 Assert(!(pCtx->es.Attr.u & 0xf00));
6340 Assert(!(pCtx->es.Attr.u & 0xfffe0000));
6341 Assert( (pCtx->es.u32Limit & 0xfff) == 0xfff
6342 || !(pCtx->es.Attr.n.u1Granularity));
6343 Assert( !(pCtx->es.u32Limit & 0xfff00000)
6344 || (pCtx->es.Attr.n.u1Granularity));
6345 Assert( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6346 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ));
6347 }
6348 if (pCtx->fs.Attr.u && !(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
6349 {
6350 Assert(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6351 Assert(pCtx->fs.Attr.n.u1Present);
6352 Assert(pCtx->fs.Attr.n.u4Type > 11 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL));
6353 Assert(!(pCtx->fs.Attr.u & 0xf00));
6354 Assert(!(pCtx->fs.Attr.u & 0xfffe0000));
6355 Assert( (pCtx->fs.u32Limit & 0xfff) == 0xfff
6356 || !(pCtx->fs.Attr.n.u1Granularity));
6357 Assert( !(pCtx->fs.u32Limit & 0xfff00000)
6358 || (pCtx->fs.Attr.n.u1Granularity));
6359 Assert( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6360 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ));
6361 }
6362 if (pCtx->gs.Attr.u && !(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
6363 {
6364 Assert(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED);
6365 Assert(pCtx->gs.Attr.n.u1Present);
6366 Assert(pCtx->gs.Attr.n.u4Type > 11 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL));
6367 Assert(!(pCtx->gs.Attr.u & 0xf00));
6368 Assert(!(pCtx->gs.Attr.u & 0xfffe0000));
6369 Assert( (pCtx->gs.u32Limit & 0xfff) == 0xfff
6370 || !(pCtx->gs.Attr.n.u1Granularity));
6371 Assert( !(pCtx->gs.u32Limit & 0xfff00000)
6372 || (pCtx->gs.Attr.n.u1Granularity));
6373 Assert( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
6374 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ));
6375 }
6376 /* 64-bit capable CPUs. */
6377 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6378 Assert(!pCtx->ss.Attr.u || !RT_HI_U32(pCtx->ss.u64Base));
6379 Assert(!pCtx->ds.Attr.u || !RT_HI_U32(pCtx->ds.u64Base));
6380 Assert(!pCtx->es.Attr.u || !RT_HI_U32(pCtx->es.u64Base));
6381 }
6382 else if ( CPUMIsGuestInV86ModeEx(pCtx)
6383 || ( CPUMIsGuestInRealModeEx(pCtx)
6384 && !pVM->hmr0.s.vmx.fUnrestrictedGuest))
6385 {
6386 /* Real and v86 mode checks. */
6387 /* hmR0VmxExportGuestSegReg() writes the modified in VMCS. We want what we're feeding to VT-x. */
6388 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
6389 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
6390 {
6391 u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3;
6392 u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
6393 }
6394 else
6395 {
6396 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u; u32DSAttr = pCtx->ds.Attr.u;
6397 u32ESAttr = pCtx->es.Attr.u; u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
6398 }
6399
6400 /* CS */
6401 AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
6402 Assert(pCtx->cs.u32Limit == 0xffff);
6403 Assert(u32CSAttr == 0xf3);
6404 /* SS */
6405 Assert(pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4);
6406 Assert(pCtx->ss.u32Limit == 0xffff);
6407 Assert(u32SSAttr == 0xf3);
6408 /* DS */
6409 Assert(pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4);
6410 Assert(pCtx->ds.u32Limit == 0xffff);
6411 Assert(u32DSAttr == 0xf3);
6412 /* ES */
6413 Assert(pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4);
6414 Assert(pCtx->es.u32Limit == 0xffff);
6415 Assert(u32ESAttr == 0xf3);
6416 /* FS */
6417 Assert(pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4);
6418 Assert(pCtx->fs.u32Limit == 0xffff);
6419 Assert(u32FSAttr == 0xf3);
6420 /* GS */
6421 Assert(pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4);
6422 Assert(pCtx->gs.u32Limit == 0xffff);
6423 Assert(u32GSAttr == 0xf3);
6424 /* 64-bit capable CPUs. */
6425 Assert(!RT_HI_U32(pCtx->cs.u64Base));
6426 Assert(!u32SSAttr || !RT_HI_U32(pCtx->ss.u64Base));
6427 Assert(!u32DSAttr || !RT_HI_U32(pCtx->ds.u64Base));
6428 Assert(!u32ESAttr || !RT_HI_U32(pCtx->es.u64Base));
6429 }
6430}
6431#endif /* VBOX_STRICT */
6432
6433
6434/**
6435 * Exports a guest segment register into the guest-state area in the VMCS.
6436 *
6437 * @returns VBox status code.
6438 * @param pVCpu The cross context virtual CPU structure.
6439 * @param pVmcsInfo The VMCS info. object.
6440 * @param iSegReg The segment register number (X86_SREG_XXX).
6441 * @param pSelReg Pointer to the segment selector.
6442 *
6443 * @remarks No-long-jump zone!!!
6444 */
6445static int hmR0VmxExportGuestSegReg(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo, uint32_t iSegReg, PCCPUMSELREG pSelReg)
6446{
6447 Assert(iSegReg < X86_SREG_COUNT);
6448
6449 uint32_t u32Access = pSelReg->Attr.u;
6450 if (!pVmcsInfo->pShared->RealMode.fRealOnV86Active)
6451 {
6452 /*
6453 * The way to differentiate between whether this is really a null selector or was just
6454 * a selector loaded with 0 in real-mode is using the segment attributes. A selector
6455 * loaded in real-mode with the value 0 is valid and usable in protected-mode and we
6456 * should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures
6457 * NULL selectors loaded in protected-mode have their attribute as 0.
6458 */
6459 if (u32Access)
6460 { }
6461 else
6462 u32Access = X86DESCATTR_UNUSABLE;
6463 }
6464 else
6465 {
6466 /* VT-x requires our real-using-v86 mode hack to override the segment access-right bits. */
6467 u32Access = 0xf3;
6468 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.pRealModeTSS);
6469 Assert(PDMVmmDevHeapIsEnabled(pVCpu->CTX_SUFF(pVM)));
6470 RT_NOREF_PV(pVCpu);
6471 }
6472
6473 /* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
6474 AssertMsg((u32Access & X86DESCATTR_UNUSABLE) || (u32Access & X86_SEL_TYPE_ACCESSED),
6475 ("Access bit not set for usable segment. %.2s sel=%#x attr %#x\n", "ESCSSSDSFSGS" + iSegReg * 2, pSelReg, pSelReg->Attr.u));
6476
6477 /*
6478 * Commit it to the VMCS.
6479 */
6480 Assert((uint32_t)VMX_VMCS16_GUEST_SEG_SEL(iSegReg) == g_aVmcsSegSel[iSegReg]);
6481 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg) == g_aVmcsSegLimit[iSegReg]);
6482 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg) == g_aVmcsSegAttr[iSegReg]);
6483 Assert((uint32_t)VMX_VMCS_GUEST_SEG_BASE(iSegReg) == g_aVmcsSegBase[iSegReg]);
6484 int rc = VMXWriteVmcs32(VMX_VMCS16_GUEST_SEG_SEL(iSegReg), pSelReg->Sel); AssertRC(rc);
6485 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg), pSelReg->u32Limit); AssertRC(rc);
6486 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SEG_BASE(iSegReg), pSelReg->u64Base); AssertRC(rc);
6487 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg), u32Access); AssertRC(rc);
6488 return VINF_SUCCESS;
6489}
6490
6491
6492/**
6493 * Exports the guest segment registers, GDTR, IDTR, LDTR, TR into the guest-state
6494 * area in the VMCS.
6495 *
6496 * @returns VBox status code.
6497 * @param pVCpu The cross context virtual CPU structure.
6498 * @param pVmxTransient The VMX-transient structure.
6499 *
6500 * @remarks Will import guest CR0 on strict builds during validation of
6501 * segments.
6502 * @remarks No-long-jump zone!!!
6503 */
6504static int hmR0VmxExportGuestSegRegsXdtr(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6505{
6506 int rc = VERR_INTERNAL_ERROR_5;
6507 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6508 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6509 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6510 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
6511
6512 /*
6513 * Guest Segment registers: CS, SS, DS, ES, FS, GS.
6514 */
6515 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SREG_MASK)
6516 {
6517 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_CS)
6518 {
6519 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CS);
6520 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6521 pVmcsInfoShared->RealMode.AttrCS.u = pCtx->cs.Attr.u;
6522 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_CS, &pCtx->cs);
6523 AssertRC(rc);
6524 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_CS);
6525 }
6526
6527 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SS)
6528 {
6529 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SS);
6530 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6531 pVmcsInfoShared->RealMode.AttrSS.u = pCtx->ss.Attr.u;
6532 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_SS, &pCtx->ss);
6533 AssertRC(rc);
6534 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SS);
6535 }
6536
6537 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_DS)
6538 {
6539 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DS);
6540 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6541 pVmcsInfoShared->RealMode.AttrDS.u = pCtx->ds.Attr.u;
6542 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_DS, &pCtx->ds);
6543 AssertRC(rc);
6544 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_DS);
6545 }
6546
6547 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_ES)
6548 {
6549 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_ES);
6550 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6551 pVmcsInfoShared->RealMode.AttrES.u = pCtx->es.Attr.u;
6552 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_ES, &pCtx->es);
6553 AssertRC(rc);
6554 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_ES);
6555 }
6556
6557 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_FS)
6558 {
6559 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_FS);
6560 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6561 pVmcsInfoShared->RealMode.AttrFS.u = pCtx->fs.Attr.u;
6562 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_FS, &pCtx->fs);
6563 AssertRC(rc);
6564 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_FS);
6565 }
6566
6567 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GS)
6568 {
6569 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GS);
6570 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
6571 pVmcsInfoShared->RealMode.AttrGS.u = pCtx->gs.Attr.u;
6572 rc = hmR0VmxExportGuestSegReg(pVCpu, pVmcsInfo, X86_SREG_GS, &pCtx->gs);
6573 AssertRC(rc);
6574 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GS);
6575 }
6576
6577#ifdef VBOX_STRICT
6578 hmR0VmxValidateSegmentRegs(pVCpu, pVmcsInfo);
6579#endif
6580 Log4Func(("cs={%#04x base=%#RX64 limit=%#RX32 attr=%#RX32}\n", pCtx->cs.Sel, pCtx->cs.u64Base, pCtx->cs.u32Limit,
6581 pCtx->cs.Attr.u));
6582 }
6583
6584 /*
6585 * Guest TR.
6586 */
6587 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_TR)
6588 {
6589 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_TR);
6590
6591 /*
6592 * Real-mode emulation using virtual-8086 mode with CR4.VME. Interrupt redirection is
6593 * achieved using the interrupt redirection bitmap (all bits cleared to let the guest
6594 * handle INT-n's) in the TSS. See hmR3InitFinalizeR0() to see how pRealModeTSS is setup.
6595 */
6596 uint16_t u16Sel;
6597 uint32_t u32Limit;
6598 uint64_t u64Base;
6599 uint32_t u32AccessRights;
6600 if (!pVmcsInfoShared->RealMode.fRealOnV86Active)
6601 {
6602 u16Sel = pCtx->tr.Sel;
6603 u32Limit = pCtx->tr.u32Limit;
6604 u64Base = pCtx->tr.u64Base;
6605 u32AccessRights = pCtx->tr.Attr.u;
6606 }
6607 else
6608 {
6609 Assert(!pVmxTransient->fIsNestedGuest);
6610 Assert(pVM->hm.s.vmx.pRealModeTSS);
6611 Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMCanExecuteGuest() -XXX- what about inner loop changes? */
6612
6613 /* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
6614 RTGCPHYS GCPhys;
6615 rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
6616 AssertRCReturn(rc, rc);
6617
6618 X86DESCATTR DescAttr;
6619 DescAttr.u = 0;
6620 DescAttr.n.u1Present = 1;
6621 DescAttr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
6622
6623 u16Sel = 0;
6624 u32Limit = HM_VTX_TSS_SIZE;
6625 u64Base = GCPhys;
6626 u32AccessRights = DescAttr.u;
6627 }
6628
6629 /* Validate. */
6630 Assert(!(u16Sel & RT_BIT(2)));
6631 AssertMsg( (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY
6632 || (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
6633 AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
6634 Assert(!(u32AccessRights & RT_BIT(4))); /* System MBZ.*/
6635 Assert(u32AccessRights & RT_BIT(7)); /* Present MB1.*/
6636 Assert(!(u32AccessRights & 0xf00)); /* 11:8 MBZ. */
6637 Assert(!(u32AccessRights & 0xfffe0000)); /* 31:17 MBZ. */
6638 Assert( (u32Limit & 0xfff) == 0xfff
6639 || !(u32AccessRights & RT_BIT(15))); /* Granularity MBZ. */
6640 Assert( !(pCtx->tr.u32Limit & 0xfff00000)
6641 || (u32AccessRights & RT_BIT(15))); /* Granularity MB1. */
6642
6643 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_TR_SEL, u16Sel); AssertRC(rc);
6644 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, u32Limit); AssertRC(rc);
6645 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, u32AccessRights); AssertRC(rc);
6646 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_TR_BASE, u64Base); AssertRC(rc);
6647
6648 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_TR);
6649 Log4Func(("tr base=%#RX64 limit=%#RX32\n", pCtx->tr.u64Base, pCtx->tr.u32Limit));
6650 }
6651
6652 /*
6653 * Guest GDTR.
6654 */
6655 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_GDTR)
6656 {
6657 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_GDTR);
6658
6659 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt); AssertRC(rc);
6660 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, pCtx->gdtr.pGdt); AssertRC(rc);
6661
6662 /* Validate. */
6663 Assert(!(pCtx->gdtr.cbGdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6664
6665 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_GDTR);
6666 Log4Func(("gdtr base=%#RX64 limit=%#RX32\n", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt));
6667 }
6668
6669 /*
6670 * Guest LDTR.
6671 */
6672 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_LDTR)
6673 {
6674 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_LDTR);
6675
6676 /* The unusable bit is specific to VT-x, if it's a null selector mark it as an unusable segment. */
6677 uint32_t u32Access;
6678 if ( !pVmxTransient->fIsNestedGuest
6679 && !pCtx->ldtr.Attr.u)
6680 u32Access = X86DESCATTR_UNUSABLE;
6681 else
6682 u32Access = pCtx->ldtr.Attr.u;
6683
6684 rc = VMXWriteVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, pCtx->ldtr.Sel); AssertRC(rc);
6685 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit); AssertRC(rc);
6686 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, u32Access); AssertRC(rc);
6687 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, pCtx->ldtr.u64Base); AssertRC(rc);
6688
6689 /* Validate. */
6690 if (!(u32Access & X86DESCATTR_UNUSABLE))
6691 {
6692 Assert(!(pCtx->ldtr.Sel & RT_BIT(2))); /* TI MBZ. */
6693 Assert(pCtx->ldtr.Attr.n.u4Type == 2); /* Type MB2 (LDT). */
6694 Assert(!pCtx->ldtr.Attr.n.u1DescType); /* System MBZ. */
6695 Assert(pCtx->ldtr.Attr.n.u1Present == 1); /* Present MB1. */
6696 Assert(!pCtx->ldtr.Attr.n.u4LimitHigh); /* 11:8 MBZ. */
6697 Assert(!(pCtx->ldtr.Attr.u & 0xfffe0000)); /* 31:17 MBZ. */
6698 Assert( (pCtx->ldtr.u32Limit & 0xfff) == 0xfff
6699 || !pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MBZ. */
6700 Assert( !(pCtx->ldtr.u32Limit & 0xfff00000)
6701 || pCtx->ldtr.Attr.n.u1Granularity); /* Granularity MB1. */
6702 }
6703
6704 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_LDTR);
6705 Log4Func(("ldtr base=%#RX64 limit=%#RX32\n", pCtx->ldtr.u64Base, pCtx->ldtr.u32Limit));
6706 }
6707
6708 /*
6709 * Guest IDTR.
6710 */
6711 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_IDTR)
6712 {
6713 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_IDTR);
6714
6715 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt); AssertRC(rc);
6716 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, pCtx->idtr.pIdt); AssertRC(rc);
6717
6718 /* Validate. */
6719 Assert(!(pCtx->idtr.cbIdt & 0xffff0000)); /* Bits 31:16 MBZ. */
6720
6721 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_IDTR);
6722 Log4Func(("idtr base=%#RX64 limit=%#RX32\n", pCtx->idtr.pIdt, pCtx->idtr.cbIdt));
6723 }
6724
6725 return VINF_SUCCESS;
6726}
6727
6728
6729/**
6730 * Exports certain guest MSRs into the VM-entry MSR-load and VM-exit MSR-store
6731 * areas.
6732 *
6733 * These MSRs will automatically be loaded to the host CPU on every successful
6734 * VM-entry and stored from the host CPU on every successful VM-exit.
6735 *
6736 * We creates/updates MSR slots for the host MSRs in the VM-exit MSR-load area. The
6737 * actual host MSR values are not- updated here for performance reasons. See
6738 * hmR0VmxExportHostMsrs().
6739 *
6740 * We also exports the guest sysenter MSRs into the guest-state area in the VMCS.
6741 *
6742 * @returns VBox status code.
6743 * @param pVCpu The cross context virtual CPU structure.
6744 * @param pVmxTransient The VMX-transient structure.
6745 *
6746 * @remarks No-long-jump zone!!!
6747 */
6748static int hmR0VmxExportGuestMsrs(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6749{
6750 AssertPtr(pVCpu);
6751 AssertPtr(pVmxTransient);
6752
6753 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
6754 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
6755
6756 /*
6757 * MSRs that we use the auto-load/store MSR area in the VMCS.
6758 * For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(),
6759 * nothing to do here. The host MSR values are updated when it's safe in
6760 * hmR0VmxLazySaveHostMsrs().
6761 *
6762 * For nested-guests, the guests MSRs from the VM-entry MSR-load area are already
6763 * loaded (into the guest-CPU context) by the VMLAUNCH/VMRESUME instruction
6764 * emulation. The merged MSR permission bitmap will ensure that we get VM-exits
6765 * for any MSR that are not part of the lazy MSRs so we do not need to place
6766 * those MSRs into the auto-load/store MSR area. Nothing to do here.
6767 */
6768 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_GUEST_AUTO_MSRS)
6769 {
6770 /* No auto-load/store MSRs currently. */
6771 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_VMX_GUEST_AUTO_MSRS);
6772 }
6773
6774 /*
6775 * Guest Sysenter MSRs.
6776 */
6777 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_MSR_MASK)
6778 {
6779 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SYSENTER_MSRS);
6780
6781 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_CS_MSR)
6782 {
6783 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
6784 AssertRC(rc);
6785 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_CS_MSR);
6786 }
6787
6788 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_EIP_MSR)
6789 {
6790 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
6791 AssertRC(rc);
6792 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
6793 }
6794
6795 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_SYSENTER_ESP_MSR)
6796 {
6797 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
6798 AssertRC(rc);
6799 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
6800 }
6801 }
6802
6803 /*
6804 * Guest/host EFER MSR.
6805 */
6806 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_EFER_MSR)
6807 {
6808 /* Whether we are using the VMCS to swap the EFER MSR must have been
6809 determined earlier while exporting VM-entry/VM-exit controls. */
6810 Assert(!(ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_VMX_ENTRY_EXIT_CTLS));
6811 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
6812
6813 if (hmR0VmxShouldSwapEferMsr(pVCpu, pVmxTransient))
6814 {
6815 /*
6816 * EFER.LME is written by software, while EFER.LMA is set by the CPU to (CR0.PG & EFER.LME).
6817 * This means a guest can set EFER.LME=1 while CR0.PG=0 and EFER.LMA can remain 0.
6818 * VT-x requires that "IA-32e mode guest" VM-entry control must be identical to EFER.LMA
6819 * and to CR0.PG. Without unrestricted execution, CR0.PG (used for VT-x, not the shadow)
6820 * must always be 1. This forces us to effectively clear both EFER.LMA and EFER.LME until
6821 * the guest has also set CR0.PG=1. Otherwise, we would run into an invalid-guest state
6822 * during VM-entry.
6823 */
6824 uint64_t uGuestEferMsr = pCtx->msrEFER;
6825 if (!pVM->hmr0.s.vmx.fUnrestrictedGuest)
6826 {
6827 if (!(pCtx->msrEFER & MSR_K6_EFER_LMA))
6828 uGuestEferMsr &= ~MSR_K6_EFER_LME;
6829 else
6830 Assert((pCtx->msrEFER & (MSR_K6_EFER_LMA | MSR_K6_EFER_LME)) == (MSR_K6_EFER_LMA | MSR_K6_EFER_LME));
6831 }
6832
6833 /*
6834 * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
6835 * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
6836 */
6837 if (g_fHmVmxSupportsVmcsEfer)
6838 {
6839 int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, uGuestEferMsr);
6840 AssertRC(rc);
6841 }
6842 else
6843 {
6844 /*
6845 * We shall use the auto-load/store MSR area only for loading the EFER MSR but we must
6846 * continue to intercept guest read and write accesses to it, see @bugref{7386#c16}.
6847 */
6848 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER, uGuestEferMsr,
6849 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6850 AssertRCReturn(rc, rc);
6851 }
6852
6853 Log4Func(("efer=%#RX64 shadow=%#RX64\n", uGuestEferMsr, pCtx->msrEFER));
6854 }
6855 else if (!g_fHmVmxSupportsVmcsEfer)
6856 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K6_EFER);
6857
6858 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_EFER_MSR);
6859 }
6860
6861 /*
6862 * Other MSRs.
6863 */
6864 if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_OTHER_MSRS)
6865 {
6866 /* Speculation Control (R/W). */
6867 HMVMX_CPUMCTX_ASSERT(pVCpu, HM_CHANGED_GUEST_OTHER_MSRS);
6868 if (pVM->cpum.ro.GuestFeatures.fIbrs)
6869 {
6870 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_IA32_SPEC_CTRL, CPUMGetGuestSpecCtrl(pVCpu),
6871 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6872 AssertRCReturn(rc, rc);
6873 }
6874
6875 /* Last Branch Record. */
6876 if (pVM->hmr0.s.vmx.fLbr)
6877 {
6878 PVMXVMCSINFOSHARED const pVmcsInfoShared = pVmxTransient->pVmcsInfo->pShared;
6879 uint32_t const idFromIpMsrStart = pVM->hmr0.s.vmx.idLbrFromIpMsrFirst;
6880 uint32_t const idToIpMsrStart = pVM->hmr0.s.vmx.idLbrToIpMsrFirst;
6881 uint32_t const cLbrStack = pVM->hmr0.s.vmx.idLbrFromIpMsrLast - pVM->hmr0.s.vmx.idLbrFromIpMsrFirst + 1;
6882 Assert(cLbrStack <= 32);
6883 for (uint32_t i = 0; i < cLbrStack; i++)
6884 {
6885 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, idFromIpMsrStart + i,
6886 pVmcsInfoShared->au64LbrFromIpMsr[i],
6887 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6888 AssertRCReturn(rc, rc);
6889
6890 /* Some CPUs don't have a Branch-To-IP MSR (P4 and related Xeons). */
6891 if (idToIpMsrStart != 0)
6892 {
6893 rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, idToIpMsrStart + i,
6894 pVmcsInfoShared->au64LbrToIpMsr[i],
6895 false /* fSetReadWrite */, false /* fUpdateHostMsr */);
6896 AssertRCReturn(rc, rc);
6897 }
6898 }
6899
6900 /* Add LBR top-of-stack MSR (which contains the index to the most recent record). */
6901 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, pVM->hmr0.s.vmx.idLbrTosMsr,
6902 pVmcsInfoShared->u64LbrTosMsr, false /* fSetReadWrite */,
6903 false /* fUpdateHostMsr */);
6904 AssertRCReturn(rc, rc);
6905 }
6906
6907 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
6908 }
6909
6910 return VINF_SUCCESS;
6911}
6912
6913
6914/**
6915 * Wrapper for running the guest code in VT-x.
6916 *
6917 * @returns VBox status code, no informational status codes.
6918 * @param pVCpu The cross context virtual CPU structure.
6919 * @param pVmxTransient The VMX-transient structure.
6920 *
6921 * @remarks No-long-jump zone!!!
6922 */
6923DECLINLINE(int) hmR0VmxRunGuest(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient)
6924{
6925 /* Mark that HM is the keeper of all guest-CPU registers now that we're going to execute guest code. */
6926 pVCpu->cpum.GstCtx.fExtrn |= HMVMX_CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_KEEPER_HM;
6927
6928 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
6929 bool const fResumeVM = RT_BOOL(pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_LAUNCHED);
6930#ifdef VBOX_WITH_STATISTICS
6931 if (fResumeVM)
6932 STAM_COUNTER_INC(&pVCpu->hm.s.StatVmxVmResume);
6933 else
6934 STAM_COUNTER_INC(&pVCpu->hm.s.StatVmxVmLaunch);
6935#endif
6936 int rc = pVCpu->hmr0.s.vmx.pfnStartVm(pVmcsInfo, pVCpu, fResumeVM);
6937 AssertMsg(rc <= VINF_SUCCESS, ("%Rrc\n", rc));
6938 return rc;
6939}
6940
6941
6942/**
6943 * Reports world-switch error and dumps some useful debug info.
6944 *
6945 * @param pVCpu The cross context virtual CPU structure.
6946 * @param rcVMRun The return code from VMLAUNCH/VMRESUME.
6947 * @param pVmxTransient The VMX-transient structure (only
6948 * exitReason updated).
6949 */
6950static void hmR0VmxReportWorldSwitchError(PVMCPUCC pVCpu, int rcVMRun, PVMXTRANSIENT pVmxTransient)
6951{
6952 Assert(pVCpu);
6953 Assert(pVmxTransient);
6954 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
6955
6956 Log4Func(("VM-entry failure: %Rrc\n", rcVMRun));
6957 switch (rcVMRun)
6958 {
6959 case VERR_VMX_INVALID_VMXON_PTR:
6960 AssertFailed();
6961 break;
6962 case VINF_SUCCESS: /* VMLAUNCH/VMRESUME succeeded but VM-entry failed... yeah, true story. */
6963 case VERR_VMX_UNABLE_TO_START_VM: /* VMLAUNCH/VMRESUME itself failed. */
6964 {
6965 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &pVCpu->hm.s.vmx.LastError.u32ExitReason);
6966 rc |= VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &pVCpu->hm.s.vmx.LastError.u32InstrError);
6967 AssertRC(rc);
6968 hmR0VmxReadExitQualVmcs(pVmxTransient);
6969
6970 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hmr0.s.idEnteredCpu;
6971 /* LastError.idCurrentCpu was already updated in hmR0VmxPreRunGuestCommitted().
6972 Cannot do it here as we may have been long preempted. */
6973
6974#ifdef VBOX_STRICT
6975 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
6976 Log4(("uExitReason %#RX32 (VmxTransient %#RX16)\n", pVCpu->hm.s.vmx.LastError.u32ExitReason,
6977 pVmxTransient->uExitReason));
6978 Log4(("Exit Qualification %#RX64\n", pVmxTransient->uExitQual));
6979 Log4(("InstrError %#RX32\n", pVCpu->hm.s.vmx.LastError.u32InstrError));
6980 if (pVCpu->hm.s.vmx.LastError.u32InstrError <= HMVMX_INSTR_ERROR_MAX)
6981 Log4(("InstrError Desc. \"%s\"\n", g_apszVmxInstrErrors[pVCpu->hm.s.vmx.LastError.u32InstrError]));
6982 else
6983 Log4(("InstrError Desc. Range exceeded %u\n", HMVMX_INSTR_ERROR_MAX));
6984 Log4(("Entered host CPU %u\n", pVCpu->hm.s.vmx.LastError.idEnteredCpu));
6985 Log4(("Current host CPU %u\n", pVCpu->hm.s.vmx.LastError.idCurrentCpu));
6986
6987 static struct
6988 {
6989 /** Name of the field to log. */
6990 const char *pszName;
6991 /** The VMCS field. */
6992 uint32_t uVmcsField;
6993 /** Whether host support of this field needs to be checked. */
6994 bool fCheckSupport;
6995 } const s_aVmcsFields[] =
6996 {
6997 { "VMX_VMCS32_CTRL_PIN_EXEC", VMX_VMCS32_CTRL_PIN_EXEC, false },
6998 { "VMX_VMCS32_CTRL_PROC_EXEC", VMX_VMCS32_CTRL_PROC_EXEC, false },
6999 { "VMX_VMCS32_CTRL_PROC_EXEC2", VMX_VMCS32_CTRL_PROC_EXEC2, true },
7000 { "VMX_VMCS32_CTRL_ENTRY", VMX_VMCS32_CTRL_ENTRY, false },
7001 { "VMX_VMCS32_CTRL_EXIT", VMX_VMCS32_CTRL_EXIT, false },
7002 { "VMX_VMCS32_CTRL_CR3_TARGET_COUNT", VMX_VMCS32_CTRL_CR3_TARGET_COUNT, false },
7003 { "VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO", VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, false },
7004 { "VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE", VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, false },
7005 { "VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH", VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, false },
7006 { "VMX_VMCS32_CTRL_TPR_THRESHOLD", VMX_VMCS32_CTRL_TPR_THRESHOLD, false },
7007 { "VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, false },
7008 { "VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT, false },
7009 { "VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT", VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, false },
7010 { "VMX_VMCS32_CTRL_EXCEPTION_BITMAP", VMX_VMCS32_CTRL_EXCEPTION_BITMAP, false },
7011 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, false },
7012 { "VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH", VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, false },
7013 { "VMX_VMCS_CTRL_CR0_MASK", VMX_VMCS_CTRL_CR0_MASK, false },
7014 { "VMX_VMCS_CTRL_CR0_READ_SHADOW", VMX_VMCS_CTRL_CR0_READ_SHADOW, false },
7015 { "VMX_VMCS_CTRL_CR4_MASK", VMX_VMCS_CTRL_CR4_MASK, false },
7016 { "VMX_VMCS_CTRL_CR4_READ_SHADOW", VMX_VMCS_CTRL_CR4_READ_SHADOW, false },
7017 { "VMX_VMCS64_CTRL_EPTP_FULL", VMX_VMCS64_CTRL_EPTP_FULL, true },
7018 { "VMX_VMCS_GUEST_RIP", VMX_VMCS_GUEST_RIP, false },
7019 { "VMX_VMCS_GUEST_RSP", VMX_VMCS_GUEST_RSP, false },
7020 { "VMX_VMCS_GUEST_RFLAGS", VMX_VMCS_GUEST_RFLAGS, false },
7021 { "VMX_VMCS16_VPID", VMX_VMCS16_VPID, true, },
7022 { "VMX_VMCS_HOST_CR0", VMX_VMCS_HOST_CR0, false },
7023 { "VMX_VMCS_HOST_CR3", VMX_VMCS_HOST_CR3, false },
7024 { "VMX_VMCS_HOST_CR4", VMX_VMCS_HOST_CR4, false },
7025 /* The order of selector fields below are fixed! */
7026 { "VMX_VMCS16_HOST_ES_SEL", VMX_VMCS16_HOST_ES_SEL, false },
7027 { "VMX_VMCS16_HOST_CS_SEL", VMX_VMCS16_HOST_CS_SEL, false },
7028 { "VMX_VMCS16_HOST_SS_SEL", VMX_VMCS16_HOST_SS_SEL, false },
7029 { "VMX_VMCS16_HOST_DS_SEL", VMX_VMCS16_HOST_DS_SEL, false },
7030 { "VMX_VMCS16_HOST_FS_SEL", VMX_VMCS16_HOST_FS_SEL, false },
7031 { "VMX_VMCS16_HOST_GS_SEL", VMX_VMCS16_HOST_GS_SEL, false },
7032 { "VMX_VMCS16_HOST_TR_SEL", VMX_VMCS16_HOST_TR_SEL, false },
7033 /* End of ordered selector fields. */
7034 { "VMX_VMCS_HOST_TR_BASE", VMX_VMCS_HOST_TR_BASE, false },
7035 { "VMX_VMCS_HOST_GDTR_BASE", VMX_VMCS_HOST_GDTR_BASE, false },
7036 { "VMX_VMCS_HOST_IDTR_BASE", VMX_VMCS_HOST_IDTR_BASE, false },
7037 { "VMX_VMCS32_HOST_SYSENTER_CS", VMX_VMCS32_HOST_SYSENTER_CS, false },
7038 { "VMX_VMCS_HOST_SYSENTER_EIP", VMX_VMCS_HOST_SYSENTER_EIP, false },
7039 { "VMX_VMCS_HOST_SYSENTER_ESP", VMX_VMCS_HOST_SYSENTER_ESP, false },
7040 { "VMX_VMCS_HOST_RSP", VMX_VMCS_HOST_RSP, false },
7041 { "VMX_VMCS_HOST_RIP", VMX_VMCS_HOST_RIP, false }
7042 };
7043
7044 RTGDTR HostGdtr;
7045 ASMGetGDTR(&HostGdtr);
7046
7047 uint32_t const cVmcsFields = RT_ELEMENTS(s_aVmcsFields);
7048 for (uint32_t i = 0; i < cVmcsFields; i++)
7049 {
7050 uint32_t const uVmcsField = s_aVmcsFields[i].uVmcsField;
7051
7052 bool fSupported;
7053 if (!s_aVmcsFields[i].fCheckSupport)
7054 fSupported = true;
7055 else
7056 {
7057 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7058 switch (uVmcsField)
7059 {
7060 case VMX_VMCS64_CTRL_EPTP_FULL: fSupported = pVM->hmr0.s.fNestedPaging; break;
7061 case VMX_VMCS16_VPID: fSupported = pVM->hmr0.s.vmx.fVpid; break;
7062 case VMX_VMCS32_CTRL_PROC_EXEC2:
7063 fSupported = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
7064 break;
7065 default:
7066 AssertMsgFailedReturnVoid(("Failed to provide VMCS field support for %#RX32\n", uVmcsField));
7067 }
7068 }
7069
7070 if (fSupported)
7071 {
7072 uint8_t const uWidth = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH);
7073 switch (uWidth)
7074 {
7075 case VMX_VMCSFIELD_WIDTH_16BIT:
7076 {
7077 uint16_t u16Val;
7078 rc = VMXReadVmcs16(uVmcsField, &u16Val);
7079 AssertRC(rc);
7080 Log4(("%-40s = %#RX16\n", s_aVmcsFields[i].pszName, u16Val));
7081
7082 if ( uVmcsField >= VMX_VMCS16_HOST_ES_SEL
7083 && uVmcsField <= VMX_VMCS16_HOST_TR_SEL)
7084 {
7085 if (u16Val < HostGdtr.cbGdt)
7086 {
7087 /* Order of selectors in s_apszSel is fixed and matches the order in s_aVmcsFields. */
7088 static const char * const s_apszSel[] = { "Host ES", "Host CS", "Host SS", "Host DS",
7089 "Host FS", "Host GS", "Host TR" };
7090 uint8_t const idxSel = RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_INDEX);
7091 Assert(idxSel < RT_ELEMENTS(s_apszSel));
7092 PCX86DESCHC pDesc = (PCX86DESCHC)(HostGdtr.pGdt + (u16Val & X86_SEL_MASK));
7093 hmR0DumpDescriptor(pDesc, u16Val, s_apszSel[idxSel]);
7094 }
7095 else
7096 Log4((" Selector value exceeds GDT limit!\n"));
7097 }
7098 break;
7099 }
7100
7101 case VMX_VMCSFIELD_WIDTH_32BIT:
7102 {
7103 uint32_t u32Val;
7104 rc = VMXReadVmcs32(uVmcsField, &u32Val);
7105 AssertRC(rc);
7106 Log4(("%-40s = %#RX32\n", s_aVmcsFields[i].pszName, u32Val));
7107 break;
7108 }
7109
7110 case VMX_VMCSFIELD_WIDTH_64BIT:
7111 case VMX_VMCSFIELD_WIDTH_NATURAL:
7112 {
7113 uint64_t u64Val;
7114 rc = VMXReadVmcs64(uVmcsField, &u64Val);
7115 AssertRC(rc);
7116 Log4(("%-40s = %#RX64\n", s_aVmcsFields[i].pszName, u64Val));
7117 break;
7118 }
7119 }
7120 }
7121 }
7122
7123 Log4(("MSR_K6_EFER = %#RX64\n", ASMRdMsr(MSR_K6_EFER)));
7124 Log4(("MSR_K8_CSTAR = %#RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
7125 Log4(("MSR_K8_LSTAR = %#RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
7126 Log4(("MSR_K6_STAR = %#RX64\n", ASMRdMsr(MSR_K6_STAR)));
7127 Log4(("MSR_K8_SF_MASK = %#RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
7128 Log4(("MSR_K8_KERNEL_GS_BASE = %#RX64\n", ASMRdMsr(MSR_K8_KERNEL_GS_BASE)));
7129#endif /* VBOX_STRICT */
7130 break;
7131 }
7132
7133 default:
7134 /* Impossible */
7135 AssertMsgFailed(("hmR0VmxReportWorldSwitchError %Rrc (%#x)\n", rcVMRun, rcVMRun));
7136 break;
7137 }
7138}
7139
7140
7141/**
7142 * Sets up the usage of TSC-offsetting and updates the VMCS.
7143 *
7144 * If offsetting is not possible, cause VM-exits on RDTSC(P)s. Also sets up the
7145 * VMX-preemption timer.
7146 *
7147 * @returns VBox status code.
7148 * @param pVCpu The cross context virtual CPU structure.
7149 * @param pVmxTransient The VMX-transient structure.
7150 * @param idCurrentCpu The current CPU number.
7151 *
7152 * @remarks No-long-jump zone!!!
7153 */
7154static void hmR0VmxUpdateTscOffsettingAndPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, RTCPUID idCurrentCpu)
7155{
7156 bool fOffsettedTsc;
7157 bool fParavirtTsc;
7158 uint64_t uTscOffset;
7159 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7160 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
7161
7162 if (pVM->hmr0.s.vmx.fUsePreemptTimer)
7163 {
7164 /* The TMCpuTickGetDeadlineAndTscOffset function is expensive (calling it on
7165 every entry slowed down the bs2-test1 CPUID testcase by ~33% (on an 10980xe). */
7166 uint64_t cTicksToDeadline;
7167 if ( idCurrentCpu == pVCpu->hmr0.s.idLastCpu
7168 && TMVirtualSyncIsCurrentDeadlineVersion(pVM, pVCpu->hmr0.s.vmx.uTscDeadlineVersion))
7169 {
7170 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionReusingDeadline);
7171 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
7172 cTicksToDeadline = pVCpu->hmr0.s.vmx.uTscDeadline - SUPReadTsc();
7173 if ((int64_t)cTicksToDeadline > 0)
7174 { /* hopefully */ }
7175 else
7176 {
7177 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionReusingDeadlineExpired);
7178 cTicksToDeadline = 0;
7179 }
7180 }
7181 else
7182 {
7183 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionRecalcingDeadline);
7184 cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVM, pVCpu, &uTscOffset, &fOffsettedTsc, &fParavirtTsc,
7185 &pVCpu->hmr0.s.vmx.uTscDeadline,
7186 &pVCpu->hmr0.s.vmx.uTscDeadlineVersion);
7187 pVCpu->hmr0.s.vmx.uTscDeadline += cTicksToDeadline;
7188 if (cTicksToDeadline >= 128)
7189 { /* hopefully */ }
7190 else
7191 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatVmxPreemptionRecalcingDeadlineExpired);
7192 }
7193
7194 /* Make sure the returned values have sane upper and lower boundaries. */
7195 uint64_t const u64CpuHz = SUPGetCpuHzFromGipBySetIndex(g_pSUPGlobalInfoPage, pVCpu->iHostCpuSet);
7196 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. */
7197 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 32678); /* 1/32768th of a second, ~30us. */
7198 cTicksToDeadline >>= pVM->hm.s.vmx.cPreemptTimerShift;
7199
7200 /** @todo r=ramshankar: We need to find a way to integrate nested-guest
7201 * preemption timers here. We probably need to clamp the preemption timer,
7202 * after converting the timer value to the host. */
7203 uint32_t const cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
7204 int rc = VMXWriteVmcs32(VMX_VMCS32_PREEMPT_TIMER_VALUE, cPreemptionTickCount);
7205 AssertRC(rc);
7206 }
7207 else
7208 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
7209
7210 if (fParavirtTsc)
7211 {
7212 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
7213 information before every VM-entry, hence disable it for performance sake. */
7214#if 0
7215 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
7216 AssertRC(rc);
7217#endif
7218 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
7219 }
7220
7221 if ( fOffsettedTsc
7222 && RT_LIKELY(!pVCpu->hmr0.s.fDebugWantRdTscExit))
7223 {
7224 if (pVmxTransient->fIsNestedGuest)
7225 uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
7226 hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
7227 hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
7228 }
7229 else
7230 {
7231 /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
7232 hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
7233 }
7234}
7235
7236
7237/**
7238 * Gets the IEM exception flags for the specified vector and IDT vectoring /
7239 * VM-exit interruption info type.
7240 *
7241 * @returns The IEM exception flags.
7242 * @param uVector The event vector.
7243 * @param uVmxEventType The VMX event type.
7244 *
7245 * @remarks This function currently only constructs flags required for
7246 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g, error-code
7247 * and CR2 aspects of an exception are not included).
7248 */
7249static uint32_t hmR0VmxGetIemXcptFlags(uint8_t uVector, uint32_t uVmxEventType)
7250{
7251 uint32_t fIemXcptFlags;
7252 switch (uVmxEventType)
7253 {
7254 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT:
7255 case VMX_IDT_VECTORING_INFO_TYPE_NMI:
7256 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
7257 break;
7258
7259 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT:
7260 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
7261 break;
7262
7263 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
7264 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_ICEBP_INSTR;
7265 break;
7266
7267 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
7268 {
7269 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
7270 if (uVector == X86_XCPT_BP)
7271 fIemXcptFlags |= IEM_XCPT_FLAGS_BP_INSTR;
7272 else if (uVector == X86_XCPT_OF)
7273 fIemXcptFlags |= IEM_XCPT_FLAGS_OF_INSTR;
7274 else
7275 {
7276 fIemXcptFlags = 0;
7277 AssertMsgFailed(("Unexpected vector for software exception. uVector=%#x", uVector));
7278 }
7279 break;
7280 }
7281
7282 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
7283 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
7284 break;
7285
7286 default:
7287 fIemXcptFlags = 0;
7288 AssertMsgFailed(("Unexpected vector type! uVmxEventType=%#x uVector=%#x", uVmxEventType, uVector));
7289 break;
7290 }
7291 return fIemXcptFlags;
7292}
7293
7294
7295/**
7296 * Sets an event as a pending event to be injected into the guest.
7297 *
7298 * @param pVCpu The cross context virtual CPU structure.
7299 * @param u32IntInfo The VM-entry interruption-information field.
7300 * @param cbInstr The VM-entry instruction length in bytes (for
7301 * software interrupts, exceptions and privileged
7302 * software exceptions).
7303 * @param u32ErrCode The VM-entry exception error code.
7304 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
7305 * page-fault.
7306 */
7307DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPUCC pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
7308 RTGCUINTPTR GCPtrFaultAddress)
7309{
7310 Assert(!pVCpu->hm.s.Event.fPending);
7311 pVCpu->hm.s.Event.fPending = true;
7312 pVCpu->hm.s.Event.u64IntInfo = u32IntInfo;
7313 pVCpu->hm.s.Event.u32ErrCode = u32ErrCode;
7314 pVCpu->hm.s.Event.cbInstr = cbInstr;
7315 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
7316}
7317
7318
7319/**
7320 * Sets an external interrupt as pending-for-injection into the VM.
7321 *
7322 * @param pVCpu The cross context virtual CPU structure.
7323 * @param u8Interrupt The external interrupt vector.
7324 */
7325DECLINLINE(void) hmR0VmxSetPendingExtInt(PVMCPUCC pVCpu, uint8_t u8Interrupt)
7326{
7327 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, u8Interrupt)
7328 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
7329 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7330 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7331 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7332}
7333
7334
7335/**
7336 * Sets an NMI (\#NMI) exception as pending-for-injection into the VM.
7337 *
7338 * @param pVCpu The cross context virtual CPU structure.
7339 */
7340DECLINLINE(void) hmR0VmxSetPendingXcptNmi(PVMCPUCC pVCpu)
7341{
7342 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI)
7343 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI)
7344 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7345 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7346 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7347}
7348
7349
7350/**
7351 * Sets a double-fault (\#DF) exception as pending-for-injection into the VM.
7352 *
7353 * @param pVCpu The cross context virtual CPU structure.
7354 */
7355DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPUCC pVCpu)
7356{
7357 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
7358 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7359 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7360 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7361 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7362}
7363
7364
7365/**
7366 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
7367 *
7368 * @param pVCpu The cross context virtual CPU structure.
7369 */
7370DECLINLINE(void) hmR0VmxSetPendingXcptUD(PVMCPUCC pVCpu)
7371{
7372 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_UD)
7373 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7374 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7375 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7376 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7377}
7378
7379
7380/**
7381 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
7382 *
7383 * @param pVCpu The cross context virtual CPU structure.
7384 */
7385DECLINLINE(void) hmR0VmxSetPendingXcptDB(PVMCPUCC pVCpu)
7386{
7387 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DB)
7388 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7389 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
7390 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7391 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
7392}
7393
7394
7395#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7396/**
7397 * Sets a general-protection (\#GP) exception as pending-for-injection into the VM.
7398 *
7399 * @param pVCpu The cross context virtual CPU structure.
7400 * @param u32ErrCode The error code for the general-protection exception.
7401 */
7402DECLINLINE(void) hmR0VmxSetPendingXcptGP(PVMCPUCC pVCpu, uint32_t u32ErrCode)
7403{
7404 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
7405 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7406 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7407 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7408 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
7409}
7410
7411
7412/**
7413 * Sets a stack (\#SS) exception as pending-for-injection into the VM.
7414 *
7415 * @param pVCpu The cross context virtual CPU structure.
7416 * @param u32ErrCode The error code for the stack exception.
7417 */
7418DECLINLINE(void) hmR0VmxSetPendingXcptSS(PVMCPUCC pVCpu, uint32_t u32ErrCode)
7419{
7420 uint32_t const u32IntInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_SS)
7421 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT)
7422 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 1)
7423 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
7424 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrCode, 0 /* GCPtrFaultAddress */);
7425}
7426#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
7427
7428
7429/**
7430 * Fixes up attributes for the specified segment register.
7431 *
7432 * @param pVCpu The cross context virtual CPU structure.
7433 * @param pSelReg The segment register that needs fixing.
7434 * @param pszRegName The register name (for logging and assertions).
7435 */
7436static void hmR0VmxFixUnusableSegRegAttr(PVMCPUCC pVCpu, PCPUMSELREG pSelReg, const char *pszRegName)
7437{
7438 Assert(pSelReg->Attr.u & X86DESCATTR_UNUSABLE);
7439
7440 /*
7441 * If VT-x marks the segment as unusable, most other bits remain undefined:
7442 * - For CS the L, D and G bits have meaning.
7443 * - For SS the DPL has meaning (it -is- the CPL for Intel and VBox).
7444 * - For the remaining data segments no bits are defined.
7445 *
7446 * The present bit and the unusable bit has been observed to be set at the
7447 * same time (the selector was supposed to be invalid as we started executing
7448 * a V8086 interrupt in ring-0).
7449 *
7450 * What should be important for the rest of the VBox code, is that the P bit is
7451 * cleared. Some of the other VBox code recognizes the unusable bit, but
7452 * AMD-V certainly don't, and REM doesn't really either. So, to be on the
7453 * safe side here, we'll strip off P and other bits we don't care about. If
7454 * any code breaks because Attr.u != 0 when Sel < 4, it should be fixed.
7455 *
7456 * See Intel spec. 27.3.2 "Saving Segment Registers and Descriptor-Table Registers".
7457 */
7458#ifdef VBOX_STRICT
7459 uint32_t const uAttr = pSelReg->Attr.u;
7460#endif
7461
7462 /* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
7463 pSelReg->Attr.u &= X86DESCATTR_UNUSABLE | X86DESCATTR_L | X86DESCATTR_D | X86DESCATTR_G
7464 | X86DESCATTR_DPL | X86DESCATTR_TYPE | X86DESCATTR_DT;
7465
7466#ifdef VBOX_STRICT
7467 VMMRZCallRing3Disable(pVCpu);
7468 Log4Func(("Unusable %s: sel=%#x attr=%#x -> %#x\n", pszRegName, pSelReg->Sel, uAttr, pSelReg->Attr.u));
7469# ifdef DEBUG_bird
7470 AssertMsg((uAttr & ~X86DESCATTR_P) == pSelReg->Attr.u,
7471 ("%s: %#x != %#x (sel=%#x base=%#llx limit=%#x)\n",
7472 pszRegName, uAttr, pSelReg->Attr.u, pSelReg->Sel, pSelReg->u64Base, pSelReg->u32Limit));
7473# endif
7474 VMMRZCallRing3Enable(pVCpu);
7475 NOREF(uAttr);
7476#endif
7477 RT_NOREF2(pVCpu, pszRegName);
7478}
7479
7480
7481/**
7482 * Imports a guest segment register from the current VMCS into the guest-CPU
7483 * context.
7484 *
7485 * @param pVCpu The cross context virtual CPU structure.
7486 * @param iSegReg The segment register number (X86_SREG_XXX).
7487 *
7488 * @remarks Called with interrupts and/or preemption disabled.
7489 */
7490static void hmR0VmxImportGuestSegReg(PVMCPUCC pVCpu, uint32_t iSegReg)
7491{
7492 Assert(iSegReg < X86_SREG_COUNT);
7493 Assert((uint32_t)VMX_VMCS16_GUEST_SEG_SEL(iSegReg) == g_aVmcsSegSel[iSegReg]);
7494 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg) == g_aVmcsSegLimit[iSegReg]);
7495 Assert((uint32_t)VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg) == g_aVmcsSegAttr[iSegReg]);
7496 Assert((uint32_t)VMX_VMCS_GUEST_SEG_BASE(iSegReg) == g_aVmcsSegBase[iSegReg]);
7497
7498 PCPUMSELREG pSelReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
7499
7500 uint16_t u16Sel;
7501 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_SEG_SEL(iSegReg), &u16Sel); AssertRC(rc);
7502 pSelReg->Sel = u16Sel;
7503 pSelReg->ValidSel = u16Sel;
7504
7505 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SEG_LIMIT(iSegReg), &pSelReg->u32Limit); AssertRC(rc);
7506 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SEG_BASE(iSegReg), &pSelReg->u64Base); AssertRC(rc);
7507
7508 uint32_t u32Attr;
7509 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(iSegReg), &u32Attr); AssertRC(rc);
7510 pSelReg->Attr.u = u32Attr;
7511 if (u32Attr & X86DESCATTR_UNUSABLE)
7512 hmR0VmxFixUnusableSegRegAttr(pVCpu, pSelReg, "ES\0CS\0SS\0DS\0FS\0GS" + iSegReg * 3);
7513
7514 pSelReg->fFlags = CPUMSELREG_FLAGS_VALID;
7515}
7516
7517
7518/**
7519 * Imports the guest LDTR from the current VMCS into the guest-CPU context.
7520 *
7521 * @param pVCpu The cross context virtual CPU structure.
7522 *
7523 * @remarks Called with interrupts and/or preemption disabled.
7524 */
7525static void hmR0VmxImportGuestLdtr(PVMCPUCC pVCpu)
7526{
7527 uint16_t u16Sel;
7528 uint64_t u64Base;
7529 uint32_t u32Limit, u32Attr;
7530 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_LDTR_SEL, &u16Sel); AssertRC(rc);
7531 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, &u32Limit); AssertRC(rc);
7532 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7533 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_LDTR_BASE, &u64Base); AssertRC(rc);
7534
7535 pVCpu->cpum.GstCtx.ldtr.Sel = u16Sel;
7536 pVCpu->cpum.GstCtx.ldtr.ValidSel = u16Sel;
7537 pVCpu->cpum.GstCtx.ldtr.fFlags = CPUMSELREG_FLAGS_VALID;
7538 pVCpu->cpum.GstCtx.ldtr.u32Limit = u32Limit;
7539 pVCpu->cpum.GstCtx.ldtr.u64Base = u64Base;
7540 pVCpu->cpum.GstCtx.ldtr.Attr.u = u32Attr;
7541 if (u32Attr & X86DESCATTR_UNUSABLE)
7542 hmR0VmxFixUnusableSegRegAttr(pVCpu, &pVCpu->cpum.GstCtx.ldtr, "LDTR");
7543}
7544
7545
7546/**
7547 * Imports the guest TR from the current VMCS into the guest-CPU context.
7548 *
7549 * @param pVCpu The cross context virtual CPU structure.
7550 *
7551 * @remarks Called with interrupts and/or preemption disabled.
7552 */
7553static void hmR0VmxImportGuestTr(PVMCPUCC pVCpu)
7554{
7555 uint16_t u16Sel;
7556 uint64_t u64Base;
7557 uint32_t u32Limit, u32Attr;
7558 int rc = VMXReadVmcs16(VMX_VMCS16_GUEST_TR_SEL, &u16Sel); AssertRC(rc);
7559 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_LIMIT, &u32Limit); AssertRC(rc);
7560 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, &u32Attr); AssertRC(rc);
7561 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_TR_BASE, &u64Base); AssertRC(rc);
7562
7563 pVCpu->cpum.GstCtx.tr.Sel = u16Sel;
7564 pVCpu->cpum.GstCtx.tr.ValidSel = u16Sel;
7565 pVCpu->cpum.GstCtx.tr.fFlags = CPUMSELREG_FLAGS_VALID;
7566 pVCpu->cpum.GstCtx.tr.u32Limit = u32Limit;
7567 pVCpu->cpum.GstCtx.tr.u64Base = u64Base;
7568 pVCpu->cpum.GstCtx.tr.Attr.u = u32Attr;
7569 /* TR is the only selector that can never be unusable. */
7570 Assert(!(u32Attr & X86DESCATTR_UNUSABLE));
7571}
7572
7573
7574/**
7575 * Imports the guest RIP from the VMCS back into the guest-CPU context.
7576 *
7577 * @param pVCpu The cross context virtual CPU structure.
7578 *
7579 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7580 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7581 * instead!!!
7582 */
7583static void hmR0VmxImportGuestRip(PVMCPUCC pVCpu)
7584{
7585 uint64_t u64Val;
7586 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7587 if (pCtx->fExtrn & CPUMCTX_EXTRN_RIP)
7588 {
7589 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
7590 AssertRC(rc);
7591
7592 pCtx->rip = u64Val;
7593 EMHistoryUpdatePC(pVCpu, pCtx->rip, false);
7594 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RIP;
7595 }
7596}
7597
7598
7599/**
7600 * Imports the guest RFLAGS from the VMCS back into the guest-CPU context.
7601 *
7602 * @param pVCpu The cross context virtual CPU structure.
7603 * @param pVmcsInfo The VMCS info. object.
7604 *
7605 * @remarks Called with interrupts and/or preemption disabled, should not assert!
7606 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7607 * instead!!!
7608 */
7609static void hmR0VmxImportGuestRFlags(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7610{
7611 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7612 if (pCtx->fExtrn & CPUMCTX_EXTRN_RFLAGS)
7613 {
7614 uint64_t u64Val;
7615 int rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
7616 AssertRC(rc);
7617
7618 pCtx->rflags.u64 = u64Val;
7619 PCVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7620 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
7621 {
7622 pCtx->eflags.Bits.u1VM = 0;
7623 pCtx->eflags.Bits.u2IOPL = pVmcsInfoShared->RealMode.Eflags.Bits.u2IOPL;
7624 }
7625 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RFLAGS;
7626 }
7627}
7628
7629
7630/**
7631 * Imports the guest interruptibility-state from the VMCS back into the guest-CPU
7632 * context.
7633 *
7634 * @param pVCpu The cross context virtual CPU structure.
7635 * @param pVmcsInfo The VMCS info. object.
7636 *
7637 * @remarks Called with interrupts and/or preemption disabled, try not to assert and
7638 * do not log!
7639 * @remarks Do -not- call this function directly, use hmR0VmxImportGuestState()
7640 * instead!!!
7641 */
7642static void hmR0VmxImportGuestIntrState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
7643{
7644 uint32_t u32Val;
7645 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32Val); AssertRC(rc);
7646 if (!u32Val)
7647 {
7648 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7649 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7650 CPUMSetGuestNmiBlocking(pVCpu, false);
7651 }
7652 else
7653 {
7654 /*
7655 * We must import RIP here to set our EM interrupt-inhibited state.
7656 * We also import RFLAGS as our code that evaluates pending interrupts
7657 * before VM-entry requires it.
7658 */
7659 hmR0VmxImportGuestRip(pVCpu);
7660 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7661
7662 if (u32Val & (VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS | VMX_VMCS_GUEST_INT_STATE_BLOCK_STI))
7663 EMSetInhibitInterruptsPC(pVCpu, pVCpu->cpum.GstCtx.rip);
7664 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
7665 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
7666
7667 bool const fNmiBlocking = RT_BOOL(u32Val & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI);
7668 CPUMSetGuestNmiBlocking(pVCpu, fNmiBlocking);
7669 }
7670}
7671
7672
7673/**
7674 * Worker for VMXR0ImportStateOnDemand.
7675 *
7676 * @returns VBox status code.
7677 * @param pVCpu The cross context virtual CPU structure.
7678 * @param pVmcsInfo The VMCS info. object.
7679 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
7680 */
7681static int hmR0VmxImportGuestState(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
7682{
7683 int rc = VINF_SUCCESS;
7684 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
7685 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
7686 uint32_t u32Val;
7687
7688 /*
7689 * Note! This is hack to workaround a mysterious BSOD observed with release builds
7690 * on Windows 10 64-bit hosts. Profile and debug builds are not affected and
7691 * neither are other host platforms.
7692 *
7693 * Committing this temporarily as it prevents BSOD.
7694 *
7695 * Update: This is very likely a compiler optimization bug, see @bugref{9180}.
7696 */
7697#ifdef RT_OS_WINDOWS
7698 if (pVM == 0 || pVM == (void *)(uintptr_t)-1)
7699 return VERR_HM_IPE_1;
7700#endif
7701
7702 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatImportGuestState, x);
7703
7704 /*
7705 * We disable interrupts to make the updating of the state and in particular
7706 * the fExtrn modification atomic wrt to preemption hooks.
7707 */
7708 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
7709
7710 fWhat &= pCtx->fExtrn;
7711 if (fWhat)
7712 {
7713 do
7714 {
7715 if (fWhat & CPUMCTX_EXTRN_RIP)
7716 hmR0VmxImportGuestRip(pVCpu);
7717
7718 if (fWhat & CPUMCTX_EXTRN_RFLAGS)
7719 hmR0VmxImportGuestRFlags(pVCpu, pVmcsInfo);
7720
7721 if (fWhat & CPUMCTX_EXTRN_HM_VMX_INT_STATE)
7722 hmR0VmxImportGuestIntrState(pVCpu, pVmcsInfo);
7723
7724 if (fWhat & CPUMCTX_EXTRN_RSP)
7725 {
7726 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RSP, &pCtx->rsp);
7727 AssertRC(rc);
7728 }
7729
7730 if (fWhat & CPUMCTX_EXTRN_SREG_MASK)
7731 {
7732 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7733 bool const fRealOnV86Active = pVmcsInfoShared->RealMode.fRealOnV86Active;
7734 if (fWhat & CPUMCTX_EXTRN_CS)
7735 {
7736 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_CS);
7737 hmR0VmxImportGuestRip(pVCpu);
7738 if (fRealOnV86Active)
7739 pCtx->cs.Attr.u = pVmcsInfoShared->RealMode.AttrCS.u;
7740 EMHistoryUpdatePC(pVCpu, pCtx->cs.u64Base + pCtx->rip, true /* fFlattened */);
7741 }
7742 if (fWhat & CPUMCTX_EXTRN_SS)
7743 {
7744 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_SS);
7745 if (fRealOnV86Active)
7746 pCtx->ss.Attr.u = pVmcsInfoShared->RealMode.AttrSS.u;
7747 }
7748 if (fWhat & CPUMCTX_EXTRN_DS)
7749 {
7750 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_DS);
7751 if (fRealOnV86Active)
7752 pCtx->ds.Attr.u = pVmcsInfoShared->RealMode.AttrDS.u;
7753 }
7754 if (fWhat & CPUMCTX_EXTRN_ES)
7755 {
7756 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_ES);
7757 if (fRealOnV86Active)
7758 pCtx->es.Attr.u = pVmcsInfoShared->RealMode.AttrES.u;
7759 }
7760 if (fWhat & CPUMCTX_EXTRN_FS)
7761 {
7762 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_FS);
7763 if (fRealOnV86Active)
7764 pCtx->fs.Attr.u = pVmcsInfoShared->RealMode.AttrFS.u;
7765 }
7766 if (fWhat & CPUMCTX_EXTRN_GS)
7767 {
7768 hmR0VmxImportGuestSegReg(pVCpu, X86_SREG_GS);
7769 if (fRealOnV86Active)
7770 pCtx->gs.Attr.u = pVmcsInfoShared->RealMode.AttrGS.u;
7771 }
7772 }
7773
7774 if (fWhat & CPUMCTX_EXTRN_TABLE_MASK)
7775 {
7776 if (fWhat & CPUMCTX_EXTRN_LDTR)
7777 hmR0VmxImportGuestLdtr(pVCpu);
7778
7779 if (fWhat & CPUMCTX_EXTRN_GDTR)
7780 {
7781 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &pCtx->gdtr.pGdt); AssertRC(rc);
7782 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val); AssertRC(rc);
7783 pCtx->gdtr.cbGdt = u32Val;
7784 }
7785
7786 /* Guest IDTR. */
7787 if (fWhat & CPUMCTX_EXTRN_IDTR)
7788 {
7789 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &pCtx->idtr.pIdt); AssertRC(rc);
7790 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val); AssertRC(rc);
7791 pCtx->idtr.cbIdt = u32Val;
7792 }
7793
7794 /* Guest TR. */
7795 if (fWhat & CPUMCTX_EXTRN_TR)
7796 {
7797 /* Real-mode emulation using virtual-8086 mode has the fake TSS (pRealModeTSS) in TR,
7798 don't need to import that one. */
7799 if (!pVmcsInfo->pShared->RealMode.fRealOnV86Active)
7800 hmR0VmxImportGuestTr(pVCpu);
7801 }
7802 }
7803
7804 if (fWhat & CPUMCTX_EXTRN_DR7)
7805 {
7806 if (!pVCpu->hmr0.s.fUsingHyperDR7)
7807 {
7808 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_DR7, &pCtx->dr[7]);
7809 AssertRC(rc);
7810 }
7811 }
7812
7813 if (fWhat & CPUMCTX_EXTRN_SYSENTER_MSRS)
7814 {
7815 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_EIP, &pCtx->SysEnter.eip); AssertRC(rc);
7816 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_SYSENTER_ESP, &pCtx->SysEnter.esp); AssertRC(rc);
7817 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, &u32Val); AssertRC(rc);
7818 pCtx->SysEnter.cs = u32Val;
7819 }
7820
7821 if (fWhat & CPUMCTX_EXTRN_KERNEL_GS_BASE)
7822 {
7823 if ( pVM->hmr0.s.fAllow64BitGuests
7824 && (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7825 pCtx->msrKERNELGSBASE = ASMRdMsr(MSR_K8_KERNEL_GS_BASE);
7826 }
7827
7828 if (fWhat & CPUMCTX_EXTRN_SYSCALL_MSRS)
7829 {
7830 if ( pVM->hmr0.s.fAllow64BitGuests
7831 && (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST))
7832 {
7833 pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
7834 pCtx->msrSTAR = ASMRdMsr(MSR_K6_STAR);
7835 pCtx->msrSFMASK = ASMRdMsr(MSR_K8_SF_MASK);
7836 }
7837 }
7838
7839 if (fWhat & (CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS))
7840 {
7841 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
7842 PCVMXAUTOMSR pMsrs = (PCVMXAUTOMSR)pVmcsInfo->pvGuestMsrStore;
7843 uint32_t const cMsrs = pVmcsInfo->cExitMsrStore;
7844 Assert(pMsrs);
7845 Assert(cMsrs <= VMX_MISC_MAX_MSRS(g_HmMsrs.u.vmx.u64Misc));
7846 Assert(sizeof(*pMsrs) * cMsrs <= X86_PAGE_4K_SIZE);
7847 for (uint32_t i = 0; i < cMsrs; i++)
7848 {
7849 uint32_t const idMsr = pMsrs[i].u32Msr;
7850 switch (idMsr)
7851 {
7852 case MSR_K8_TSC_AUX: CPUMSetGuestTscAux(pVCpu, pMsrs[i].u64Value); break;
7853 case MSR_IA32_SPEC_CTRL: CPUMSetGuestSpecCtrl(pVCpu, pMsrs[i].u64Value); break;
7854 case MSR_K6_EFER: /* Can't be changed without causing a VM-exit */ break;
7855 default:
7856 {
7857 uint32_t idxLbrMsr;
7858 if (pVM->hmr0.s.vmx.fLbr)
7859 {
7860 if (hmR0VmxIsLbrBranchFromMsr(pVM, idMsr, &idxLbrMsr))
7861 {
7862 Assert(idxLbrMsr < RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr));
7863 pVmcsInfoShared->au64LbrFromIpMsr[idxLbrMsr] = pMsrs[i].u64Value;
7864 break;
7865 }
7866 if (hmR0VmxIsLbrBranchToMsr(pVM, idMsr, &idxLbrMsr))
7867 {
7868 Assert(idxLbrMsr < RT_ELEMENTS(pVmcsInfoShared->au64LbrFromIpMsr));
7869 pVmcsInfoShared->au64LbrToIpMsr[idxLbrMsr] = pMsrs[i].u64Value;
7870 break;
7871 }
7872 if (idMsr == pVM->hmr0.s.vmx.idLbrTosMsr)
7873 {
7874 pVmcsInfoShared->u64LbrTosMsr = pMsrs[i].u64Value;
7875 break;
7876 }
7877 /* Fallthru (no break) */
7878 }
7879 pCtx->fExtrn = 0;
7880 pVCpu->hm.s.u32HMError = pMsrs->u32Msr;
7881 ASMSetFlags(fEFlags);
7882 AssertMsgFailed(("Unexpected MSR in auto-load/store area. idMsr=%#RX32 cMsrs=%u\n", idMsr, cMsrs));
7883 return VERR_HM_UNEXPECTED_LD_ST_MSR;
7884 }
7885 }
7886 }
7887 }
7888
7889 if (fWhat & CPUMCTX_EXTRN_CR_MASK)
7890 {
7891 if (fWhat & CPUMCTX_EXTRN_CR0)
7892 {
7893 uint64_t u64Cr0;
7894 uint64_t u64Shadow;
7895 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Cr0); AssertRC(rc);
7896 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Shadow); AssertRC(rc);
7897#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
7898 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7899 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7900#else
7901 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
7902 {
7903 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7904 | (u64Shadow & pVmcsInfo->u64Cr0Mask);
7905 }
7906 else
7907 {
7908 /*
7909 * We've merged the guest and nested-guest's CR0 guest/host mask while executing
7910 * the nested-guest using hardware-assisted VMX. Accordingly we need to
7911 * re-construct CR0. See @bugref{9180#c95} for details.
7912 */
7913 PCVMXVMCSINFO const pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
7914 PVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7915 u64Cr0 = (u64Cr0 & ~pVmcsInfo->u64Cr0Mask)
7916 | (pVmcsNstGst->u64GuestCr0.u & pVmcsNstGst->u64Cr0Mask.u)
7917 | (u64Shadow & (pVmcsInfoGst->u64Cr0Mask & ~pVmcsNstGst->u64Cr0Mask.u));
7918 }
7919#endif
7920 VMMRZCallRing3Disable(pVCpu); /* May call into PGM which has Log statements. */
7921 CPUMSetGuestCR0(pVCpu, u64Cr0);
7922 VMMRZCallRing3Enable(pVCpu);
7923 }
7924
7925 if (fWhat & CPUMCTX_EXTRN_CR4)
7926 {
7927 uint64_t u64Cr4;
7928 uint64_t u64Shadow;
7929 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64Cr4); AssertRC(rc);
7930 rc |= VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Shadow); AssertRC(rc);
7931#ifndef VBOX_WITH_NESTED_HWVIRT_VMX
7932 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7933 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7934#else
7935 if (!CPUMIsGuestInVmxNonRootMode(pCtx))
7936 {
7937 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7938 | (u64Shadow & pVmcsInfo->u64Cr4Mask);
7939 }
7940 else
7941 {
7942 /*
7943 * We've merged the guest and nested-guest's CR4 guest/host mask while executing
7944 * the nested-guest using hardware-assisted VMX. Accordingly we need to
7945 * re-construct CR4. See @bugref{9180#c95} for details.
7946 */
7947 PCVMXVMCSINFO const pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
7948 PVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
7949 u64Cr4 = (u64Cr4 & ~pVmcsInfo->u64Cr4Mask)
7950 | (pVmcsNstGst->u64GuestCr4.u & pVmcsNstGst->u64Cr4Mask.u)
7951 | (u64Shadow & (pVmcsInfoGst->u64Cr4Mask & ~pVmcsNstGst->u64Cr4Mask.u));
7952 }
7953#endif
7954 pCtx->cr4 = u64Cr4;
7955 }
7956
7957 if (fWhat & CPUMCTX_EXTRN_CR3)
7958 {
7959 /* CR0.PG bit changes are always intercepted, so it's up to date. */
7960 if ( pVM->hmr0.s.vmx.fUnrestrictedGuest
7961 || ( pVM->hmr0.s.fNestedPaging
7962 && CPUMIsGuestPagingEnabledEx(pCtx)))
7963 {
7964 uint64_t u64Cr3;
7965 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR3, &u64Cr3); AssertRC(rc);
7966 if (pCtx->cr3 != u64Cr3)
7967 {
7968 pCtx->cr3 = u64Cr3;
7969 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7970 }
7971
7972 /*
7973 * If the guest is in PAE mode, sync back the PDPE's into the guest state.
7974 * CR4.PAE, CR0.PG, EFER MSR changes are always intercepted, so they're up to date.
7975 */
7976 if (CPUMIsGuestInPAEModeEx(pCtx))
7977 {
7978 X86PDPE aPaePdpes[4];
7979 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &aPaePdpes[0].u); AssertRC(rc);
7980 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &aPaePdpes[1].u); AssertRC(rc);
7981 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &aPaePdpes[2].u); AssertRC(rc);
7982 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &aPaePdpes[3].u); AssertRC(rc);
7983 if (memcmp(&aPaePdpes[0], &pCtx->aPaePdpes[0], sizeof(aPaePdpes)))
7984 {
7985 memcpy(&pCtx->aPaePdpes[0], &aPaePdpes[0], sizeof(aPaePdpes));
7986 /* PGM now updates PAE PDPTEs while updating CR3. */
7987 VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
7988 }
7989 }
7990 }
7991 }
7992 }
7993
7994#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
7995 if (fWhat & CPUMCTX_EXTRN_HWVIRT)
7996 {
7997 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
7998 && !CPUMIsGuestInVmxNonRootMode(pCtx))
7999 {
8000 Assert(CPUMIsGuestInVmxRootMode(pCtx));
8001 rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
8002 if (RT_SUCCESS(rc))
8003 { /* likely */ }
8004 else
8005 break;
8006 }
8007 }
8008#endif
8009 } while (0);
8010
8011 if (RT_SUCCESS(rc))
8012 {
8013 /* Update fExtrn. */
8014 pCtx->fExtrn &= ~fWhat;
8015
8016 /* If everything has been imported, clear the HM keeper bit. */
8017 if (!(pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL))
8018 {
8019 pCtx->fExtrn &= ~CPUMCTX_EXTRN_KEEPER_HM;
8020 Assert(!pCtx->fExtrn);
8021 }
8022 }
8023 }
8024 else
8025 AssertMsg(!pCtx->fExtrn || (pCtx->fExtrn & HMVMX_CPUMCTX_EXTRN_ALL), ("%#RX64\n", pCtx->fExtrn));
8026
8027 /*
8028 * Restore interrupts.
8029 */
8030 ASMSetFlags(fEFlags);
8031
8032 STAM_PROFILE_ADV_STOP(& pVCpu->hm.s.StatImportGuestState, x);
8033
8034 if (RT_SUCCESS(rc))
8035 { /* likely */ }
8036 else
8037 return rc;
8038
8039 /*
8040 * Honor any pending CR3 updates.
8041 *
8042 * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> VMXR0CallRing3Callback()
8043 * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
8044 * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
8045 *
8046 * The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
8047 * if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
8048 * calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
8049 * -NOT- check if CPUMCTX_EXTRN_CR3 is set!
8050 *
8051 * The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
8052 *
8053 * The force-flag is checked first as it's cheaper for potential superfluous calls to this function.
8054 */
8055 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3)
8056 && VMMRZCallRing3IsEnabled(pVCpu))
8057 {
8058 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & CPUMCTX_EXTRN_CR3));
8059 PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu), false /* fPdpesMapped */);
8060 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
8061 }
8062
8063 return VINF_SUCCESS;
8064}
8065
8066
8067/**
8068 * Saves the guest state from the VMCS into the guest-CPU context.
8069 *
8070 * @returns VBox status code.
8071 * @param pVCpu The cross context virtual CPU structure.
8072 * @param fWhat What to import, CPUMCTX_EXTRN_XXX.
8073 */
8074VMMR0DECL(int) VMXR0ImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat)
8075{
8076 AssertPtr(pVCpu);
8077 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8078 return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
8079}
8080
8081
8082/**
8083 * Check per-VM and per-VCPU force flag actions that require us to go back to
8084 * ring-3 for one reason or another.
8085 *
8086 * @returns Strict VBox status code (i.e. informational status codes too)
8087 * @retval VINF_SUCCESS if we don't have any actions that require going back to
8088 * ring-3.
8089 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
8090 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
8091 * interrupts)
8092 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
8093 * all EMTs to be in ring-3.
8094 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
8095 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
8096 * to the EM loop.
8097 *
8098 * @param pVCpu The cross context virtual CPU structure.
8099 * @param pVmxTransient The VMX-transient structure.
8100 * @param fStepping Whether we are single-stepping the guest using the
8101 * hypervisor debugger.
8102 *
8103 * @remarks This might cause nested-guest VM-exits, caller must check if the guest
8104 * is no longer in VMX non-root mode.
8105 */
8106static VBOXSTRICTRC hmR0VmxCheckForceFlags(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, bool fStepping)
8107{
8108 Assert(VMMRZCallRing3IsEnabled(pVCpu));
8109
8110 /*
8111 * Update pending interrupts into the APIC's IRR.
8112 */
8113 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
8114 APICUpdatePendingInterrupts(pVCpu);
8115
8116 /*
8117 * Anything pending? Should be more likely than not if we're doing a good job.
8118 */
8119 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8120 if ( !fStepping
8121 ? !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_MASK)
8122 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_MASK)
8123 : !VM_FF_IS_ANY_SET(pVM, VM_FF_HP_R0_PRE_HM_STEP_MASK)
8124 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
8125 return VINF_SUCCESS;
8126
8127 /* Pending PGM C3 sync. */
8128 if (VMCPU_FF_IS_ANY_SET(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
8129 {
8130 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8131 Assert(!(ASMAtomicUoReadU64(&pCtx->fExtrn) & (CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4)));
8132 VBOXSTRICTRC rcStrict = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4,
8133 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
8134 if (rcStrict != VINF_SUCCESS)
8135 {
8136 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
8137 Log4Func(("PGMSyncCR3 forcing us back to ring-3. rc2=%d\n", VBOXSTRICTRC_VAL(rcStrict)));
8138 return rcStrict;
8139 }
8140 }
8141
8142 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
8143 if ( VM_FF_IS_ANY_SET(pVM, VM_FF_HM_TO_R3_MASK)
8144 || VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
8145 {
8146 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
8147 int rc = RT_LIKELY(!VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_RAW_TO_R3 : VINF_EM_NO_MEMORY;
8148 Log4Func(("HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
8149 return rc;
8150 }
8151
8152 /* Pending VM request packets, such as hardware interrupts. */
8153 if ( VM_FF_IS_SET(pVM, VM_FF_REQUEST)
8154 || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_REQUEST))
8155 {
8156 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchVmReq);
8157 Log4Func(("Pending VM request forcing us back to ring-3\n"));
8158 return VINF_EM_PENDING_REQUEST;
8159 }
8160
8161 /* Pending PGM pool flushes. */
8162 if (VM_FF_IS_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
8163 {
8164 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPgmPoolFlush);
8165 Log4Func(("PGM pool flush pending forcing us back to ring-3\n"));
8166 return VINF_PGM_POOL_FLUSH_PENDING;
8167 }
8168
8169 /* Pending DMA requests. */
8170 if (VM_FF_IS_SET(pVM, VM_FF_PDM_DMA))
8171 {
8172 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchDma);
8173 Log4Func(("Pending DMA request forcing us back to ring-3\n"));
8174 return VINF_EM_RAW_TO_R3;
8175 }
8176
8177#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8178 /*
8179 * Pending nested-guest events.
8180 *
8181 * Please note the priority of these events are specified and important.
8182 * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
8183 * See Intel spec. 6.9 "Priority Among Simultaneous Exceptions And Interrupts".
8184 */
8185 if (pVmxTransient->fIsNestedGuest)
8186 {
8187 /* Pending nested-guest APIC-write. */
8188 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
8189 {
8190 Log4Func(("Pending nested-guest APIC-write\n"));
8191 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitApicWrite(pVCpu);
8192 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8193 return rcStrict;
8194 }
8195
8196 /* Pending nested-guest monitor-trap flag (MTF). */
8197 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_MTF))
8198 {
8199 Log4Func(("Pending nested-guest MTF\n"));
8200 VBOXSTRICTRC rcStrict = IEMExecVmxVmexit(pVCpu, VMX_EXIT_MTF, 0 /* uExitQual */);
8201 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8202 return rcStrict;
8203 }
8204
8205 /* Pending nested-guest VMX-preemption timer expired. */
8206 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_PREEMPT_TIMER))
8207 {
8208 Log4Func(("Pending nested-guest preempt timer\n"));
8209 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitPreemptTimer(pVCpu);
8210 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
8211 return rcStrict;
8212 }
8213 }
8214#else
8215 NOREF(pVmxTransient);
8216#endif
8217
8218 return VINF_SUCCESS;
8219}
8220
8221
8222/**
8223 * Converts any TRPM trap into a pending HM event. This is typically used when
8224 * entering from ring-3 (not longjmp returns).
8225 *
8226 * @param pVCpu The cross context virtual CPU structure.
8227 */
8228static void hmR0VmxTrpmTrapToPendingEvent(PVMCPUCC pVCpu)
8229{
8230 Assert(TRPMHasTrap(pVCpu));
8231 Assert(!pVCpu->hm.s.Event.fPending);
8232
8233 uint8_t uVector;
8234 TRPMEVENT enmTrpmEvent;
8235 uint32_t uErrCode;
8236 RTGCUINTPTR GCPtrFaultAddress;
8237 uint8_t cbInstr;
8238 bool fIcebp;
8239
8240 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr, &fIcebp);
8241 AssertRC(rc);
8242
8243 uint32_t u32IntInfo;
8244 u32IntInfo = uVector | VMX_IDT_VECTORING_INFO_VALID;
8245 u32IntInfo |= HMTrpmEventTypeToVmxEventType(uVector, enmTrpmEvent, fIcebp);
8246
8247 rc = TRPMResetTrap(pVCpu);
8248 AssertRC(rc);
8249 Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
8250 u32IntInfo, enmTrpmEvent, cbInstr, uErrCode, GCPtrFaultAddress));
8251
8252 hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, cbInstr, uErrCode, GCPtrFaultAddress);
8253}
8254
8255
8256/**
8257 * Converts the pending HM event into a TRPM trap.
8258 *
8259 * @param pVCpu The cross context virtual CPU structure.
8260 */
8261static void hmR0VmxPendingEventToTrpmTrap(PVMCPUCC pVCpu)
8262{
8263 Assert(pVCpu->hm.s.Event.fPending);
8264
8265 /* If a trap was already pending, we did something wrong! */
8266 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
8267
8268 uint32_t const u32IntInfo = pVCpu->hm.s.Event.u64IntInfo;
8269 uint32_t const uVector = VMX_IDT_VECTORING_INFO_VECTOR(u32IntInfo);
8270 TRPMEVENT const enmTrapType = HMVmxEventTypeToTrpmEventType(u32IntInfo);
8271
8272 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, enmTrapType));
8273
8274 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
8275 AssertRC(rc);
8276
8277 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8278 TRPMSetErrorCode(pVCpu, pVCpu->hm.s.Event.u32ErrCode);
8279
8280 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(u32IntInfo))
8281 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
8282 else
8283 {
8284 uint8_t const uVectorType = VMX_IDT_VECTORING_INFO_TYPE(u32IntInfo);
8285 switch (uVectorType)
8286 {
8287 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT:
8288 TRPMSetTrapDueToIcebp(pVCpu);
8289 RT_FALL_THRU();
8290 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT:
8291 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT:
8292 {
8293 AssertMsg( uVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
8294 || ( uVector == X86_XCPT_BP /* INT3 */
8295 || uVector == X86_XCPT_OF /* INTO */
8296 || uVector == X86_XCPT_DB /* INT1 (ICEBP) */),
8297 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
8298 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
8299 break;
8300 }
8301 }
8302 }
8303
8304 /* We're now done converting the pending event. */
8305 pVCpu->hm.s.Event.fPending = false;
8306}
8307
8308
8309/**
8310 * Sets the interrupt-window exiting control in the VMCS which instructs VT-x to
8311 * cause a VM-exit as soon as the guest is in a state to receive interrupts.
8312 *
8313 * @param pVmcsInfo The VMCS info. object.
8314 */
8315static void hmR0VmxSetIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8316{
8317 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_INT_WINDOW_EXIT)
8318 {
8319 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
8320 {
8321 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_INT_WINDOW_EXIT;
8322 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8323 AssertRC(rc);
8324 }
8325 } /* else we will deliver interrupts whenever the guest Vm-exits next and is in a state to receive the interrupt. */
8326}
8327
8328
8329/**
8330 * Clears the interrupt-window exiting control in the VMCS.
8331 *
8332 * @param pVmcsInfo The VMCS info. object.
8333 */
8334DECLINLINE(void) hmR0VmxClearIntWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8335{
8336 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT)
8337 {
8338 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_INT_WINDOW_EXIT;
8339 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8340 AssertRC(rc);
8341 }
8342}
8343
8344
8345/**
8346 * Sets the NMI-window exiting control in the VMCS which instructs VT-x to
8347 * cause a VM-exit as soon as the guest is in a state to receive NMIs.
8348 *
8349 * @param pVmcsInfo The VMCS info. object.
8350 */
8351static void hmR0VmxSetNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8352{
8353 if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
8354 {
8355 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))
8356 {
8357 pVmcsInfo->u32ProcCtls |= VMX_PROC_CTLS_NMI_WINDOW_EXIT;
8358 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8359 AssertRC(rc);
8360 Log4Func(("Setup NMI-window exiting\n"));
8361 }
8362 } /* else we will deliver NMIs whenever we VM-exit next, even possibly nesting NMIs. Can't be helped on ancient CPUs. */
8363}
8364
8365
8366/**
8367 * Clears the NMI-window exiting control in the VMCS.
8368 *
8369 * @param pVmcsInfo The VMCS info. object.
8370 */
8371DECLINLINE(void) hmR0VmxClearNmiWindowExitVmcs(PVMXVMCSINFO pVmcsInfo)
8372{
8373 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT)
8374 {
8375 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_NMI_WINDOW_EXIT;
8376 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
8377 AssertRC(rc);
8378 }
8379}
8380
8381
8382/**
8383 * Does the necessary state syncing before returning to ring-3 for any reason
8384 * (longjmp, preemption, voluntary exits to ring-3) from VT-x.
8385 *
8386 * @returns VBox status code.
8387 * @param pVCpu The cross context virtual CPU structure.
8388 * @param fImportState Whether to import the guest state from the VMCS back
8389 * to the guest-CPU context.
8390 *
8391 * @remarks No-long-jmp zone!!!
8392 */
8393static int hmR0VmxLeave(PVMCPUCC pVCpu, bool fImportState)
8394{
8395 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8396 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8397
8398 RTCPUID const idCpu = RTMpCpuId();
8399 Log4Func(("HostCpuId=%u\n", idCpu));
8400
8401 /*
8402 * !!! IMPORTANT !!!
8403 * If you modify code here, check whether VMXR0CallRing3Callback() needs to be updated too.
8404 */
8405
8406 /* Save the guest state if necessary. */
8407 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8408 if (fImportState)
8409 {
8410 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8411 AssertRCReturn(rc, rc);
8412 }
8413
8414 /* Restore host FPU state if necessary. We will resync on next R0 reentry. */
8415 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8416 Assert(!CPUMIsGuestFPUStateActive(pVCpu));
8417
8418 /* Restore host debug registers if necessary. We will resync on next R0 reentry. */
8419#ifdef VBOX_STRICT
8420 if (CPUMIsHyperDebugStateActive(pVCpu))
8421 Assert(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MOV_DR_EXIT);
8422#endif
8423 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8424 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
8425 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
8426
8427 /* Restore host-state bits that VT-x only restores partially. */
8428 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
8429 {
8430 Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hmr0.s.vmx.fRestoreHostFlags, idCpu));
8431 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
8432 }
8433 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
8434
8435 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8436 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8437 {
8438 /* We shouldn't restore the host MSRs without saving the guest MSRs first. */
8439 if (!fImportState)
8440 {
8441 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS);
8442 AssertRCReturn(rc, rc);
8443 }
8444 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8445 Assert(!pVCpu->hmr0.s.vmx.fLazyMsrs);
8446 }
8447 else
8448 pVCpu->hmr0.s.vmx.fLazyMsrs = 0;
8449
8450 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8451 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
8452
8453 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
8454 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatImportGuestState);
8455 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExportGuestState);
8456 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatPreExit);
8457 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitHandling);
8458 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitIO);
8459 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitMovCRx);
8460 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitXcptNmi);
8461 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExitVmentry);
8462 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8463
8464 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8465
8466 /** @todo This partially defeats the purpose of having preemption hooks.
8467 * The problem is, deregistering the hooks should be moved to a place that
8468 * lasts until the EMT is about to be destroyed not everytime while leaving HM
8469 * context.
8470 */
8471 int rc = hmR0VmxClearVmcs(pVmcsInfo);
8472 AssertRCReturn(rc, rc);
8473
8474#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
8475 /*
8476 * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
8477 * clear a shadow VMCS before allowing that VMCS to become active on another
8478 * logical processor. We may or may not be importing guest state which clears
8479 * it, so cover for it here.
8480 *
8481 * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
8482 */
8483 if ( pVmcsInfo->pvShadowVmcs
8484 && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
8485 {
8486 rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
8487 AssertRCReturn(rc, rc);
8488 }
8489
8490 /*
8491 * Flag that we need to re-export the host state if we switch to this VMCS before
8492 * executing guest or nested-guest code.
8493 */
8494 pVmcsInfo->idHostCpuState = NIL_RTCPUID;
8495#endif
8496
8497 Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
8498 NOREF(idCpu);
8499 return VINF_SUCCESS;
8500}
8501
8502
8503/**
8504 * Leaves the VT-x session.
8505 *
8506 * @returns VBox status code.
8507 * @param pVCpu The cross context virtual CPU structure.
8508 *
8509 * @remarks No-long-jmp zone!!!
8510 */
8511static int hmR0VmxLeaveSession(PVMCPUCC pVCpu)
8512{
8513 HM_DISABLE_PREEMPT(pVCpu);
8514 HMVMX_ASSERT_CPU_SAFE(pVCpu);
8515 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
8516 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
8517
8518 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
8519 and done this from the VMXR0ThreadCtxCallback(). */
8520 if (!pVCpu->hmr0.s.fLeaveDone)
8521 {
8522 int rc2 = hmR0VmxLeave(pVCpu, true /* fImportState */);
8523 AssertRCReturnStmt(rc2, HM_RESTORE_PREEMPT(), rc2);
8524 pVCpu->hmr0.s.fLeaveDone = true;
8525 }
8526 Assert(!pVCpu->cpum.GstCtx.fExtrn);
8527
8528 /*
8529 * !!! IMPORTANT !!!
8530 * If you modify code here, make sure to check whether VMXR0CallRing3Callback() needs to be updated too.
8531 */
8532
8533 /* Deregister hook now that we've left HM context before re-enabling preemption. */
8534 /** @todo Deregistering here means we need to VMCLEAR always
8535 * (longjmp/exit-to-r3) in VT-x which is not efficient, eliminate need
8536 * for calling VMMR0ThreadCtxHookDisable here! */
8537 VMMR0ThreadCtxHookDisable(pVCpu);
8538
8539 /* Leave HM context. This takes care of local init (term) and deregistering the longjmp-to-ring-3 callback. */
8540 int rc = HMR0LeaveCpu(pVCpu);
8541 HM_RESTORE_PREEMPT();
8542 return rc;
8543}
8544
8545
8546/**
8547 * Take necessary actions before going back to ring-3.
8548 *
8549 * An action requires us to go back to ring-3. This function does the necessary
8550 * steps before we can safely return to ring-3. This is not the same as longjmps
8551 * to ring-3, this is voluntary and prepares the guest so it may continue
8552 * executing outside HM (recompiler/IEM).
8553 *
8554 * @returns VBox status code.
8555 * @param pVCpu The cross context virtual CPU structure.
8556 * @param rcExit The reason for exiting to ring-3. Can be
8557 * VINF_VMM_UNKNOWN_RING3_CALL.
8558 */
8559static int hmR0VmxExitToRing3(PVMCPUCC pVCpu, VBOXSTRICTRC rcExit)
8560{
8561 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
8562
8563 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8564 if (RT_UNLIKELY(rcExit == VERR_VMX_INVALID_VMCS_PTR))
8565 {
8566 VMXGetCurrentVmcs(&pVCpu->hm.s.vmx.LastError.HCPhysCurrentVmcs);
8567 pVCpu->hm.s.vmx.LastError.u32VmcsRev = *(uint32_t *)pVmcsInfo->pvVmcs;
8568 pVCpu->hm.s.vmx.LastError.idEnteredCpu = pVCpu->hmr0.s.idEnteredCpu;
8569 /* LastError.idCurrentCpu was updated in hmR0VmxPreRunGuestCommitted(). */
8570 }
8571
8572 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
8573 VMMRZCallRing3Disable(pVCpu);
8574 Log4Func(("rcExit=%d\n", VBOXSTRICTRC_VAL(rcExit)));
8575
8576 /*
8577 * Convert any pending HM events back to TRPM due to premature exits to ring-3.
8578 * We need to do this only on returns to ring-3 and not for longjmps to ring3.
8579 *
8580 * This is because execution may continue from ring-3 and we would need to inject
8581 * the event from there (hence place it back in TRPM).
8582 */
8583 if (pVCpu->hm.s.Event.fPending)
8584 {
8585 hmR0VmxPendingEventToTrpmTrap(pVCpu);
8586 Assert(!pVCpu->hm.s.Event.fPending);
8587
8588 /* Clear the events from the VMCS. */
8589 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0); AssertRC(rc);
8590 rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, 0); AssertRC(rc);
8591 }
8592#ifdef VBOX_STRICT
8593 /*
8594 * We check for rcExit here since for errors like VERR_VMX_UNABLE_TO_START_VM (which are
8595 * fatal), we don't care about verifying duplicate injection of events. Errors like
8596 * VERR_EM_INTERPRET are converted to their VINF_* counterparts -prior- to calling this
8597 * function so those should and will be checked below.
8598 */
8599 else if (RT_SUCCESS(rcExit))
8600 {
8601 /*
8602 * Ensure we don't accidentally clear a pending HM event without clearing the VMCS.
8603 * This can be pretty hard to debug otherwise, interrupts might get injected twice
8604 * occasionally, see @bugref{9180#c42}.
8605 *
8606 * However, if the VM-entry failed, any VM entry-interruption info. field would
8607 * be left unmodified as the event would not have been injected to the guest. In
8608 * such cases, don't assert, we're not going to continue guest execution anyway.
8609 */
8610 uint32_t uExitReason;
8611 uint32_t uEntryIntInfo;
8612 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
8613 rc |= VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &uEntryIntInfo);
8614 AssertRC(rc);
8615 AssertMsg(VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason) || !VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo),
8616 ("uExitReason=%#RX32 uEntryIntInfo=%#RX32 rcExit=%d\n", uExitReason, uEntryIntInfo, VBOXSTRICTRC_VAL(rcExit)));
8617 }
8618#endif
8619
8620 /*
8621 * Clear the interrupt-window and NMI-window VMCS controls as we could have got
8622 * a VM-exit with higher priority than interrupt-window or NMI-window VM-exits
8623 * (e.g. TPR below threshold).
8624 */
8625 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8626 {
8627 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
8628 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
8629 }
8630
8631 /* If we're emulating an instruction, we shouldn't have any TRPM traps pending
8632 and if we're injecting an event we should have a TRPM trap pending. */
8633 AssertMsg(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8634#ifndef DEBUG_bird /* Triggered after firing an NMI against NT4SP1, possibly a triple fault in progress. */
8635 AssertMsg(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu), ("%Rrc\n", VBOXSTRICTRC_VAL(rcExit)));
8636#endif
8637
8638 /* Save guest state and restore host state bits. */
8639 int rc = hmR0VmxLeaveSession(pVCpu);
8640 AssertRCReturn(rc, rc);
8641 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
8642
8643 /* Thread-context hooks are unregistered at this point!!! */
8644 /* Ring-3 callback notifications are unregistered at this point!!! */
8645
8646 /* Sync recompiler state. */
8647 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
8648 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
8649 | CPUM_CHANGED_LDTR
8650 | CPUM_CHANGED_GDTR
8651 | CPUM_CHANGED_IDTR
8652 | CPUM_CHANGED_TR
8653 | CPUM_CHANGED_HIDDEN_SEL_REGS);
8654 if ( pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging
8655 && CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx))
8656 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
8657
8658 Assert(!pVCpu->hmr0.s.fClearTrapFlag);
8659
8660 /* Update the exit-to-ring 3 reason. */
8661 pVCpu->hm.s.rcLastExitToR3 = VBOXSTRICTRC_VAL(rcExit);
8662
8663 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
8664 if ( rcExit != VINF_EM_RAW_INTERRUPT
8665 || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
8666 {
8667 Assert(!(pVCpu->cpum.GstCtx.fExtrn & HMVMX_CPUMCTX_EXTRN_ALL));
8668 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
8669 }
8670
8671 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
8672 VMMRZCallRing3Enable(pVCpu);
8673 return rc;
8674}
8675
8676
8677/**
8678 * VMMRZCallRing3() callback wrapper which saves the guest state before we
8679 * longjump due to a ring-0 assertion.
8680 *
8681 * @returns VBox status code.
8682 * @param pVCpu The cross context virtual CPU structure.
8683 */
8684VMMR0DECL(int) VMXR0AssertionCallback(PVMCPUCC pVCpu)
8685{
8686 /*
8687 * !!! IMPORTANT !!!
8688 * If you modify code here, check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs to be updated too.
8689 * This is a stripped down version which gets out ASAP, trying to not trigger any further assertions.
8690 */
8691 VMMR0AssertionRemoveNotification(pVCpu);
8692 VMMRZCallRing3Disable(pVCpu);
8693 HM_DISABLE_PREEMPT(pVCpu);
8694
8695 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
8696 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
8697 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
8698 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, true /* save DR6 */);
8699
8700 /* Restore host-state bits that VT-x only restores partially. */
8701 if (pVCpu->hmr0.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED)
8702 VMXRestoreHostState(pVCpu->hmr0.s.vmx.fRestoreHostFlags, &pVCpu->hmr0.s.vmx.RestoreHost);
8703 pVCpu->hmr0.s.vmx.fRestoreHostFlags = 0;
8704
8705 /* Restore the lazy host MSRs as we're leaving VT-x context. */
8706 if (pVCpu->hmr0.s.vmx.fLazyMsrs & VMX_LAZY_MSRS_LOADED_GUEST)
8707 hmR0VmxLazyRestoreHostMsrs(pVCpu);
8708
8709 /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
8710 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = false;
8711 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
8712
8713 /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
8714 cleared as part of importing the guest state above. */
8715 hmR0VmxClearVmcs(pVmcsInfo);
8716
8717 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
8718 VMMR0ThreadCtxHookDisable(pVCpu);
8719
8720 /* Leave HM context. This takes care of local init (term). */
8721 HMR0LeaveCpu(pVCpu);
8722 HM_RESTORE_PREEMPT();
8723 return VINF_SUCCESS;
8724}
8725
8726
8727/**
8728 * Pushes a 2-byte value onto the real-mode (in virtual-8086 mode) guest's
8729 * stack.
8730 *
8731 * @returns Strict VBox status code (i.e. informational status codes too).
8732 * @retval VINF_EM_RESET if pushing a value to the stack caused a triple-fault.
8733 * @param pVCpu The cross context virtual CPU structure.
8734 * @param uValue The value to push to the guest stack.
8735 */
8736static VBOXSTRICTRC hmR0VmxRealModeGuestStackPush(PVMCPUCC pVCpu, uint16_t uValue)
8737{
8738 /*
8739 * The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
8740 * virtual 8086 mode in VT-x. See Intel spec. 26.3.1.2 "Checks on Guest Segment Registers".
8741 * See Intel Instruction reference for PUSH and Intel spec. 22.33.1 "Segment Wraparound".
8742 */
8743 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8744 if (pCtx->sp == 1)
8745 return VINF_EM_RESET;
8746 pCtx->sp -= sizeof(uint16_t); /* May wrap around which is expected behaviour. */
8747 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pCtx->ss.u64Base + pCtx->sp, &uValue, sizeof(uint16_t));
8748 AssertRC(rc);
8749 return rc;
8750}
8751
8752
8753/**
8754 * Injects an event into the guest upon VM-entry by updating the relevant fields
8755 * in the VM-entry area in the VMCS.
8756 *
8757 * @returns Strict VBox status code (i.e. informational status codes too).
8758 * @retval VINF_SUCCESS if the event is successfully injected into the VMCS.
8759 * @retval VINF_EM_RESET if event injection resulted in a triple-fault.
8760 *
8761 * @param pVCpu The cross context virtual CPU structure.
8762 * @param pVmxTransient The VMX-transient structure.
8763 * @param pEvent The event being injected.
8764 * @param pfIntrState Pointer to the VT-x guest-interruptibility-state. This
8765 * will be updated if necessary. This cannot not be NULL.
8766 * @param fStepping Whether we're single-stepping guest execution and should
8767 * return VINF_EM_DBG_STEPPED if the event is injected
8768 * directly (registers modified by us, not by hardware on
8769 * VM-entry).
8770 */
8771static VBOXSTRICTRC hmR0VmxInjectEventVmcs(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PCHMEVENT pEvent, bool fStepping,
8772 uint32_t *pfIntrState)
8773{
8774 /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
8775 AssertMsg(!RT_HI_U32(pEvent->u64IntInfo), ("%#RX64\n", pEvent->u64IntInfo));
8776 Assert(pfIntrState);
8777
8778 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
8779 uint32_t u32IntInfo = pEvent->u64IntInfo;
8780 uint32_t const u32ErrCode = pEvent->u32ErrCode;
8781 uint32_t const cbInstr = pEvent->cbInstr;
8782 RTGCUINTPTR const GCPtrFault = pEvent->GCPtrFaultAddress;
8783 uint8_t const uVector = VMX_ENTRY_INT_INFO_VECTOR(u32IntInfo);
8784 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(u32IntInfo);
8785
8786#ifdef VBOX_STRICT
8787 /*
8788 * Validate the error-code-valid bit for hardware exceptions.
8789 * No error codes for exceptions in real-mode.
8790 *
8791 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8792 */
8793 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8794 && !CPUMIsGuestInRealModeEx(pCtx))
8795 {
8796 switch (uVector)
8797 {
8798 case X86_XCPT_PF:
8799 case X86_XCPT_DF:
8800 case X86_XCPT_TS:
8801 case X86_XCPT_NP:
8802 case X86_XCPT_SS:
8803 case X86_XCPT_GP:
8804 case X86_XCPT_AC:
8805 AssertMsg(VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo),
8806 ("Error-code-valid bit not set for exception that has an error code uVector=%#x\n", uVector));
8807 RT_FALL_THRU();
8808 default:
8809 break;
8810 }
8811 }
8812
8813 /* Cannot inject an NMI when block-by-MOV SS is in effect. */
8814 Assert( uIntType != VMX_EXIT_INT_INFO_TYPE_NMI
8815 || !(*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
8816#endif
8817
8818 if ( uIntType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
8819 || uIntType == VMX_EXIT_INT_INFO_TYPE_NMI
8820 || uIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT
8821 || uIntType == VMX_EXIT_INT_INFO_TYPE_SW_XCPT)
8822 {
8823 Assert(uVector <= X86_XCPT_LAST);
8824 Assert(uIntType != VMX_EXIT_INT_INFO_TYPE_NMI || uVector == X86_XCPT_NMI);
8825 Assert(uIntType != VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT || uVector == X86_XCPT_DB);
8826 STAM_COUNTER_INC(&pVCpu->hm.s.aStatInjectedXcpts[uVector]);
8827 }
8828 else
8829 STAM_COUNTER_INC(&pVCpu->hm.s.aStatInjectedIrqs[uVector & MASK_INJECT_IRQ_STAT]);
8830
8831 /*
8832 * Hardware interrupts & exceptions cannot be delivered through the software interrupt
8833 * redirection bitmap to the real mode task in virtual-8086 mode. We must jump to the
8834 * interrupt handler in the (real-mode) guest.
8835 *
8836 * See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode".
8837 * See Intel spec. 20.1.4 "Interrupt and Exception Handling" for real-mode interrupt handling.
8838 */
8839 if (CPUMIsGuestInRealModeEx(pCtx)) /* CR0.PE bit changes are always intercepted, so it's up to date. */
8840 {
8841 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest)
8842 {
8843 /*
8844 * For CPUs with unrestricted guest execution enabled and with the guest
8845 * in real-mode, we must not set the deliver-error-code bit.
8846 *
8847 * See Intel spec. 26.2.1.3 "VM-Entry Control Fields".
8848 */
8849 u32IntInfo &= ~VMX_ENTRY_INT_INFO_ERROR_CODE_VALID;
8850 }
8851 else
8852 {
8853 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
8854 Assert(PDMVmmDevHeapIsEnabled(pVM));
8855 Assert(pVM->hm.s.vmx.pRealModeTSS);
8856 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
8857
8858 /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
8859 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
8860 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
8861 | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
8862 AssertRCReturn(rc2, rc2);
8863
8864 /* Check if the interrupt handler is present in the IVT (real-mode IDT). IDT limit is (4N - 1). */
8865 size_t const cbIdtEntry = sizeof(X86IDTR16);
8866 if (uVector * cbIdtEntry + (cbIdtEntry - 1) > pCtx->idtr.cbIdt)
8867 {
8868 /* If we are trying to inject a #DF with no valid IDT entry, return a triple-fault. */
8869 if (uVector == X86_XCPT_DF)
8870 return VINF_EM_RESET;
8871
8872 /* If we're injecting a #GP with no valid IDT entry, inject a double-fault.
8873 No error codes for exceptions in real-mode. */
8874 if (uVector == X86_XCPT_GP)
8875 {
8876 uint32_t const uXcptDfInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_DF)
8877 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8878 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8879 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8880 HMEVENT EventXcptDf;
8881 RT_ZERO(EventXcptDf);
8882 EventXcptDf.u64IntInfo = uXcptDfInfo;
8883 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptDf, fStepping, pfIntrState);
8884 }
8885
8886 /*
8887 * If we're injecting an event with no valid IDT entry, inject a #GP.
8888 * No error codes for exceptions in real-mode.
8889 *
8890 * See Intel spec. 20.1.4 "Interrupt and Exception Handling"
8891 */
8892 uint32_t const uXcptGpInfo = RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_GP)
8893 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT)
8894 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID, 0)
8895 | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1);
8896 HMEVENT EventXcptGp;
8897 RT_ZERO(EventXcptGp);
8898 EventXcptGp.u64IntInfo = uXcptGpInfo;
8899 return hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &EventXcptGp, fStepping, pfIntrState);
8900 }
8901
8902 /* Software exceptions (#BP and #OF exceptions thrown as a result of INT3 or INTO) */
8903 uint16_t uGuestIp = pCtx->ip;
8904 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_XCPT)
8905 {
8906 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF);
8907 /* #BP and #OF are both benign traps, we need to resume the next instruction. */
8908 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8909 }
8910 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_SW_INT)
8911 uGuestIp = pCtx->ip + (uint16_t)cbInstr;
8912
8913 /* Get the code segment selector and offset from the IDT entry for the interrupt handler. */
8914 X86IDTR16 IdtEntry;
8915 RTGCPHYS const GCPhysIdtEntry = (RTGCPHYS)pCtx->idtr.pIdt + uVector * cbIdtEntry;
8916 rc2 = PGMPhysSimpleReadGCPhys(pVM, &IdtEntry, GCPhysIdtEntry, cbIdtEntry);
8917 AssertRCReturn(rc2, rc2);
8918
8919 /* Construct the stack frame for the interrupt/exception handler. */
8920 VBOXSTRICTRC rcStrict;
8921 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->eflags.u32);
8922 if (rcStrict == VINF_SUCCESS)
8923 {
8924 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, pCtx->cs.Sel);
8925 if (rcStrict == VINF_SUCCESS)
8926 rcStrict = hmR0VmxRealModeGuestStackPush(pVCpu, uGuestIp);
8927 }
8928
8929 /* Clear the required eflag bits and jump to the interrupt/exception handler. */
8930 if (rcStrict == VINF_SUCCESS)
8931 {
8932 pCtx->eflags.u32 &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
8933 pCtx->rip = IdtEntry.offSel;
8934 pCtx->cs.Sel = IdtEntry.uSel;
8935 pCtx->cs.ValidSel = IdtEntry.uSel;
8936 pCtx->cs.u64Base = IdtEntry.uSel << cbIdtEntry;
8937 if ( uIntType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
8938 && uVector == X86_XCPT_PF)
8939 pCtx->cr2 = GCPtrFault;
8940
8941 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CS | HM_CHANGED_GUEST_CR2
8942 | HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
8943 | HM_CHANGED_GUEST_RSP);
8944
8945 /*
8946 * If we delivered a hardware exception (other than an NMI) and if there was
8947 * block-by-STI in effect, we should clear it.
8948 */
8949 if (*pfIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
8950 {
8951 Assert( uIntType != VMX_ENTRY_INT_INFO_TYPE_NMI
8952 && uIntType != VMX_ENTRY_INT_INFO_TYPE_EXT_INT);
8953 Log4Func(("Clearing inhibition due to STI\n"));
8954 *pfIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
8955 }
8956
8957 Log4(("Injected real-mode: u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x Eflags=%#x CS:EIP=%04x:%04x\n",
8958 u32IntInfo, u32ErrCode, cbInstr, pCtx->eflags.u, pCtx->cs.Sel, pCtx->eip));
8959
8960 /*
8961 * The event has been truly dispatched to the guest. Mark it as no longer pending so
8962 * we don't attempt to undo it if we are returning to ring-3 before executing guest code.
8963 */
8964 pVCpu->hm.s.Event.fPending = false;
8965
8966 /*
8967 * If we eventually support nested-guest execution without unrestricted guest execution,
8968 * we should set fInterceptEvents here.
8969 */
8970 Assert(!pVmxTransient->fIsNestedGuest);
8971
8972 /* If we're stepping and we've changed cs:rip above, bail out of the VMX R0 execution loop. */
8973 if (fStepping)
8974 rcStrict = VINF_EM_DBG_STEPPED;
8975 }
8976 AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
8977 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
8978 return rcStrict;
8979 }
8980 }
8981
8982 /*
8983 * Validate.
8984 */
8985 Assert(VMX_ENTRY_INT_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
8986 Assert(!(u32IntInfo & VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK)); /* Bits 30:12 MBZ. */
8987
8988 /*
8989 * Inject the event into the VMCS.
8990 */
8991 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, u32IntInfo);
8992 if (VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(u32IntInfo))
8993 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, u32ErrCode);
8994 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
8995 AssertRC(rc);
8996
8997 /*
8998 * Update guest CR2 if this is a page-fault.
8999 */
9000 if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
9001 pCtx->cr2 = GCPtrFault;
9002
9003 Log4(("Injecting u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x CR2=%#RX64\n", u32IntInfo, u32ErrCode, cbInstr, pCtx->cr2));
9004 return VINF_SUCCESS;
9005}
9006
9007
9008/**
9009 * Evaluates the event to be delivered to the guest and sets it as the pending
9010 * event.
9011 *
9012 * Toggling of interrupt force-flags here is safe since we update TRPM on premature
9013 * exits to ring-3 before executing guest code, see hmR0VmxExitToRing3(). We must
9014 * NOT restore these force-flags.
9015 *
9016 * @returns Strict VBox status code (i.e. informational status codes too).
9017 * @param pVCpu The cross context virtual CPU structure.
9018 * @param pVmxTransient The VMX-transient structure.
9019 * @param pfIntrState Where to store the VT-x guest-interruptibility state.
9020 */
9021static VBOXSTRICTRC hmR0VmxEvaluatePendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t *pfIntrState)
9022{
9023 Assert(pfIntrState);
9024 Assert(!TRPMHasTrap(pVCpu));
9025
9026 /*
9027 * Compute/update guest-interruptibility state related FFs.
9028 * The FFs will be used below while evaluating events to be injected.
9029 */
9030 *pfIntrState = hmR0VmxGetGuestIntrStateAndUpdateFFs(pVCpu);
9031
9032 /*
9033 * Evaluate if a new event needs to be injected.
9034 * An event that's already pending has already performed all necessary checks.
9035 */
9036 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
9037 bool const fIsNestedGuest = pVmxTransient->fIsNestedGuest;
9038 if ( !pVCpu->hm.s.Event.fPending
9039 && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
9040 {
9041 /** @todo SMI. SMIs take priority over NMIs. */
9042
9043 /*
9044 * NMIs.
9045 * NMIs take priority over external interrupts.
9046 */
9047 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9048 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
9049 {
9050 /*
9051 * For a guest, the FF always indicates the guest's ability to receive an NMI.
9052 *
9053 * For a nested-guest, the FF always indicates the outer guest's ability to
9054 * receive an NMI while the guest-interruptibility state bit depends on whether
9055 * the nested-hypervisor is using virtual-NMIs.
9056 */
9057 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_BLOCK_NMIS))
9058 {
9059#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9060 if ( fIsNestedGuest
9061 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_NMI_EXIT))
9062 return IEMExecVmxVmexitXcptNmi(pVCpu);
9063#endif
9064 hmR0VmxSetPendingXcptNmi(pVCpu);
9065 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
9066 Log4Func(("NMI pending injection\n"));
9067
9068 /* We've injected the NMI, bail. */
9069 return VINF_SUCCESS;
9070 }
9071 else if (!fIsNestedGuest)
9072 hmR0VmxSetNmiWindowExitVmcs(pVmcsInfo);
9073 }
9074
9075 /*
9076 * External interrupts (PIC/APIC).
9077 * Once PDMGetInterrupt() returns a valid interrupt we -must- deliver it.
9078 * We cannot re-request the interrupt from the controller again.
9079 */
9080 if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
9081 && !pVCpu->hm.s.fSingleInstruction)
9082 {
9083 Assert(!DBGFIsStepping(pVCpu));
9084 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
9085 AssertRC(rc);
9086
9087 /*
9088 * We must not check EFLAGS directly when executing a nested-guest, use
9089 * CPUMIsGuestPhysIntrEnabled() instead as EFLAGS.IF does not control the blocking of
9090 * external interrupts when "External interrupt exiting" is set. This fixes a nasty
9091 * SMP hang while executing nested-guest VCPUs on spinlocks which aren't rescued by
9092 * other VM-exits (like a preemption timer), see @bugref{9562#c18}.
9093 *
9094 * See Intel spec. 25.4.1 "Event Blocking".
9095 */
9096 if (CPUMIsGuestPhysIntrEnabled(pVCpu))
9097 {
9098#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9099 if ( fIsNestedGuest
9100 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
9101 {
9102 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, 0 /* uVector */, true /* fIntPending */);
9103 if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
9104 return rcStrict;
9105 }
9106#endif
9107 uint8_t u8Interrupt;
9108 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
9109 if (RT_SUCCESS(rc))
9110 {
9111#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
9112 if ( fIsNestedGuest
9113 && CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT))
9114 {
9115 VBOXSTRICTRC rcStrict = IEMExecVmxVmexitExtInt(pVCpu, u8Interrupt, false /* fIntPending */);
9116 Assert(rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE);
9117 return rcStrict;
9118 }
9119#endif
9120 hmR0VmxSetPendingExtInt(pVCpu, u8Interrupt);
9121 Log4Func(("External interrupt (%#x) pending injection\n", u8Interrupt));
9122 }
9123 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
9124 {
9125 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
9126
9127 if ( !fIsNestedGuest
9128 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
9129 hmR0VmxApicSetTprThreshold(pVmcsInfo, u8Interrupt >> 4);
9130 /* else: for nested-guests, TPR threshold is picked up while merging VMCS controls. */
9131
9132 /*
9133 * If the CPU doesn't have TPR shadowing, we will always get a VM-exit on TPR changes and
9134 * APICSetTpr() will end up setting the VMCPU_FF_INTERRUPT_APIC if required, so there is no
9135 * need to re-set this force-flag here.
9136 */
9137 }
9138 else
9139 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
9140
9141 /* We've injected the interrupt or taken necessary action, bail. */
9142 return VINF_SUCCESS;
9143 }
9144 if (!fIsNestedGuest)
9145 hmR0VmxSetIntWindowExitVmcs(pVmcsInfo);
9146 }
9147 }
9148 else if (!fIsNestedGuest)
9149 {
9150 /*
9151 * An event is being injected or we are in an interrupt shadow. Check if another event is
9152 * pending. If so, instruct VT-x to cause a VM-exit as soon as the guest is ready to accept
9153 * the pending event.
9154 */
9155 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI))
9156 hmR0VmxSetNmiWindowExitVmcs(pVmcsInfo);
9157 else if ( VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
9158 && !pVCpu->hm.s.fSingleInstruction)
9159 hmR0VmxSetIntWindowExitVmcs(pVmcsInfo);
9160 }
9161 /* else: for nested-guests, NMI/interrupt-window exiting will be picked up when merging VMCS controls. */
9162
9163 return VINF_SUCCESS;
9164}
9165
9166
9167/**
9168 * Injects any pending events into the guest if the guest is in a state to
9169 * receive them.
9170 *
9171 * @returns Strict VBox status code (i.e. informational status codes too).
9172 * @param pVCpu The cross context virtual CPU structure.
9173 * @param pVmxTransient The VMX-transient structure.
9174 * @param fIntrState The VT-x guest-interruptibility state.
9175 * @param fStepping Whether we are single-stepping the guest using the
9176 * hypervisor debugger and should return
9177 * VINF_EM_DBG_STEPPED if the event was dispatched
9178 * directly.
9179 */
9180static VBOXSTRICTRC hmR0VmxInjectPendingEvent(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t fIntrState, bool fStepping)
9181{
9182 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9183 Assert(VMMRZCallRing3IsEnabled(pVCpu));
9184
9185#ifdef VBOX_STRICT
9186 /*
9187 * Verify guest-interruptibility state.
9188 *
9189 * We put this in a scoped block so we do not accidentally use fBlockSti or fBlockMovSS,
9190 * since injecting an event may modify the interruptibility state and we must thus always
9191 * use fIntrState.
9192 */
9193 {
9194 bool const fBlockMovSS = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS);
9195 bool const fBlockSti = RT_BOOL(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI);
9196 Assert(!fBlockSti || !(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_RFLAGS));
9197 Assert(!fBlockSti || pVCpu->cpum.GstCtx.eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
9198 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI)); /* We don't support block-by-SMI yet.*/
9199 Assert(!TRPMHasTrap(pVCpu));
9200 NOREF(fBlockMovSS); NOREF(fBlockSti);
9201 }
9202#endif
9203
9204 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
9205 if (pVCpu->hm.s.Event.fPending)
9206 {
9207 /*
9208 * Do -not- clear any interrupt-window exiting control here. We might have an interrupt
9209 * pending even while injecting an event and in this case, we want a VM-exit as soon as
9210 * the guest is ready for the next interrupt, see @bugref{6208#c45}.
9211 *
9212 * See Intel spec. 26.6.5 "Interrupt-Window Exiting and Virtual-Interrupt Delivery".
9213 */
9214 uint32_t const uIntType = VMX_ENTRY_INT_INFO_TYPE(pVCpu->hm.s.Event.u64IntInfo);
9215#ifdef VBOX_STRICT
9216 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
9217 {
9218 Assert(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_IF);
9219 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
9220 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
9221 }
9222 else if (uIntType == VMX_ENTRY_INT_INFO_TYPE_NMI)
9223 {
9224 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI));
9225 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI));
9226 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
9227 }
9228#endif
9229 Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#RX32\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
9230 uIntType));
9231
9232 /*
9233 * Inject the event and get any changes to the guest-interruptibility state.
9234 *
9235 * The guest-interruptibility state may need to be updated if we inject the event
9236 * into the guest IDT ourselves (for real-on-v86 guest injecting software interrupts).
9237 */
9238 rcStrict = hmR0VmxInjectEventVmcs(pVCpu, pVmxTransient, &pVCpu->hm.s.Event, fStepping, &fIntrState);
9239 AssertRCReturn(VBOXSTRICTRC_VAL(rcStrict), rcStrict);
9240
9241 if (uIntType == VMX_ENTRY_INT_INFO_TYPE_EXT_INT)
9242 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
9243 else
9244 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
9245 }
9246
9247 /*
9248 * Deliver any pending debug exceptions if the guest is single-stepping using EFLAGS.TF and
9249 * is an interrupt shadow (block-by-STI or block-by-MOV SS).
9250 */
9251 if ( (fIntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
9252 && !pVmxTransient->fIsNestedGuest)
9253 {
9254 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS);
9255
9256 if (!pVCpu->hm.s.fSingleInstruction)
9257 {
9258 /*
9259 * Set or clear the BS bit depending on whether the trap flag is active or not. We need
9260 * to do both since we clear the BS bit from the VMCS while exiting to ring-3.
9261 */
9262 Assert(!DBGFIsStepping(pVCpu));
9263 uint8_t const fTrapFlag = !!(pVCpu->cpum.GstCtx.eflags.u32 & X86_EFL_TF);
9264 int rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, fTrapFlag << VMX_BF_VMCS_PENDING_DBG_XCPT_BS_SHIFT);
9265 AssertRC(rc);
9266 }
9267 else
9268 {
9269 /*
9270 * We must not deliver a debug exception when single-stepping over STI/Mov-SS in the
9271 * hypervisor debugger using EFLAGS.TF but rather clear interrupt inhibition. However,
9272 * we take care of this case in hmR0VmxExportSharedDebugState and also the case if
9273 * we use MTF, so just make sure it's called before executing guest-code.
9274 */
9275 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR_MASK);
9276 }
9277 }
9278 /* else: for nested-guest currently handling while merging controls. */
9279
9280 /*
9281 * Finally, update the guest-interruptibility state.
9282 *
9283 * This is required for the real-on-v86 software interrupt injection, for
9284 * pending debug exceptions as well as updates to the guest state from ring-3 (IEM).
9285 */
9286 int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
9287 AssertRC(rc);
9288
9289 /*
9290 * There's no need to clear the VM-entry interruption-information field here if we're not
9291 * injecting anything. VT-x clears the valid bit on every VM-exit.
9292 *
9293 * See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
9294 */
9295
9296 Assert(rcStrict == VINF_SUCCESS || rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping));
9297 return rcStrict;
9298}
9299
9300
9301/**
9302 * Enters the VT-x session.
9303 *
9304 * @returns VBox status code.
9305 * @param pVCpu The cross context virtual CPU structure.
9306 */
9307VMMR0DECL(int) VMXR0Enter(PVMCPUCC pVCpu)
9308{
9309 AssertPtr(pVCpu);
9310 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fSupported);
9311 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9312
9313 LogFlowFunc(("pVCpu=%p\n", pVCpu));
9314 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9315 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
9316
9317#ifdef VBOX_STRICT
9318 /* At least verify VMX is enabled, since we can't check if we're in VMX root mode without #GP'ing. */
9319 RTCCUINTREG uHostCr4 = ASMGetCR4();
9320 if (!(uHostCr4 & X86_CR4_VMXE))
9321 {
9322 LogRelFunc(("X86_CR4_VMXE bit in CR4 is not set!\n"));
9323 return VERR_VMX_X86_CR4_VMXE_CLEARED;
9324 }
9325#endif
9326
9327 /*
9328 * Do the EMT scheduled L1D and MDS flush here if needed.
9329 */
9330 if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_L1D_SCHED)
9331 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
9332 else if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_MDS_SCHED)
9333 hmR0MdsClear();
9334
9335 /*
9336 * Load the appropriate VMCS as the current and active one.
9337 */
9338 PVMXVMCSINFO pVmcsInfo;
9339 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx);
9340 if (!fInNestedGuestMode)
9341 pVmcsInfo = &pVCpu->hmr0.s.vmx.VmcsInfo;
9342 else
9343 pVmcsInfo = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
9344 int rc = hmR0VmxLoadVmcs(pVmcsInfo);
9345 if (RT_SUCCESS(rc))
9346 {
9347 pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs = fInNestedGuestMode;
9348 pVCpu->hm.s.vmx.fSwitchedToNstGstVmcsCopyForRing3 = fInNestedGuestMode;
9349 pVCpu->hmr0.s.fLeaveDone = false;
9350 Log4Func(("Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
9351 }
9352 return rc;
9353}
9354
9355
9356/**
9357 * The thread-context callback.
9358 *
9359 * This is used together with RTThreadCtxHookCreate() on platforms which
9360 * supports it, and directly from VMMR0EmtPrepareForBlocking() and
9361 * VMMR0EmtResumeAfterBlocking() on platforms which don't.
9362 *
9363 * @param enmEvent The thread-context event.
9364 * @param pVCpu The cross context virtual CPU structure.
9365 * @param fGlobalInit Whether global VT-x/AMD-V init. was used.
9366 * @thread EMT(pVCpu)
9367 */
9368VMMR0DECL(void) VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit)
9369{
9370 AssertPtr(pVCpu);
9371 RT_NOREF1(fGlobalInit);
9372
9373 switch (enmEvent)
9374 {
9375 case RTTHREADCTXEVENT_OUT:
9376 {
9377 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9378 VMCPU_ASSERT_EMT(pVCpu);
9379
9380 /* No longjmps (logger flushes, locks) in this fragile context. */
9381 VMMRZCallRing3Disable(pVCpu);
9382 Log4Func(("Preempting: HostCpuId=%u\n", RTMpCpuId()));
9383
9384 /* Restore host-state (FPU, debug etc.) */
9385 if (!pVCpu->hmr0.s.fLeaveDone)
9386 {
9387 /*
9388 * Do -not- import the guest-state here as we might already be in the middle of importing
9389 * it, esp. bad if we're holding the PGM lock, see comment in hmR0VmxImportGuestState().
9390 */
9391 hmR0VmxLeave(pVCpu, false /* fImportState */);
9392 pVCpu->hmr0.s.fLeaveDone = true;
9393 }
9394
9395 /* Leave HM context, takes care of local init (term). */
9396 int rc = HMR0LeaveCpu(pVCpu);
9397 AssertRC(rc);
9398
9399 /* Restore longjmp state. */
9400 VMMRZCallRing3Enable(pVCpu);
9401 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
9402 break;
9403 }
9404
9405 case RTTHREADCTXEVENT_IN:
9406 {
9407 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9408 VMCPU_ASSERT_EMT(pVCpu);
9409
9410 /* Do the EMT scheduled L1D and MDS flush here if needed. */
9411 if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_L1D_SCHED)
9412 ASMWrMsr(MSR_IA32_FLUSH_CMD, MSR_IA32_FLUSH_CMD_F_L1D);
9413 else if (pVCpu->hmr0.s.fWorldSwitcher & HM_WSF_MDS_SCHED)
9414 hmR0MdsClear();
9415
9416 /* No longjmps here, as we don't want to trigger preemption (& its hook) while resuming. */
9417 VMMRZCallRing3Disable(pVCpu);
9418 Log4Func(("Resumed: HostCpuId=%u\n", RTMpCpuId()));
9419
9420 /* Initialize the bare minimum state required for HM. This takes care of
9421 initializing VT-x if necessary (onlined CPUs, local init etc.) */
9422 int rc = hmR0EnterCpu(pVCpu);
9423 AssertRC(rc);
9424 Assert( (pVCpu->hm.s.fCtxChanged & (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE))
9425 == (HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE));
9426
9427 /* Load the active VMCS as the current one. */
9428 PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
9429 rc = hmR0VmxLoadVmcs(pVmcsInfo);
9430 AssertRC(rc);
9431 Log4Func(("Resumed: Loaded Vmcs. HostCpuId=%u\n", RTMpCpuId()));
9432 pVCpu->hmr0.s.fLeaveDone = false;
9433
9434 /* Restore longjmp state. */
9435 VMMRZCallRing3Enable(pVCpu);
9436 break;
9437 }
9438
9439 default:
9440 break;
9441 }
9442}
9443
9444
9445/**
9446 * Exports the host state into the VMCS host-state area.
9447 * Sets up the VM-exit MSR-load area.
9448 *
9449 * The CPU state will be loaded from these fields on every successful VM-exit.
9450 *
9451 * @returns VBox status code.
9452 * @param pVCpu The cross context virtual CPU structure.
9453 *
9454 * @remarks No-long-jump zone!!!
9455 */
9456static int hmR0VmxExportHostState(PVMCPUCC pVCpu)
9457{
9458 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9459
9460 int rc = VINF_SUCCESS;
9461 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
9462 {
9463 uint64_t uHostCr4 = hmR0VmxExportHostControlRegs();
9464
9465 rc = hmR0VmxExportHostSegmentRegs(pVCpu, uHostCr4);
9466 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9467
9468 hmR0VmxExportHostMsrs(pVCpu);
9469
9470 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_HOST_CONTEXT;
9471 }
9472 return rc;
9473}
9474
9475
9476/**
9477 * Saves the host state in the VMCS host-state.
9478 *
9479 * @returns VBox status code.
9480 * @param pVCpu The cross context virtual CPU structure.
9481 *
9482 * @remarks No-long-jump zone!!!
9483 */
9484VMMR0DECL(int) VMXR0ExportHostState(PVMCPUCC pVCpu)
9485{
9486 AssertPtr(pVCpu);
9487 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9488
9489 /*
9490 * Export the host state here while entering HM context.
9491 * When thread-context hooks are used, we might get preempted and have to re-save the host
9492 * state but most of the time we won't be, so do it here before we disable interrupts.
9493 */
9494 return hmR0VmxExportHostState(pVCpu);
9495}
9496
9497
9498/**
9499 * Exports the guest state into the VMCS guest-state area.
9500 *
9501 * The will typically be done before VM-entry when the guest-CPU state and the
9502 * VMCS state may potentially be out of sync.
9503 *
9504 * Sets up the VM-entry MSR-load and VM-exit MSR-store areas. Sets up the
9505 * VM-entry controls.
9506 * Sets up the appropriate VMX non-root function to execute guest code based on
9507 * the guest CPU mode.
9508 *
9509 * @returns VBox strict status code.
9510 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9511 * without unrestricted guest execution and the VMMDev is not presently
9512 * mapped (e.g. EFI32).
9513 *
9514 * @param pVCpu The cross context virtual CPU structure.
9515 * @param pVmxTransient The VMX-transient structure.
9516 *
9517 * @remarks No-long-jump zone!!!
9518 */
9519static VBOXSTRICTRC hmR0VmxExportGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9520{
9521 AssertPtr(pVCpu);
9522 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9523 LogFlowFunc(("pVCpu=%p\n", pVCpu));
9524
9525 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExportGuestState, x);
9526
9527 /*
9528 * Determine real-on-v86 mode.
9529 * Used when the guest is in real-mode and unrestricted guest execution is not used.
9530 */
9531 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmxTransient->pVmcsInfo->pShared;
9532 if ( pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest
9533 || !CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx))
9534 pVmcsInfoShared->RealMode.fRealOnV86Active = false;
9535 else
9536 {
9537 Assert(!pVmxTransient->fIsNestedGuest);
9538 pVmcsInfoShared->RealMode.fRealOnV86Active = true;
9539 }
9540
9541 /*
9542 * Any ordering dependency among the sub-functions below must be explicitly stated using comments.
9543 * Ideally, assert that the cross-dependent bits are up-to-date at the point of using it.
9544 */
9545 int rc = hmR0VmxExportGuestEntryExitCtls(pVCpu, pVmxTransient);
9546 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9547
9548 rc = hmR0VmxExportGuestCR0(pVCpu, pVmxTransient);
9549 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9550
9551 VBOXSTRICTRC rcStrict = hmR0VmxExportGuestCR3AndCR4(pVCpu, pVmxTransient);
9552 if (rcStrict == VINF_SUCCESS)
9553 { /* likely */ }
9554 else
9555 {
9556 Assert(rcStrict == VINF_EM_RESCHEDULE_REM || RT_FAILURE_NP(rcStrict));
9557 return rcStrict;
9558 }
9559
9560 rc = hmR0VmxExportGuestSegRegsXdtr(pVCpu, pVmxTransient);
9561 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9562
9563 rc = hmR0VmxExportGuestMsrs(pVCpu, pVmxTransient);
9564 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9565
9566 hmR0VmxExportGuestApicTpr(pVCpu, pVmxTransient);
9567 hmR0VmxExportGuestXcptIntercepts(pVCpu, pVmxTransient);
9568 hmR0VmxExportGuestRip(pVCpu);
9569 hmR0VmxExportGuestRsp(pVCpu);
9570 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9571
9572 rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9573 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
9574
9575 /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
9576 ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~( (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
9577 | HM_CHANGED_GUEST_CR2
9578 | (HM_CHANGED_GUEST_DR_MASK & ~HM_CHANGED_GUEST_DR7)
9579 | HM_CHANGED_GUEST_X87
9580 | HM_CHANGED_GUEST_SSE_AVX
9581 | HM_CHANGED_GUEST_OTHER_XSAVE
9582 | HM_CHANGED_GUEST_XCRx
9583 | HM_CHANGED_GUEST_KERNEL_GS_BASE /* Part of lazy or auto load-store MSRs. */
9584 | HM_CHANGED_GUEST_SYSCALL_MSRS /* Part of lazy or auto load-store MSRs. */
9585 | HM_CHANGED_GUEST_TSC_AUX
9586 | HM_CHANGED_GUEST_OTHER_MSRS
9587 | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
9588
9589 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExportGuestState, x);
9590 return rc;
9591}
9592
9593
9594/**
9595 * Exports the state shared between the host and guest into the VMCS.
9596 *
9597 * @param pVCpu The cross context virtual CPU structure.
9598 * @param pVmxTransient The VMX-transient structure.
9599 *
9600 * @remarks No-long-jump zone!!!
9601 */
9602static void hmR0VmxExportSharedState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9603{
9604 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9605 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9606
9607 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_DR_MASK)
9608 {
9609 int rc = hmR0VmxExportSharedDebugState(pVCpu, pVmxTransient);
9610 AssertRC(rc);
9611 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_GUEST_DR_MASK;
9612
9613 /* Loading shared debug bits might have changed eflags.TF bit for debugging purposes. */
9614 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_GUEST_RFLAGS)
9615 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9616 }
9617
9618 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_GUEST_LAZY_MSRS)
9619 {
9620 hmR0VmxLazyLoadGuestMsrs(pVCpu);
9621 pVCpu->hm.s.fCtxChanged &= ~HM_CHANGED_VMX_GUEST_LAZY_MSRS;
9622 }
9623
9624 AssertMsg(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE),
9625 ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
9626}
9627
9628
9629/**
9630 * Worker for loading the guest-state bits in the inner VT-x execution loop.
9631 *
9632 * @returns Strict VBox status code (i.e. informational status codes too).
9633 * @retval VINF_EM_RESCHEDULE_REM if we try to emulate non-paged guest code
9634 * without unrestricted guest execution and the VMMDev is not presently
9635 * mapped (e.g. EFI32).
9636 *
9637 * @param pVCpu The cross context virtual CPU structure.
9638 * @param pVmxTransient The VMX-transient structure.
9639 *
9640 * @remarks No-long-jump zone!!!
9641 */
9642static VBOXSTRICTRC hmR0VmxExportGuestStateOptimal(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
9643{
9644 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
9645 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9646
9647#ifdef HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE
9648 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
9649#endif
9650
9651 /*
9652 * For many VM-exits only RIP/RSP/RFLAGS (and HWVIRT state when executing a nested-guest)
9653 * changes. First try to export only these without going through all other changed-flag checks.
9654 */
9655 VBOXSTRICTRC rcStrict;
9656 uint64_t const fCtxMask = HM_CHANGED_ALL_GUEST & ~HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE;
9657 uint64_t const fMinimalMask = HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT;
9658 uint64_t const fCtxChanged = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9659
9660 /* If only RIP/RSP/RFLAGS/HWVIRT changed, export only those (quicker, happens more often).*/
9661 if ( (fCtxChanged & fMinimalMask)
9662 && !(fCtxChanged & (fCtxMask & ~fMinimalMask)))
9663 {
9664 hmR0VmxExportGuestRip(pVCpu);
9665 hmR0VmxExportGuestRsp(pVCpu);
9666 hmR0VmxExportGuestRflags(pVCpu, pVmxTransient);
9667 rcStrict = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
9668 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportMinimal);
9669 }
9670 /* If anything else also changed, go through the full export routine and export as required. */
9671 else if (fCtxChanged & fCtxMask)
9672 {
9673 rcStrict = hmR0VmxExportGuestState(pVCpu, pVmxTransient);
9674 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
9675 { /* likely */}
9676 else
9677 {
9678 AssertMsg(rcStrict == VINF_EM_RESCHEDULE_REM, ("Failed to export guest state! rc=%Rrc\n",
9679 VBOXSTRICTRC_VAL(rcStrict)));
9680 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
9681 return rcStrict;
9682 }
9683 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportFull);
9684 }
9685 /* Nothing changed, nothing to load here. */
9686 else
9687 rcStrict = VINF_SUCCESS;
9688
9689#ifdef VBOX_STRICT
9690 /* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
9691 uint64_t const fCtxChangedCur = ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged);
9692 AssertMsg(!(fCtxChangedCur & fCtxMask), ("fCtxChangedCur=%#RX64\n", fCtxChangedCur));
9693#endif
9694 return rcStrict;
9695}
9696
9697
9698/**
9699 * Tries to determine what part of the guest-state VT-x has deemed as invalid
9700 * and update error record fields accordingly.
9701 *
9702 * @returns VMX_IGS_* error codes.
9703 * @retval VMX_IGS_REASON_NOT_FOUND if this function could not find anything
9704 * wrong with the guest state.
9705 *
9706 * @param pVCpu The cross context virtual CPU structure.
9707 * @param pVmcsInfo The VMCS info. object.
9708 *
9709 * @remarks This function assumes our cache of the VMCS controls
9710 * are valid, i.e. hmR0VmxCheckCachedVmcsCtls() succeeded.
9711 */
9712static uint32_t hmR0VmxCheckGuestState(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
9713{
9714#define HMVMX_ERROR_BREAK(err) { uError = (err); break; }
9715#define HMVMX_CHECK_BREAK(expr, err) do { \
9716 if (!(expr)) { uError = (err); break; } \
9717 } while (0)
9718
9719 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
9720 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
9721 uint32_t uError = VMX_IGS_ERROR;
9722 uint32_t u32IntrState = 0;
9723 bool const fUnrestrictedGuest = pVM->hmr0.s.vmx.fUnrestrictedGuest;
9724 do
9725 {
9726 int rc;
9727
9728 /*
9729 * Guest-interruptibility state.
9730 *
9731 * Read this first so that any check that fails prior to those that actually
9732 * require the guest-interruptibility state would still reflect the correct
9733 * VMCS value and avoids causing further confusion.
9734 */
9735 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &u32IntrState);
9736 AssertRC(rc);
9737
9738 uint32_t u32Val;
9739 uint64_t u64Val;
9740
9741 /*
9742 * CR0.
9743 */
9744 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9745 uint64_t fSetCr0 = (g_HmMsrs.u.vmx.u64Cr0Fixed0 & g_HmMsrs.u.vmx.u64Cr0Fixed1);
9746 uint64_t const fZapCr0 = (g_HmMsrs.u.vmx.u64Cr0Fixed0 | g_HmMsrs.u.vmx.u64Cr0Fixed1);
9747 /* Exceptions for unrestricted guest execution for CR0 fixed bits (PE, PG).
9748 See Intel spec. 26.3.1 "Checks on Guest Control Registers, Debug Registers and MSRs." */
9749 if (fUnrestrictedGuest)
9750 fSetCr0 &= ~(uint64_t)(X86_CR0_PE | X86_CR0_PG);
9751
9752 uint64_t u64GuestCr0;
9753 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64GuestCr0);
9754 AssertRC(rc);
9755 HMVMX_CHECK_BREAK((u64GuestCr0 & fSetCr0) == fSetCr0, VMX_IGS_CR0_FIXED1);
9756 HMVMX_CHECK_BREAK(!(u64GuestCr0 & ~fZapCr0), VMX_IGS_CR0_FIXED0);
9757 if ( !fUnrestrictedGuest
9758 && (u64GuestCr0 & X86_CR0_PG)
9759 && !(u64GuestCr0 & X86_CR0_PE))
9760 HMVMX_ERROR_BREAK(VMX_IGS_CR0_PG_PE_COMBO);
9761
9762 /*
9763 * CR4.
9764 */
9765 /** @todo Why do we need to OR and AND the fixed-0 and fixed-1 bits below? */
9766 uint64_t const fSetCr4 = (g_HmMsrs.u.vmx.u64Cr4Fixed0 & g_HmMsrs.u.vmx.u64Cr4Fixed1);
9767 uint64_t const fZapCr4 = (g_HmMsrs.u.vmx.u64Cr4Fixed0 | g_HmMsrs.u.vmx.u64Cr4Fixed1);
9768
9769 uint64_t u64GuestCr4;
9770 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR4, &u64GuestCr4);
9771 AssertRC(rc);
9772 HMVMX_CHECK_BREAK((u64GuestCr4 & fSetCr4) == fSetCr4, VMX_IGS_CR4_FIXED1);
9773 HMVMX_CHECK_BREAK(!(u64GuestCr4 & ~fZapCr4), VMX_IGS_CR4_FIXED0);
9774
9775 /*
9776 * IA32_DEBUGCTL MSR.
9777 */
9778 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, &u64Val);
9779 AssertRC(rc);
9780 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9781 && (u64Val & 0xfffffe3c)) /* Bits 31:9, bits 5:2 MBZ. */
9782 {
9783 HMVMX_ERROR_BREAK(VMX_IGS_DEBUGCTL_MSR_RESERVED);
9784 }
9785 uint64_t u64DebugCtlMsr = u64Val;
9786
9787#ifdef VBOX_STRICT
9788 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY, &u32Val);
9789 AssertRC(rc);
9790 Assert(u32Val == pVmcsInfo->u32EntryCtls);
9791#endif
9792 bool const fLongModeGuest = RT_BOOL(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
9793
9794 /*
9795 * RIP and RFLAGS.
9796 */
9797 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RIP, &u64Val);
9798 AssertRC(rc);
9799 /* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
9800 if ( !fLongModeGuest
9801 || !pCtx->cs.Attr.n.u1Long)
9802 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffff00000000)), VMX_IGS_LONGMODE_RIP_INVALID);
9803 /** @todo If the processor supports N < 64 linear-address bits, bits 63:N
9804 * must be identical if the "IA-32e mode guest" VM-entry
9805 * control is 1 and CS.L is 1. No check applies if the
9806 * CPU supports 64 linear-address bits. */
9807
9808 /* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
9809 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_RFLAGS, &u64Val);
9810 AssertRC(rc);
9811 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffc08028)), /* Bit 63:22, Bit 15, 5, 3 MBZ. */
9812 VMX_IGS_RFLAGS_RESERVED);
9813 HMVMX_CHECK_BREAK((u64Val & X86_EFL_RA1_MASK), VMX_IGS_RFLAGS_RESERVED1); /* Bit 1 MB1. */
9814 uint32_t const u32Eflags = u64Val;
9815
9816 if ( fLongModeGuest
9817 || ( fUnrestrictedGuest
9818 && !(u64GuestCr0 & X86_CR0_PE)))
9819 {
9820 HMVMX_CHECK_BREAK(!(u32Eflags & X86_EFL_VM), VMX_IGS_RFLAGS_VM_INVALID);
9821 }
9822
9823 uint32_t u32EntryInfo;
9824 rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
9825 AssertRC(rc);
9826 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
9827 HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
9828
9829 /*
9830 * 64-bit checks.
9831 */
9832 if (fLongModeGuest)
9833 {
9834 HMVMX_CHECK_BREAK(u64GuestCr0 & X86_CR0_PG, VMX_IGS_CR0_PG_LONGMODE);
9835 HMVMX_CHECK_BREAK(u64GuestCr4 & X86_CR4_PAE, VMX_IGS_CR4_PAE_LONGMODE);
9836 }
9837
9838 if ( !fLongModeGuest
9839 && (u64GuestCr4 & X86_CR4_PCIDE))
9840 HMVMX_ERROR_BREAK(VMX_IGS_CR4_PCIDE);
9841
9842 /** @todo CR3 field must be such that bits 63:52 and bits in the range
9843 * 51:32 beyond the processor's physical-address width are 0. */
9844
9845 if ( (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_DEBUG)
9846 && (pCtx->dr[7] & X86_DR7_MBZ_MASK))
9847 HMVMX_ERROR_BREAK(VMX_IGS_DR7_RESERVED);
9848
9849 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_ESP, &u64Val);
9850 AssertRC(rc);
9851 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_ESP_NOT_CANONICAL);
9852
9853 rc = VMXReadVmcsNw(VMX_VMCS_HOST_SYSENTER_EIP, &u64Val);
9854 AssertRC(rc);
9855 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_SYSENTER_EIP_NOT_CANONICAL);
9856
9857 /*
9858 * PERF_GLOBAL MSR.
9859 */
9860 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PERF_MSR)
9861 {
9862 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL, &u64Val);
9863 AssertRC(rc);
9864 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffff8fffffffc)),
9865 VMX_IGS_PERF_GLOBAL_MSR_RESERVED); /* Bits 63:35, bits 31:2 MBZ. */
9866 }
9867
9868 /*
9869 * PAT MSR.
9870 */
9871 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_PAT_MSR)
9872 {
9873 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PAT_FULL, &u64Val);
9874 AssertRC(rc);
9875 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
9876 for (unsigned i = 0; i < 8; i++)
9877 {
9878 uint8_t u8Val = (u64Val & 0xff);
9879 if ( u8Val != 0 /* UC */
9880 && u8Val != 1 /* WC */
9881 && u8Val != 4 /* WT */
9882 && u8Val != 5 /* WP */
9883 && u8Val != 6 /* WB */
9884 && u8Val != 7 /* UC- */)
9885 HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
9886 u64Val >>= 8;
9887 }
9888 }
9889
9890 /*
9891 * EFER MSR.
9892 */
9893 if (pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
9894 {
9895 Assert(g_fHmVmxSupportsVmcsEfer);
9896 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_EFER_FULL, &u64Val);
9897 AssertRC(rc);
9898 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xfffffffffffff2fe)),
9899 VMX_IGS_EFER_MSR_RESERVED); /* Bits 63:12, bit 9, bits 7:1 MBZ. */
9900 HMVMX_CHECK_BREAK(RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL( pVmcsInfo->u32EntryCtls
9901 & VMX_ENTRY_CTLS_IA32E_MODE_GUEST),
9902 VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH);
9903 /** @todo r=ramshankar: Unrestricted check here is probably wrong, see
9904 * iemVmxVmentryCheckGuestState(). */
9905 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9906 || !(u64GuestCr0 & X86_CR0_PG)
9907 || RT_BOOL(u64Val & MSR_K6_EFER_LMA) == RT_BOOL(u64Val & MSR_K6_EFER_LME),
9908 VMX_IGS_EFER_LMA_LME_MISMATCH);
9909 }
9910
9911 /*
9912 * Segment registers.
9913 */
9914 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
9915 || !(pCtx->ldtr.Sel & X86_SEL_LDT), VMX_IGS_LDTR_TI_INVALID);
9916 if (!(u32Eflags & X86_EFL_VM))
9917 {
9918 /* CS */
9919 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1Present, VMX_IGS_CS_ATTR_P_INVALID);
9920 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xf00), VMX_IGS_CS_ATTR_RESERVED);
9921 HMVMX_CHECK_BREAK(!(pCtx->cs.Attr.u & 0xfffe0000), VMX_IGS_CS_ATTR_RESERVED);
9922 HMVMX_CHECK_BREAK( (pCtx->cs.u32Limit & 0xfff) == 0xfff
9923 || !(pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9924 HMVMX_CHECK_BREAK( !(pCtx->cs.u32Limit & 0xfff00000)
9925 || (pCtx->cs.Attr.n.u1Granularity), VMX_IGS_CS_ATTR_G_INVALID);
9926 /* CS cannot be loaded with NULL in protected mode. */
9927 HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
9928 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u1DescType, VMX_IGS_CS_ATTR_S_INVALID);
9929 if (pCtx->cs.Attr.n.u4Type == 9 || pCtx->cs.Attr.n.u4Type == 11)
9930 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL);
9931 else if (pCtx->cs.Attr.n.u4Type == 13 || pCtx->cs.Attr.n.u4Type == 15)
9932 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl <= pCtx->ss.Attr.n.u2Dpl, VMX_IGS_CS_SS_ATTR_DPL_MISMATCH);
9933 else if (fUnrestrictedGuest && pCtx->cs.Attr.n.u4Type == 3)
9934 HMVMX_CHECK_BREAK(pCtx->cs.Attr.n.u2Dpl == 0, VMX_IGS_CS_ATTR_DPL_INVALID);
9935 else
9936 HMVMX_ERROR_BREAK(VMX_IGS_CS_ATTR_TYPE_INVALID);
9937
9938 /* SS */
9939 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9940 || (pCtx->ss.Sel & X86_SEL_RPL) == (pCtx->cs.Sel & X86_SEL_RPL), VMX_IGS_SS_CS_RPL_UNEQUAL);
9941 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
9942 if ( !(pCtx->cr0 & X86_CR0_PE)
9943 || pCtx->cs.Attr.n.u4Type == 3)
9944 HMVMX_CHECK_BREAK(!pCtx->ss.Attr.n.u2Dpl, VMX_IGS_SS_ATTR_DPL_INVALID);
9945
9946 if (!(pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE))
9947 {
9948 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
9949 HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u1Present, VMX_IGS_SS_ATTR_P_INVALID);
9950 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xf00), VMX_IGS_SS_ATTR_RESERVED);
9951 HMVMX_CHECK_BREAK(!(pCtx->ss.Attr.u & 0xfffe0000), VMX_IGS_SS_ATTR_RESERVED);
9952 HMVMX_CHECK_BREAK( (pCtx->ss.u32Limit & 0xfff) == 0xfff
9953 || !(pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9954 HMVMX_CHECK_BREAK( !(pCtx->ss.u32Limit & 0xfff00000)
9955 || (pCtx->ss.Attr.n.u1Granularity), VMX_IGS_SS_ATTR_G_INVALID);
9956 }
9957
9958 /* DS, ES, FS, GS - only check for usable selectors, see hmR0VmxExportGuestSReg(). */
9959 if (!(pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE))
9960 {
9961 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_DS_ATTR_A_INVALID);
9962 HMVMX_CHECK_BREAK(pCtx->ds.Attr.n.u1Present, VMX_IGS_DS_ATTR_P_INVALID);
9963 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9964 || pCtx->ds.Attr.n.u4Type > 11
9965 || pCtx->ds.Attr.n.u2Dpl >= (pCtx->ds.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9966 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xf00), VMX_IGS_DS_ATTR_RESERVED);
9967 HMVMX_CHECK_BREAK(!(pCtx->ds.Attr.u & 0xfffe0000), VMX_IGS_DS_ATTR_RESERVED);
9968 HMVMX_CHECK_BREAK( (pCtx->ds.u32Limit & 0xfff) == 0xfff
9969 || !(pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9970 HMVMX_CHECK_BREAK( !(pCtx->ds.u32Limit & 0xfff00000)
9971 || (pCtx->ds.Attr.n.u1Granularity), VMX_IGS_DS_ATTR_G_INVALID);
9972 HMVMX_CHECK_BREAK( !(pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9973 || (pCtx->ds.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_DS_ATTR_TYPE_INVALID);
9974 }
9975 if (!(pCtx->es.Attr.u & X86DESCATTR_UNUSABLE))
9976 {
9977 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_ES_ATTR_A_INVALID);
9978 HMVMX_CHECK_BREAK(pCtx->es.Attr.n.u1Present, VMX_IGS_ES_ATTR_P_INVALID);
9979 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9980 || pCtx->es.Attr.n.u4Type > 11
9981 || pCtx->es.Attr.n.u2Dpl >= (pCtx->es.Sel & X86_SEL_RPL), VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL);
9982 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xf00), VMX_IGS_ES_ATTR_RESERVED);
9983 HMVMX_CHECK_BREAK(!(pCtx->es.Attr.u & 0xfffe0000), VMX_IGS_ES_ATTR_RESERVED);
9984 HMVMX_CHECK_BREAK( (pCtx->es.u32Limit & 0xfff) == 0xfff
9985 || !(pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9986 HMVMX_CHECK_BREAK( !(pCtx->es.u32Limit & 0xfff00000)
9987 || (pCtx->es.Attr.n.u1Granularity), VMX_IGS_ES_ATTR_G_INVALID);
9988 HMVMX_CHECK_BREAK( !(pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_CODE)
9989 || (pCtx->es.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_ES_ATTR_TYPE_INVALID);
9990 }
9991 if (!(pCtx->fs.Attr.u & X86DESCATTR_UNUSABLE))
9992 {
9993 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_FS_ATTR_A_INVALID);
9994 HMVMX_CHECK_BREAK(pCtx->fs.Attr.n.u1Present, VMX_IGS_FS_ATTR_P_INVALID);
9995 HMVMX_CHECK_BREAK( fUnrestrictedGuest
9996 || pCtx->fs.Attr.n.u4Type > 11
9997 || pCtx->fs.Attr.n.u2Dpl >= (pCtx->fs.Sel & X86_SEL_RPL), VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL);
9998 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xf00), VMX_IGS_FS_ATTR_RESERVED);
9999 HMVMX_CHECK_BREAK(!(pCtx->fs.Attr.u & 0xfffe0000), VMX_IGS_FS_ATTR_RESERVED);
10000 HMVMX_CHECK_BREAK( (pCtx->fs.u32Limit & 0xfff) == 0xfff
10001 || !(pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
10002 HMVMX_CHECK_BREAK( !(pCtx->fs.u32Limit & 0xfff00000)
10003 || (pCtx->fs.Attr.n.u1Granularity), VMX_IGS_FS_ATTR_G_INVALID);
10004 HMVMX_CHECK_BREAK( !(pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10005 || (pCtx->fs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_FS_ATTR_TYPE_INVALID);
10006 }
10007 if (!(pCtx->gs.Attr.u & X86DESCATTR_UNUSABLE))
10008 {
10009 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_ACCESSED, VMX_IGS_GS_ATTR_A_INVALID);
10010 HMVMX_CHECK_BREAK(pCtx->gs.Attr.n.u1Present, VMX_IGS_GS_ATTR_P_INVALID);
10011 HMVMX_CHECK_BREAK( fUnrestrictedGuest
10012 || pCtx->gs.Attr.n.u4Type > 11
10013 || pCtx->gs.Attr.n.u2Dpl >= (pCtx->gs.Sel & X86_SEL_RPL), VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL);
10014 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xf00), VMX_IGS_GS_ATTR_RESERVED);
10015 HMVMX_CHECK_BREAK(!(pCtx->gs.Attr.u & 0xfffe0000), VMX_IGS_GS_ATTR_RESERVED);
10016 HMVMX_CHECK_BREAK( (pCtx->gs.u32Limit & 0xfff) == 0xfff
10017 || !(pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10018 HMVMX_CHECK_BREAK( !(pCtx->gs.u32Limit & 0xfff00000)
10019 || (pCtx->gs.Attr.n.u1Granularity), VMX_IGS_GS_ATTR_G_INVALID);
10020 HMVMX_CHECK_BREAK( !(pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_CODE)
10021 || (pCtx->gs.Attr.n.u4Type & X86_SEL_TYPE_READ), VMX_IGS_GS_ATTR_TYPE_INVALID);
10022 }
10023 /* 64-bit capable CPUs. */
10024 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10025 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10026 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10027 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10028 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10029 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
10030 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10031 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
10032 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10033 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
10034 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10035 }
10036 else
10037 {
10038 /* V86 mode checks. */
10039 uint32_t u32CSAttr, u32SSAttr, u32DSAttr, u32ESAttr, u32FSAttr, u32GSAttr;
10040 if (pVmcsInfo->pShared->RealMode.fRealOnV86Active)
10041 {
10042 u32CSAttr = 0xf3; u32SSAttr = 0xf3;
10043 u32DSAttr = 0xf3; u32ESAttr = 0xf3;
10044 u32FSAttr = 0xf3; u32GSAttr = 0xf3;
10045 }
10046 else
10047 {
10048 u32CSAttr = pCtx->cs.Attr.u; u32SSAttr = pCtx->ss.Attr.u;
10049 u32DSAttr = pCtx->ds.Attr.u; u32ESAttr = pCtx->es.Attr.u;
10050 u32FSAttr = pCtx->fs.Attr.u; u32GSAttr = pCtx->gs.Attr.u;
10051 }
10052
10053 /* CS */
10054 HMVMX_CHECK_BREAK((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), VMX_IGS_V86_CS_BASE_INVALID);
10055 HMVMX_CHECK_BREAK(pCtx->cs.u32Limit == 0xffff, VMX_IGS_V86_CS_LIMIT_INVALID);
10056 HMVMX_CHECK_BREAK(u32CSAttr == 0xf3, VMX_IGS_V86_CS_ATTR_INVALID);
10057 /* SS */
10058 HMVMX_CHECK_BREAK((pCtx->ss.u64Base == (uint64_t)pCtx->ss.Sel << 4), VMX_IGS_V86_SS_BASE_INVALID);
10059 HMVMX_CHECK_BREAK(pCtx->ss.u32Limit == 0xffff, VMX_IGS_V86_SS_LIMIT_INVALID);
10060 HMVMX_CHECK_BREAK(u32SSAttr == 0xf3, VMX_IGS_V86_SS_ATTR_INVALID);
10061 /* DS */
10062 HMVMX_CHECK_BREAK((pCtx->ds.u64Base == (uint64_t)pCtx->ds.Sel << 4), VMX_IGS_V86_DS_BASE_INVALID);
10063 HMVMX_CHECK_BREAK(pCtx->ds.u32Limit == 0xffff, VMX_IGS_V86_DS_LIMIT_INVALID);
10064 HMVMX_CHECK_BREAK(u32DSAttr == 0xf3, VMX_IGS_V86_DS_ATTR_INVALID);
10065 /* ES */
10066 HMVMX_CHECK_BREAK((pCtx->es.u64Base == (uint64_t)pCtx->es.Sel << 4), VMX_IGS_V86_ES_BASE_INVALID);
10067 HMVMX_CHECK_BREAK(pCtx->es.u32Limit == 0xffff, VMX_IGS_V86_ES_LIMIT_INVALID);
10068 HMVMX_CHECK_BREAK(u32ESAttr == 0xf3, VMX_IGS_V86_ES_ATTR_INVALID);
10069 /* FS */
10070 HMVMX_CHECK_BREAK((pCtx->fs.u64Base == (uint64_t)pCtx->fs.Sel << 4), VMX_IGS_V86_FS_BASE_INVALID);
10071 HMVMX_CHECK_BREAK(pCtx->fs.u32Limit == 0xffff, VMX_IGS_V86_FS_LIMIT_INVALID);
10072 HMVMX_CHECK_BREAK(u32FSAttr == 0xf3, VMX_IGS_V86_FS_ATTR_INVALID);
10073 /* GS */
10074 HMVMX_CHECK_BREAK((pCtx->gs.u64Base == (uint64_t)pCtx->gs.Sel << 4), VMX_IGS_V86_GS_BASE_INVALID);
10075 HMVMX_CHECK_BREAK(pCtx->gs.u32Limit == 0xffff, VMX_IGS_V86_GS_LIMIT_INVALID);
10076 HMVMX_CHECK_BREAK(u32GSAttr == 0xf3, VMX_IGS_V86_GS_ATTR_INVALID);
10077 /* 64-bit capable CPUs. */
10078 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->fs.u64Base), VMX_IGS_FS_BASE_NOT_CANONICAL);
10079 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->gs.u64Base), VMX_IGS_GS_BASE_NOT_CANONICAL);
10080 HMVMX_CHECK_BREAK( (pCtx->ldtr.Attr.u & X86DESCATTR_UNUSABLE)
10081 || X86_IS_CANONICAL(pCtx->ldtr.u64Base), VMX_IGS_LDTR_BASE_NOT_CANONICAL);
10082 HMVMX_CHECK_BREAK(!RT_HI_U32(pCtx->cs.u64Base), VMX_IGS_LONGMODE_CS_BASE_INVALID);
10083 HMVMX_CHECK_BREAK((pCtx->ss.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ss.u64Base),
10084 VMX_IGS_LONGMODE_SS_BASE_INVALID);
10085 HMVMX_CHECK_BREAK((pCtx->ds.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->ds.u64Base),
10086 VMX_IGS_LONGMODE_DS_BASE_INVALID);
10087 HMVMX_CHECK_BREAK((pCtx->es.Attr.u & X86DESCATTR_UNUSABLE) || !RT_HI_U32(pCtx->es.u64Base),
10088 VMX_IGS_LONGMODE_ES_BASE_INVALID);
10089 }
10090
10091 /*
10092 * TR.
10093 */
10094 HMVMX_CHECK_BREAK(!(pCtx->tr.Sel & X86_SEL_LDT), VMX_IGS_TR_TI_INVALID);
10095 /* 64-bit capable CPUs. */
10096 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(pCtx->tr.u64Base), VMX_IGS_TR_BASE_NOT_CANONICAL);
10097 if (fLongModeGuest)
10098 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u4Type == 11, /* 64-bit busy TSS. */
10099 VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID);
10100 else
10101 HMVMX_CHECK_BREAK( pCtx->tr.Attr.n.u4Type == 3 /* 16-bit busy TSS. */
10102 || pCtx->tr.Attr.n.u4Type == 11, /* 32-bit busy TSS.*/
10103 VMX_IGS_TR_ATTR_TYPE_INVALID);
10104 HMVMX_CHECK_BREAK(!pCtx->tr.Attr.n.u1DescType, VMX_IGS_TR_ATTR_S_INVALID);
10105 HMVMX_CHECK_BREAK(pCtx->tr.Attr.n.u1Present, VMX_IGS_TR_ATTR_P_INVALID);
10106 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & 0xf00), VMX_IGS_TR_ATTR_RESERVED); /* Bits 11:8 MBZ. */
10107 HMVMX_CHECK_BREAK( (pCtx->tr.u32Limit & 0xfff) == 0xfff
10108 || !(pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
10109 HMVMX_CHECK_BREAK( !(pCtx->tr.u32Limit & 0xfff00000)
10110 || (pCtx->tr.Attr.n.u1Granularity), VMX_IGS_TR_ATTR_G_INVALID);
10111 HMVMX_CHECK_BREAK(!(pCtx->tr.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_TR_ATTR_UNUSABLE);
10112
10113 /*
10114 * GDTR and IDTR (64-bit capable checks).
10115 */
10116 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_GDTR_BASE, &u64Val);
10117 AssertRC(rc);
10118 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_GDTR_BASE_NOT_CANONICAL);
10119
10120 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_IDTR_BASE, &u64Val);
10121 AssertRC(rc);
10122 HMVMX_CHECK_BREAK(X86_IS_CANONICAL(u64Val), VMX_IGS_IDTR_BASE_NOT_CANONICAL);
10123
10124 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_GDTR_LIMIT, &u32Val);
10125 AssertRC(rc);
10126 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_GDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
10127
10128 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_IDTR_LIMIT, &u32Val);
10129 AssertRC(rc);
10130 HMVMX_CHECK_BREAK(!(u32Val & 0xffff0000), VMX_IGS_IDTR_LIMIT_INVALID); /* Bits 31:16 MBZ. */
10131
10132 /*
10133 * Guest Non-Register State.
10134 */
10135 /* Activity State. */
10136 uint32_t u32ActivityState;
10137 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_ACTIVITY_STATE, &u32ActivityState);
10138 AssertRC(rc);
10139 HMVMX_CHECK_BREAK( !u32ActivityState
10140 || (u32ActivityState & RT_BF_GET(g_HmMsrs.u.vmx.u64Misc, VMX_BF_MISC_ACTIVITY_STATES)),
10141 VMX_IGS_ACTIVITY_STATE_INVALID);
10142 HMVMX_CHECK_BREAK( !(pCtx->ss.Attr.n.u2Dpl)
10143 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_HLT, VMX_IGS_ACTIVITY_STATE_HLT_INVALID);
10144
10145 if ( u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS
10146 || u32IntrState == VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10147 HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
10148
10149 /** @todo Activity state and injecting interrupts. Left as a todo since we
10150 * currently don't use activity states but ACTIVE. */
10151
10152 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
10153 || u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
10154
10155 /* Guest interruptibility-state. */
10156 HMVMX_CHECK_BREAK(!(u32IntrState & 0xffffffe0), VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED);
10157 HMVMX_CHECK_BREAK((u32IntrState & (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS))
10158 != (VMX_VMCS_GUEST_INT_STATE_BLOCK_STI | VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10159 VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID);
10160 HMVMX_CHECK_BREAK( (u32Eflags & X86_EFL_IF)
10161 || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
10162 VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
10163 if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
10164 {
10165 HMVMX_CHECK_BREAK( !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10166 && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10167 VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
10168 }
10169 else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
10170 {
10171 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
10172 VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
10173 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
10174 VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
10175 }
10176 /** @todo Assumes the processor is not in SMM. */
10177 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
10178 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID);
10179 HMVMX_CHECK_BREAK( !(pVmcsInfo->u32EntryCtls & VMX_ENTRY_CTLS_ENTRY_TO_SMM)
10180 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI),
10181 VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
10182 if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
10183 && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
10184 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI), VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID);
10185
10186 /* Pending debug exceptions. */
10187 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, &u64Val);
10188 AssertRC(rc);
10189 /* Bits 63:15, Bit 13, Bits 11:4 MBZ. */
10190 HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
10191 u32Val = u64Val; /* For pending debug exceptions checks below. */
10192
10193 if ( (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
10194 || (u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS)
10195 || u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_HLT)
10196 {
10197 if ( (u32Eflags & X86_EFL_TF)
10198 && !(u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
10199 {
10200 /* Bit 14 is PendingDebug.BS. */
10201 HMVMX_CHECK_BREAK(u32Val & RT_BIT(14), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET);
10202 }
10203 if ( !(u32Eflags & X86_EFL_TF)
10204 || (u64DebugCtlMsr & RT_BIT_64(1))) /* Bit 1 is IA32_DEBUGCTL.BTF. */
10205 {
10206 /* Bit 14 is PendingDebug.BS. */
10207 HMVMX_CHECK_BREAK(!(u32Val & RT_BIT(14)), VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR);
10208 }
10209 }
10210
10211 /* VMCS link pointer. */
10212 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, &u64Val);
10213 AssertRC(rc);
10214 if (u64Val != UINT64_C(0xffffffffffffffff))
10215 {
10216 HMVMX_CHECK_BREAK(!(u64Val & 0xfff), VMX_IGS_VMCS_LINK_PTR_RESERVED);
10217 /** @todo Bits beyond the processor's physical-address width MBZ. */
10218 /** @todo SMM checks. */
10219 Assert(pVmcsInfo->HCPhysShadowVmcs == u64Val);
10220 Assert(pVmcsInfo->pvShadowVmcs);
10221 VMXVMCSREVID VmcsRevId;
10222 VmcsRevId.u = *(uint32_t *)pVmcsInfo->pvShadowVmcs;
10223 HMVMX_CHECK_BREAK(VmcsRevId.n.u31RevisionId == RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_ID),
10224 VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID);
10225 HMVMX_CHECK_BREAK(VmcsRevId.n.fIsShadowVmcs == (uint32_t)!!(pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING),
10226 VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW);
10227 }
10228
10229 /** @todo Checks on Guest Page-Directory-Pointer-Table Entries when guest is
10230 * not using nested paging? */
10231 if ( pVM->hmr0.s.fNestedPaging
10232 && !fLongModeGuest
10233 && CPUMIsGuestInPAEModeEx(pCtx))
10234 {
10235 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE0_FULL, &u64Val);
10236 AssertRC(rc);
10237 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10238
10239 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE1_FULL, &u64Val);
10240 AssertRC(rc);
10241 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10242
10243 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE2_FULL, &u64Val);
10244 AssertRC(rc);
10245 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10246
10247 rc = VMXReadVmcs64(VMX_VMCS64_GUEST_PDPTE3_FULL, &u64Val);
10248 AssertRC(rc);
10249 HMVMX_CHECK_BREAK(!(u64Val & X86_PDPE_PAE_MBZ_MASK), VMX_IGS_PAE_PDPTE_RESERVED);
10250 }
10251
10252 /* Shouldn't happen but distinguish it from AssertRCBreak() errors. */
10253 if (uError == VMX_IGS_ERROR)
10254 uError = VMX_IGS_REASON_NOT_FOUND;
10255 } while (0);
10256
10257 pVCpu->hm.s.u32HMError = uError;
10258 pVCpu->hm.s.vmx.LastError.u32GuestIntrState = u32IntrState;
10259 return uError;
10260
10261#undef HMVMX_ERROR_BREAK
10262#undef HMVMX_CHECK_BREAK
10263}
10264
10265
10266/**
10267 * Map the APIC-access page for virtualizing APIC accesses.
10268 *
10269 * This can cause a longjumps to R3 due to the acquisition of the PGM lock. Hence,
10270 * this not done as part of exporting guest state, see @bugref{8721}.
10271 *
10272 * @returns VBox status code.
10273 * @param pVCpu The cross context virtual CPU structure.
10274 */
10275static int hmR0VmxMapHCApicAccessPage(PVMCPUCC pVCpu)
10276{
10277 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10278 uint64_t const u64MsrApicBase = APICGetBaseMsrNoCheck(pVCpu);
10279
10280 Assert(PDMHasApic(pVM));
10281 Assert(u64MsrApicBase);
10282
10283 RTGCPHYS const GCPhysApicBase = u64MsrApicBase & PAGE_BASE_GC_MASK;
10284 Log4Func(("Mappping HC APIC-access page at %#RGp\n", GCPhysApicBase));
10285
10286 /* Unalias the existing mapping. */
10287 int rc = PGMHandlerPhysicalReset(pVM, GCPhysApicBase);
10288 AssertRCReturn(rc, rc);
10289
10290 /* Map the HC APIC-access page in place of the MMIO page, also updates the shadow page tables if necessary. */
10291 Assert(pVM->hmr0.s.vmx.HCPhysApicAccess != NIL_RTHCPHYS);
10292 rc = IOMR0MmioMapMmioHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hmr0.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
10293 AssertRCReturn(rc, rc);
10294
10295 /* Update the per-VCPU cache of the APIC base MSR. */
10296 pVCpu->hm.s.vmx.u64GstMsrApicBase = u64MsrApicBase;
10297 return VINF_SUCCESS;
10298}
10299
10300
10301/**
10302 * Worker function passed to RTMpOnSpecific() that is to be called on the target
10303 * CPU.
10304 *
10305 * @param idCpu The ID for the CPU the function is called on.
10306 * @param pvUser1 Null, not used.
10307 * @param pvUser2 Null, not used.
10308 */
10309static DECLCALLBACK(void) hmR0DispatchHostNmi(RTCPUID idCpu, void *pvUser1, void *pvUser2)
10310{
10311 RT_NOREF3(idCpu, pvUser1, pvUser2);
10312 VMXDispatchHostNmi();
10313}
10314
10315
10316/**
10317 * Dispatching an NMI on the host CPU that received it.
10318 *
10319 * @returns VBox status code.
10320 * @param pVCpu The cross context virtual CPU structure.
10321 * @param pVmcsInfo The VMCS info. object corresponding to the VMCS that was
10322 * executing when receiving the host NMI in VMX non-root
10323 * operation.
10324 */
10325static int hmR0VmxExitHostNmi(PVMCPUCC pVCpu, PCVMXVMCSINFO pVmcsInfo)
10326{
10327 RTCPUID const idCpu = pVmcsInfo->idHostCpuExec;
10328 Assert(idCpu != NIL_RTCPUID);
10329
10330 /*
10331 * We don't want to delay dispatching the NMI any more than we have to. However,
10332 * we have already chosen -not- to dispatch NMIs when interrupts were still disabled
10333 * after executing guest or nested-guest code for the following reasons:
10334 *
10335 * - We would need to perform VMREADs with interrupts disabled and is orders of
10336 * magnitude worse when we run as a nested hypervisor without VMCS shadowing
10337 * supported by the host hypervisor.
10338 *
10339 * - It affects the common VM-exit scenario and keeps interrupts disabled for a
10340 * longer period of time just for handling an edge case like host NMIs which do
10341 * not occur nearly as frequently as other VM-exits.
10342 *
10343 * Let's cover the most likely scenario first. Check if we are on the target CPU
10344 * and dispatch the NMI right away. This should be much faster than calling into
10345 * RTMpOnSpecific() machinery.
10346 */
10347 bool fDispatched = false;
10348 RTCCUINTREG const fEFlags = ASMIntDisableFlags();
10349 if (idCpu == RTMpCpuId())
10350 {
10351 VMXDispatchHostNmi();
10352 fDispatched = true;
10353 }
10354 ASMSetFlags(fEFlags);
10355 if (fDispatched)
10356 {
10357 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
10358 return VINF_SUCCESS;
10359 }
10360
10361 /*
10362 * RTMpOnSpecific() waits until the worker function has run on the target CPU. So
10363 * there should be no race or recursion even if we are unlucky enough to be preempted
10364 * (to the target CPU) without dispatching the host NMI above.
10365 */
10366 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGCIpi);
10367 return RTMpOnSpecific(idCpu, &hmR0DispatchHostNmi, NULL /* pvUser1 */, NULL /* pvUser2 */);
10368}
10369
10370
10371#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10372/**
10373 * Merges the guest with the nested-guest MSR bitmap in preparation of executing the
10374 * nested-guest using hardware-assisted VMX.
10375 *
10376 * @param pVCpu The cross context virtual CPU structure.
10377 * @param pVmcsInfoNstGst The nested-guest VMCS info. object.
10378 * @param pVmcsInfoGst The guest VMCS info. object.
10379 */
10380static void hmR0VmxMergeMsrBitmapNested(PCVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfoNstGst, PCVMXVMCSINFO pVmcsInfoGst)
10381{
10382 uint32_t const cbMsrBitmap = X86_PAGE_4K_SIZE;
10383 uint64_t *pu64MsrBitmap = (uint64_t *)pVmcsInfoNstGst->pvMsrBitmap;
10384 Assert(pu64MsrBitmap);
10385
10386 /*
10387 * We merge the guest MSR bitmap with the nested-guest MSR bitmap such that any
10388 * MSR that is intercepted by the guest is also intercepted while executing the
10389 * nested-guest using hardware-assisted VMX.
10390 *
10391 * Note! If the nested-guest is not using an MSR bitmap, every MSR must cause a
10392 * nested-guest VM-exit even if the outer guest is not intercepting some
10393 * MSRs. We cannot assume the caller has initialized the nested-guest
10394 * MSR bitmap in this case.
10395 *
10396 * The nested hypervisor may also switch whether it uses MSR bitmaps for
10397 * each of its VM-entry, hence initializing it once per-VM while setting
10398 * up the nested-guest VMCS is not sufficient.
10399 */
10400 PCVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
10401 if (pVmcsNstGst->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10402 {
10403 uint64_t const *pu64MsrBitmapNstGst = (uint64_t const *)&pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap[0];
10404 uint64_t const *pu64MsrBitmapGst = (uint64_t const *)pVmcsInfoGst->pvMsrBitmap;
10405 Assert(pu64MsrBitmapNstGst);
10406 Assert(pu64MsrBitmapGst);
10407
10408 /** @todo Detect and use EVEX.POR? */
10409 uint32_t const cFrags = cbMsrBitmap / sizeof(uint64_t);
10410 for (uint32_t i = 0; i < cFrags; i++)
10411 pu64MsrBitmap[i] = pu64MsrBitmapNstGst[i] | pu64MsrBitmapGst[i];
10412 }
10413 else
10414 ASMMemFill32(pu64MsrBitmap, cbMsrBitmap, UINT32_C(0xffffffff));
10415}
10416
10417
10418/**
10419 * Merges the guest VMCS in to the nested-guest VMCS controls in preparation of
10420 * hardware-assisted VMX execution of the nested-guest.
10421 *
10422 * For a guest, we don't modify these controls once we set up the VMCS and hence
10423 * this function is never called.
10424 *
10425 * For nested-guests since the nested hypervisor provides these controls on every
10426 * nested-guest VM-entry and could potentially change them everytime we need to
10427 * merge them before every nested-guest VM-entry.
10428 *
10429 * @returns VBox status code.
10430 * @param pVCpu The cross context virtual CPU structure.
10431 */
10432static int hmR0VmxMergeVmcsNested(PVMCPUCC pVCpu)
10433{
10434 PVMCC const pVM = pVCpu->CTX_SUFF(pVM);
10435 PCVMXVMCSINFO const pVmcsInfoGst = &pVCpu->hmr0.s.vmx.VmcsInfo;
10436 PCVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
10437
10438 /*
10439 * Merge the controls with the requirements of the guest VMCS.
10440 *
10441 * We do not need to validate the nested-guest VMX features specified in the nested-guest
10442 * VMCS with the features supported by the physical CPU as it's already done by the
10443 * VMLAUNCH/VMRESUME instruction emulation.
10444 *
10445 * This is because the VMX features exposed by CPUM (through CPUID/MSRs) to the guest are
10446 * derived from the VMX features supported by the physical CPU.
10447 */
10448
10449 /* Pin-based VM-execution controls. */
10450 uint32_t const u32PinCtls = pVmcsNstGst->u32PinCtls | pVmcsInfoGst->u32PinCtls;
10451
10452 /* Processor-based VM-execution controls. */
10453 uint32_t u32ProcCtls = (pVmcsNstGst->u32ProcCtls & ~VMX_PROC_CTLS_USE_IO_BITMAPS)
10454 | (pVmcsInfoGst->u32ProcCtls & ~( VMX_PROC_CTLS_INT_WINDOW_EXIT
10455 | VMX_PROC_CTLS_NMI_WINDOW_EXIT
10456 | VMX_PROC_CTLS_MOV_DR_EXIT
10457 | VMX_PROC_CTLS_USE_TPR_SHADOW
10458 | VMX_PROC_CTLS_MONITOR_TRAP_FLAG));
10459
10460 /* Secondary processor-based VM-execution controls. */
10461 uint32_t const u32ProcCtls2 = (pVmcsNstGst->u32ProcCtls2 & ~VMX_PROC_CTLS2_VPID)
10462 | (pVmcsInfoGst->u32ProcCtls2 & ~( VMX_PROC_CTLS2_VIRT_APIC_ACCESS
10463 | VMX_PROC_CTLS2_INVPCID
10464 | VMX_PROC_CTLS2_VMCS_SHADOWING
10465 | VMX_PROC_CTLS2_RDTSCP
10466 | VMX_PROC_CTLS2_XSAVES_XRSTORS
10467 | VMX_PROC_CTLS2_APIC_REG_VIRT
10468 | VMX_PROC_CTLS2_VIRT_INT_DELIVERY
10469 | VMX_PROC_CTLS2_VMFUNC));
10470
10471 /*
10472 * VM-entry controls:
10473 * These controls contains state that depends on the nested-guest state (primarily
10474 * EFER MSR) and is thus not constant between VMLAUNCH/VMRESUME and the nested-guest
10475 * VM-exit. Although the nested hypervisor cannot change it, we need to in order to
10476 * properly continue executing the nested-guest if the EFER MSR changes but does not
10477 * cause a nested-guest VM-exits.
10478 *
10479 * VM-exit controls:
10480 * These controls specify the host state on return. We cannot use the controls from
10481 * the nested hypervisor state as is as it would contain the guest state rather than
10482 * the host state. Since the host state is subject to change (e.g. preemption, trips
10483 * to ring-3, longjmp and rescheduling to a different host CPU) they are not constant
10484 * through VMLAUNCH/VMRESUME and the nested-guest VM-exit.
10485 *
10486 * VM-entry MSR-load:
10487 * The guest MSRs from the VM-entry MSR-load area are already loaded into the guest-CPU
10488 * context by the VMLAUNCH/VMRESUME instruction emulation.
10489 *
10490 * VM-exit MSR-store:
10491 * The VM-exit emulation will take care of populating the MSRs from the guest-CPU context
10492 * back into the VM-exit MSR-store area.
10493 *
10494 * VM-exit MSR-load areas:
10495 * This must contain the real host MSRs with hardware-assisted VMX execution. Hence, we
10496 * can entirely ignore what the nested hypervisor wants to load here.
10497 */
10498
10499 /*
10500 * Exception bitmap.
10501 *
10502 * We could remove #UD from the guest bitmap and merge it with the nested-guest bitmap
10503 * here (and avoid doing anything while exporting nested-guest state), but to keep the
10504 * code more flexible if intercepting exceptions become more dynamic in the future we do
10505 * it as part of exporting the nested-guest state.
10506 */
10507 uint32_t const u32XcptBitmap = pVmcsNstGst->u32XcptBitmap | pVmcsInfoGst->u32XcptBitmap;
10508
10509 /*
10510 * CR0/CR4 guest/host mask.
10511 *
10512 * Modifications by the nested-guest to CR0/CR4 bits owned by the host and the guest must
10513 * cause VM-exits, so we need to merge them here.
10514 */
10515 uint64_t const u64Cr0Mask = pVmcsNstGst->u64Cr0Mask.u | pVmcsInfoGst->u64Cr0Mask;
10516 uint64_t const u64Cr4Mask = pVmcsNstGst->u64Cr4Mask.u | pVmcsInfoGst->u64Cr4Mask;
10517
10518 /*
10519 * Page-fault error-code mask and match.
10520 *
10521 * Although we require unrestricted guest execution (and thereby nested-paging) for
10522 * hardware-assisted VMX execution of nested-guests and thus the outer guest doesn't
10523 * normally intercept #PFs, it might intercept them for debugging purposes.
10524 *
10525 * If the outer guest is not intercepting #PFs, we can use the nested-guest #PF filters.
10526 * If the outer guest is intercepting #PFs, we must intercept all #PFs.
10527 */
10528 uint32_t u32XcptPFMask;
10529 uint32_t u32XcptPFMatch;
10530 if (!(pVmcsInfoGst->u32XcptBitmap & RT_BIT(X86_XCPT_PF)))
10531 {
10532 u32XcptPFMask = pVmcsNstGst->u32XcptPFMask;
10533 u32XcptPFMatch = pVmcsNstGst->u32XcptPFMatch;
10534 }
10535 else
10536 {
10537 u32XcptPFMask = 0;
10538 u32XcptPFMatch = 0;
10539 }
10540
10541 /*
10542 * Pause-Loop exiting.
10543 */
10544 /** @todo r=bird: given that both pVM->hm.s.vmx.cPleGapTicks and
10545 * pVM->hm.s.vmx.cPleWindowTicks defaults to zero, I cannot see how
10546 * this will work... */
10547 uint32_t const cPleGapTicks = RT_MIN(pVM->hm.s.vmx.cPleGapTicks, pVmcsNstGst->u32PleGap);
10548 uint32_t const cPleWindowTicks = RT_MIN(pVM->hm.s.vmx.cPleWindowTicks, pVmcsNstGst->u32PleWindow);
10549
10550 /*
10551 * Pending debug exceptions.
10552 * Currently just copy whatever the nested-guest provides us.
10553 */
10554 uint64_t const uPendingDbgXcpts = pVmcsNstGst->u64GuestPendingDbgXcpts.u;
10555
10556 /*
10557 * I/O Bitmap.
10558 *
10559 * We do not use the I/O bitmap that may be provided by the nested hypervisor as we always
10560 * intercept all I/O port accesses.
10561 */
10562 Assert(u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT);
10563 Assert(!(u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS));
10564
10565 /*
10566 * VMCS shadowing.
10567 *
10568 * We do not yet expose VMCS shadowing to the guest and thus VMCS shadowing should not be
10569 * enabled while executing the nested-guest.
10570 */
10571 Assert(!(u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING));
10572
10573 /*
10574 * APIC-access page.
10575 */
10576 RTHCPHYS HCPhysApicAccess;
10577 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10578 {
10579 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
10580 RTGCPHYS const GCPhysApicAccess = pVmcsNstGst->u64AddrApicAccess.u;
10581
10582 /** @todo NSTVMX: This is not really correct but currently is required to make
10583 * things work. We need to re-enable the page handler when we fallback to
10584 * IEM execution of the nested-guest! */
10585 PGMHandlerPhysicalPageTempOff(pVM, GCPhysApicAccess, GCPhysApicAccess);
10586
10587 void *pvPage;
10588 PGMPAGEMAPLOCK PgLockApicAccess;
10589 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysApicAccess, &pvPage, &PgLockApicAccess);
10590 if (RT_SUCCESS(rc))
10591 {
10592 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysApicAccess, &HCPhysApicAccess);
10593 AssertMsgRCReturn(rc, ("Failed to get host-physical address for APIC-access page at %#RGp\n", GCPhysApicAccess), rc);
10594
10595 /** @todo Handle proper releasing of page-mapping lock later. */
10596 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockApicAccess);
10597 }
10598 else
10599 return rc;
10600 }
10601 else
10602 HCPhysApicAccess = 0;
10603
10604 /*
10605 * Virtual-APIC page and TPR threshold.
10606 */
10607 RTHCPHYS HCPhysVirtApic;
10608 uint32_t u32TprThreshold;
10609 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10610 {
10611 Assert(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW);
10612 RTGCPHYS const GCPhysVirtApic = pVmcsNstGst->u64AddrVirtApic.u;
10613
10614 void *pvPage;
10615 PGMPAGEMAPLOCK PgLockVirtApic;
10616 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysVirtApic, &pvPage, &PgLockVirtApic);
10617 if (RT_SUCCESS(rc))
10618 {
10619 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysVirtApic, &HCPhysVirtApic);
10620 AssertMsgRCReturn(rc, ("Failed to get host-physical address for virtual-APIC page at %#RGp\n", GCPhysVirtApic), rc);
10621
10622 /** @todo Handle proper releasing of page-mapping lock later. */
10623 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), &PgLockVirtApic);
10624 }
10625 else
10626 return rc;
10627
10628 u32TprThreshold = pVmcsNstGst->u32TprThreshold;
10629 }
10630 else
10631 {
10632 HCPhysVirtApic = 0;
10633 u32TprThreshold = 0;
10634
10635 /*
10636 * We must make sure CR8 reads/write must cause VM-exits when TPR shadowing is not
10637 * used by the nested hypervisor. Preventing MMIO accesses to the physical APIC will
10638 * be taken care of by EPT/shadow paging.
10639 */
10640 if (pVM->hmr0.s.fAllow64BitGuests)
10641 u32ProcCtls |= VMX_PROC_CTLS_CR8_STORE_EXIT
10642 | VMX_PROC_CTLS_CR8_LOAD_EXIT;
10643 }
10644
10645 /*
10646 * Validate basic assumptions.
10647 */
10648 PVMXVMCSINFO pVmcsInfoNstGst = &pVCpu->hmr0.s.vmx.VmcsInfoNstGst;
10649 Assert(pVM->hmr0.s.vmx.fUnrestrictedGuest);
10650 Assert(g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS);
10651 Assert(hmGetVmxActiveVmcsInfo(pVCpu) == pVmcsInfoNstGst);
10652
10653 /*
10654 * Commit it to the nested-guest VMCS.
10655 */
10656 int rc = VINF_SUCCESS;
10657 if (pVmcsInfoNstGst->u32PinCtls != u32PinCtls)
10658 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PIN_EXEC, u32PinCtls);
10659 if (pVmcsInfoNstGst->u32ProcCtls != u32ProcCtls)
10660 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, u32ProcCtls);
10661 if (pVmcsInfoNstGst->u32ProcCtls2 != u32ProcCtls2)
10662 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, u32ProcCtls2);
10663 if (pVmcsInfoNstGst->u32XcptBitmap != u32XcptBitmap)
10664 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, u32XcptBitmap);
10665 if (pVmcsInfoNstGst->u64Cr0Mask != u64Cr0Mask)
10666 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, u64Cr0Mask);
10667 if (pVmcsInfoNstGst->u64Cr4Mask != u64Cr4Mask)
10668 rc |= VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, u64Cr4Mask);
10669 if (pVmcsInfoNstGst->u32XcptPFMask != u32XcptPFMask)
10670 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK, u32XcptPFMask);
10671 if (pVmcsInfoNstGst->u32XcptPFMatch != u32XcptPFMatch)
10672 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH, u32XcptPFMatch);
10673 if ( !(u32ProcCtls & VMX_PROC_CTLS_PAUSE_EXIT)
10674 && (u32ProcCtls2 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
10675 {
10676 Assert(g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_PAUSE_LOOP_EXIT);
10677 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_GAP, cPleGapTicks);
10678 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_PLE_WINDOW, cPleWindowTicks);
10679 }
10680 if (u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
10681 {
10682 rc |= VMXWriteVmcs32(VMX_VMCS32_CTRL_TPR_THRESHOLD, u32TprThreshold);
10683 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL, HCPhysVirtApic);
10684 }
10685 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10686 rc |= VMXWriteVmcs64(VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL, HCPhysApicAccess);
10687 rc |= VMXWriteVmcsNw(VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS, uPendingDbgXcpts);
10688 AssertRC(rc);
10689
10690 /*
10691 * Update the nested-guest VMCS cache.
10692 */
10693 pVmcsInfoNstGst->u32PinCtls = u32PinCtls;
10694 pVmcsInfoNstGst->u32ProcCtls = u32ProcCtls;
10695 pVmcsInfoNstGst->u32ProcCtls2 = u32ProcCtls2;
10696 pVmcsInfoNstGst->u32XcptBitmap = u32XcptBitmap;
10697 pVmcsInfoNstGst->u64Cr0Mask = u64Cr0Mask;
10698 pVmcsInfoNstGst->u64Cr4Mask = u64Cr4Mask;
10699 pVmcsInfoNstGst->u32XcptPFMask = u32XcptPFMask;
10700 pVmcsInfoNstGst->u32XcptPFMatch = u32XcptPFMatch;
10701 pVmcsInfoNstGst->HCPhysVirtApic = HCPhysVirtApic;
10702
10703 /*
10704 * We need to flush the TLB if we are switching the APIC-access page address.
10705 * See Intel spec. 28.3.3.4 "Guidelines for Use of the INVEPT Instruction".
10706 */
10707 if (u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10708 pVCpu->hm.s.vmx.fSwitchedNstGstFlushTlb = true;
10709
10710 /*
10711 * MSR bitmap.
10712 *
10713 * The MSR bitmap address has already been initialized while setting up the nested-guest
10714 * VMCS, here we need to merge the MSR bitmaps.
10715 */
10716 if (u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
10717 hmR0VmxMergeMsrBitmapNested(pVCpu, pVmcsInfoNstGst, pVmcsInfoGst);
10718
10719 return VINF_SUCCESS;
10720}
10721#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
10722
10723
10724/**
10725 * Does the preparations before executing guest code in VT-x.
10726 *
10727 * This may cause longjmps to ring-3 and may even result in rescheduling to the
10728 * recompiler/IEM. We must be cautious what we do here regarding committing
10729 * guest-state information into the VMCS assuming we assuredly execute the
10730 * guest in VT-x mode.
10731 *
10732 * If we fall back to the recompiler/IEM after updating the VMCS and clearing
10733 * the common-state (TRPM/forceflags), we must undo those changes so that the
10734 * recompiler/IEM can (and should) use them when it resumes guest execution.
10735 * Otherwise such operations must be done when we can no longer exit to ring-3.
10736 *
10737 * @returns Strict VBox status code (i.e. informational status codes too).
10738 * @retval VINF_SUCCESS if we can proceed with running the guest, interrupts
10739 * have been disabled.
10740 * @retval VINF_VMX_VMEXIT if a nested-guest VM-exit occurs (e.g., while evaluating
10741 * pending events).
10742 * @retval VINF_EM_RESET if a triple-fault occurs while injecting a
10743 * double-fault into the guest.
10744 * @retval VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
10745 * dispatched directly.
10746 * @retval VINF_* scheduling changes, we have to go back to ring-3.
10747 *
10748 * @param pVCpu The cross context virtual CPU structure.
10749 * @param pVmxTransient The VMX-transient structure.
10750 * @param fStepping Whether we are single-stepping the guest in the
10751 * hypervisor debugger. Makes us ignore some of the reasons
10752 * for returning to ring-3, and return VINF_EM_DBG_STEPPED
10753 * if event dispatching took place.
10754 */
10755static VBOXSTRICTRC hmR0VmxPreRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, bool fStepping)
10756{
10757 Assert(VMMRZCallRing3IsEnabled(pVCpu));
10758
10759 Log4Func(("fIsNested=%RTbool fStepping=%RTbool\n", pVmxTransient->fIsNestedGuest, fStepping));
10760
10761#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
10762 if (pVmxTransient->fIsNestedGuest)
10763 {
10764 RT_NOREF2(pVCpu, fStepping);
10765 Log2Func(("Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
10766 return VINF_EM_RESCHEDULE_REM;
10767 }
10768#endif
10769
10770 /*
10771 * Check and process force flag actions, some of which might require us to go back to ring-3.
10772 */
10773 VBOXSTRICTRC rcStrict = hmR0VmxCheckForceFlags(pVCpu, pVmxTransient, fStepping);
10774 if (rcStrict == VINF_SUCCESS)
10775 {
10776 /* FFs don't get set all the time. */
10777#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10778 if ( pVmxTransient->fIsNestedGuest
10779 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10780 {
10781 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10782 return VINF_VMX_VMEXIT;
10783 }
10784#endif
10785 }
10786 else
10787 return rcStrict;
10788
10789 /*
10790 * Virtualize memory-mapped accesses to the physical APIC (may take locks).
10791 */
10792 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10793 if ( !pVCpu->hm.s.vmx.u64GstMsrApicBase
10794 && (g_HmMsrs.u.vmx.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
10795 && PDMHasApic(pVM))
10796 {
10797 int rc = hmR0VmxMapHCApicAccessPage(pVCpu);
10798 AssertRCReturn(rc, rc);
10799 }
10800
10801#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10802 /*
10803 * Merge guest VMCS controls with the nested-guest VMCS controls.
10804 *
10805 * Even if we have not executed the guest prior to this (e.g. when resuming from a
10806 * saved state), we should be okay with merging controls as we initialize the
10807 * guest VMCS controls as part of VM setup phase.
10808 */
10809 if ( pVmxTransient->fIsNestedGuest
10810 && !pVCpu->hm.s.vmx.fMergedNstGstCtls)
10811 {
10812 int rc = hmR0VmxMergeVmcsNested(pVCpu);
10813 AssertRCReturn(rc, rc);
10814 pVCpu->hm.s.vmx.fMergedNstGstCtls = true;
10815 }
10816#endif
10817
10818 /*
10819 * Evaluate events to be injected into the guest.
10820 *
10821 * Events in TRPM can be injected without inspecting the guest state.
10822 * If any new events (interrupts/NMI) are pending currently, we try to set up the
10823 * guest to cause a VM-exit the next time they are ready to receive the event.
10824 */
10825 if (TRPMHasTrap(pVCpu))
10826 hmR0VmxTrpmTrapToPendingEvent(pVCpu);
10827
10828 uint32_t fIntrState;
10829 rcStrict = hmR0VmxEvaluatePendingEvent(pVCpu, pVmxTransient, &fIntrState);
10830
10831#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10832 /*
10833 * While evaluating pending events if something failed (unlikely) or if we were
10834 * preparing to run a nested-guest but performed a nested-guest VM-exit, we should bail.
10835 */
10836 if (rcStrict != VINF_SUCCESS)
10837 return rcStrict;
10838 if ( pVmxTransient->fIsNestedGuest
10839 && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
10840 {
10841 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
10842 return VINF_VMX_VMEXIT;
10843 }
10844#else
10845 Assert(rcStrict == VINF_SUCCESS);
10846#endif
10847
10848 /*
10849 * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus
10850 * needs to be done with longjmps or interrupts + preemption enabled. Event injection might
10851 * also result in triple-faulting the VM.
10852 *
10853 * With nested-guests, the above does not apply since unrestricted guest execution is a
10854 * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
10855 */
10856 rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
10857 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10858 { /* likely */ }
10859 else
10860 {
10861 AssertMsg(rcStrict == VINF_EM_RESET || (rcStrict == VINF_EM_DBG_STEPPED && fStepping),
10862 ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
10863 return rcStrict;
10864 }
10865
10866 /*
10867 * A longjump might result in importing CR3 even for VM-exits that don't necessarily
10868 * import CR3 themselves. We will need to update them here, as even as late as the above
10869 * hmR0VmxInjectPendingEvent() call may lazily import guest-CPU state on demand causing
10870 * the below force flags to be set.
10871 */
10872 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3))
10873 {
10874 Assert(!(ASMAtomicUoReadU64(&pVCpu->cpum.GstCtx.fExtrn) & CPUMCTX_EXTRN_CR3));
10875 int rc2 = PGMUpdateCR3(pVCpu, CPUMGetGuestCR3(pVCpu), false /* fPdpesMapped */);
10876 AssertMsgReturn(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_SYNC_CR3,
10877 ("%Rrc\n", rc2), RT_FAILURE_NP(rc2) ? rc2 : VERR_IPE_UNEXPECTED_INFO_STATUS);
10878 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
10879 }
10880
10881#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10882 /* Paranoia. */
10883 Assert(!pVmxTransient->fIsNestedGuest || CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
10884#endif
10885
10886 /*
10887 * No longjmps to ring-3 from this point on!!!
10888 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
10889 * This also disables flushing of the R0-logger instance (if any).
10890 */
10891 VMMRZCallRing3Disable(pVCpu);
10892
10893 /*
10894 * Export the guest state bits.
10895 *
10896 * We cannot perform longjmps while loading the guest state because we do not preserve the
10897 * host/guest state (although the VMCS will be preserved) across longjmps which can cause
10898 * CPU migration.
10899 *
10900 * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
10901 * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
10902 */
10903 rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
10904 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
10905 { /* likely */ }
10906 else
10907 {
10908 VMMRZCallRing3Enable(pVCpu);
10909 return rcStrict;
10910 }
10911
10912 /*
10913 * We disable interrupts so that we don't miss any interrupts that would flag preemption
10914 * (IPI/timers etc.) when thread-context hooks aren't used and we've been running with
10915 * preemption disabled for a while. Since this is purely to aid the
10916 * RTThreadPreemptIsPending() code, it doesn't matter that it may temporarily reenable and
10917 * disable interrupt on NT.
10918 *
10919 * We need to check for force-flags that could've possible been altered since we last
10920 * checked them (e.g. by PDMGetInterrupt() leaving the PDM critical section,
10921 * see @bugref{6398}).
10922 *
10923 * We also check a couple of other force-flags as a last opportunity to get the EMT back
10924 * to ring-3 before executing guest code.
10925 */
10926 pVmxTransient->fEFlags = ASMIntDisableFlags();
10927
10928 if ( ( !VM_FF_IS_ANY_SET(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
10929 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
10930 || ( fStepping /* Optimized for the non-stepping case, so a bit of unnecessary work when stepping. */
10931 && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK & ~(VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT))) )
10932 {
10933 if (!RTThreadPreemptIsPending(NIL_RTTHREAD))
10934 {
10935#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
10936 /*
10937 * If we are executing a nested-guest make sure that we should intercept subsequent
10938 * events. The one we are injecting might be part of VM-entry. This is mainly to keep
10939 * the VM-exit instruction emulation happy.
10940 */
10941 if (pVmxTransient->fIsNestedGuest)
10942 CPUMSetGuestVmxInterceptEvents(&pVCpu->cpum.GstCtx, true);
10943#endif
10944
10945 /*
10946 * We've injected any pending events. This is really the point of no return (to ring-3).
10947 *
10948 * Note! The caller expects to continue with interrupts & longjmps disabled on successful
10949 * returns from this function, so do -not- enable them here.
10950 */
10951 pVCpu->hm.s.Event.fPending = false;
10952 return VINF_SUCCESS;
10953 }
10954
10955 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchPendingHostIrq);
10956 rcStrict = VINF_EM_RAW_INTERRUPT;
10957 }
10958 else
10959 {
10960 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
10961 rcStrict = VINF_EM_RAW_TO_R3;
10962 }
10963
10964 ASMSetFlags(pVmxTransient->fEFlags);
10965 VMMRZCallRing3Enable(pVCpu);
10966
10967 return rcStrict;
10968}
10969
10970
10971/**
10972 * Final preparations before executing guest code using hardware-assisted VMX.
10973 *
10974 * We can no longer get preempted to a different host CPU and there are no returns
10975 * to ring-3. We ignore any errors that may happen from this point (e.g. VMWRITE
10976 * failures), this function is not intended to fail sans unrecoverable hardware
10977 * errors.
10978 *
10979 * @param pVCpu The cross context virtual CPU structure.
10980 * @param pVmxTransient The VMX-transient structure.
10981 *
10982 * @remarks Called with preemption disabled.
10983 * @remarks No-long-jump zone!!!
10984 */
10985static void hmR0VmxPreRunGuestCommitted(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
10986{
10987 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
10988 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
10989 Assert(!pVCpu->hm.s.Event.fPending);
10990
10991 /*
10992 * Indicate start of guest execution and where poking EMT out of guest-context is recognized.
10993 */
10994 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
10995 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
10996
10997 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
10998 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
10999 PHMPHYSCPU pHostCpu = hmR0GetCurrentCpu();
11000 RTCPUID const idCurrentCpu = pHostCpu->idCpu;
11001
11002 if (!CPUMIsGuestFPUStateActive(pVCpu))
11003 {
11004 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestFpuState, x);
11005 if (CPUMR0LoadGuestFPU(pVM, pVCpu) == VINF_CPUM_HOST_CR0_MODIFIED)
11006 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_HOST_CONTEXT;
11007 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestFpuState, x);
11008 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadGuestFpu);
11009 }
11010
11011 /*
11012 * Re-export the host state bits as we may've been preempted (only happens when
11013 * thread-context hooks are used or when the VM start function changes) or if
11014 * the host CR0 is modified while loading the guest FPU state above.
11015 *
11016 * The 64-on-32 switcher saves the (64-bit) host state into the VMCS and if we
11017 * changed the switcher back to 32-bit, we *must* save the 32-bit host state here,
11018 * see @bugref{8432}.
11019 *
11020 * This may also happen when switching to/from a nested-guest VMCS without leaving
11021 * ring-0.
11022 */
11023 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT)
11024 {
11025 hmR0VmxExportHostState(pVCpu);
11026 STAM_COUNTER_INC(&pVCpu->hm.s.StatExportHostState);
11027 }
11028 Assert(!(pVCpu->hm.s.fCtxChanged & HM_CHANGED_HOST_CONTEXT));
11029
11030 /*
11031 * Export the state shared between host and guest (FPU, debug, lazy MSRs).
11032 */
11033 if (pVCpu->hm.s.fCtxChanged & HM_CHANGED_VMX_HOST_GUEST_SHARED_STATE)
11034 hmR0VmxExportSharedState(pVCpu, pVmxTransient);
11035 AssertMsg(!pVCpu->hm.s.fCtxChanged, ("fCtxChanged=%#RX64\n", pVCpu->hm.s.fCtxChanged));
11036
11037 /*
11038 * Store status of the shared guest/host debug state at the time of VM-entry.
11039 */
11040 pVmxTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
11041 pVmxTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
11042
11043 /*
11044 * Always cache the TPR-shadow if the virtual-APIC page exists, thereby skipping
11045 * more than one conditional check. The post-run side of our code shall determine
11046 * if it needs to sync. the virtual APIC TPR with the TPR-shadow.
11047 */
11048 if (pVmcsInfo->pbVirtApic)
11049 pVmxTransient->u8GuestTpr = pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR];
11050
11051 /*
11052 * Update the host MSRs values in the VM-exit MSR-load area.
11053 */
11054 if (!pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs)
11055 {
11056 if (pVmcsInfo->cExitMsrLoad > 0)
11057 hmR0VmxUpdateAutoLoadHostMsrs(pVCpu, pVmcsInfo);
11058 pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs = true;
11059 }
11060
11061 /*
11062 * Evaluate if we need to intercept guest RDTSC/P accesses. Set up the
11063 * VMX-preemption timer based on the next virtual sync clock deadline.
11064 */
11065 if ( !pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer
11066 || idCurrentCpu != pVCpu->hmr0.s.idLastCpu)
11067 {
11068 hmR0VmxUpdateTscOffsettingAndPreemptTimer(pVCpu, pVmxTransient, idCurrentCpu);
11069 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = true;
11070 }
11071
11072 /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
11073 bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
11074 if (!fIsRdtscIntercepted)
11075 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
11076 else
11077 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
11078
11079 ASMAtomicUoWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
11080 hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo); /* Invalidate the appropriate guest entries from the TLB. */
11081 Assert(idCurrentCpu == pVCpu->hmr0.s.idLastCpu);
11082 pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Record the error reporting info. with the current host CPU. */
11083 pVmcsInfo->idHostCpuState = idCurrentCpu; /* Record the CPU for which the host-state has been exported. */
11084 pVmcsInfo->idHostCpuExec = idCurrentCpu; /* Record the CPU on which we shall execute. */
11085
11086 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
11087
11088 TMNotifyStartOfExecution(pVM, pVCpu); /* Notify TM to resume its clocks when TSC is tied to execution,
11089 as we're about to start executing the guest. */
11090
11091 /*
11092 * Load the guest TSC_AUX MSR when we are not intercepting RDTSCP.
11093 *
11094 * This is done this late as updating the TSC offsetting/preemption timer above
11095 * figures out if we can skip intercepting RDTSCP by calculating the number of
11096 * host CPU ticks till the next virtual sync deadline (for the dynamic case).
11097 */
11098 if ( (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
11099 && !fIsRdtscIntercepted)
11100 {
11101 hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
11102
11103 /* NB: Because we call hmR0VmxAddAutoLoadStoreMsr with fUpdateHostMsr=true,
11104 it's safe even after hmR0VmxUpdateAutoLoadHostMsrs has already been done. */
11105 int rc = hmR0VmxAddAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX, CPUMGetGuestTscAux(pVCpu),
11106 true /* fSetReadWrite */, true /* fUpdateHostMsr */);
11107 AssertRC(rc);
11108 Assert(!pVmxTransient->fRemoveTscAuxMsr);
11109 pVmxTransient->fRemoveTscAuxMsr = true;
11110 }
11111
11112#ifdef VBOX_STRICT
11113 Assert(pVCpu->hmr0.s.vmx.fUpdatedHostAutoMsrs);
11114 hmR0VmxCheckAutoLoadStoreMsrs(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
11115 hmR0VmxCheckHostEferMsr(pVmcsInfo);
11116 AssertRC(hmR0VmxCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest));
11117#endif
11118
11119#ifdef HMVMX_ALWAYS_CHECK_GUEST_STATE
11120 /** @todo r=ramshankar: We can now probably use iemVmxVmentryCheckGuestState here.
11121 * Add a PVMXMSRS parameter to it, so that IEM can look at the host MSRs,
11122 * see @bugref{9180#c54}. */
11123 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
11124 if (uInvalidReason != VMX_IGS_REASON_NOT_FOUND)
11125 Log4(("hmR0VmxCheckGuestState returned %#x\n", uInvalidReason));
11126#endif
11127}
11128
11129
11130/**
11131 * First C routine invoked after running guest code using hardware-assisted VMX.
11132 *
11133 * @param pVCpu The cross context virtual CPU structure.
11134 * @param pVmxTransient The VMX-transient structure.
11135 * @param rcVMRun Return code of VMLAUNCH/VMRESUME.
11136 *
11137 * @remarks Called with interrupts disabled, and returns with interrupts enabled!
11138 *
11139 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
11140 * unconditionally when it is safe to do so.
11141 */
11142static void hmR0VmxPostRunGuest(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, int rcVMRun)
11143{
11144 ASMAtomicUoWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
11145 ASMAtomicIncU32(&pVCpu->hmr0.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
11146 pVCpu->hm.s.fCtxChanged = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
11147 pVmxTransient->fVmcsFieldsRead = 0; /* Transient fields need to be read from the VMCS. */
11148 pVmxTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
11149 pVmxTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
11150
11151 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11152 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
11153 {
11154 uint64_t uGstTsc;
11155 if (!pVmxTransient->fIsNestedGuest)
11156 uGstTsc = pVCpu->hmr0.s.uTscExit + pVmcsInfo->u64TscOffset;
11157 else
11158 {
11159 uint64_t const uNstGstTsc = pVCpu->hmr0.s.uTscExit + pVmcsInfo->u64TscOffset;
11160 uGstTsc = CPUMRemoveNestedGuestTscOffset(pVCpu, uNstGstTsc);
11161 }
11162 TMCpuTickSetLastSeen(pVCpu, uGstTsc); /* Update TM with the guest TSC. */
11163 }
11164
11165 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatPreExit, x);
11166 TMNotifyEndOfExecution(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->hmr0.s.uTscExit); /* Notify TM that the guest is no longer running. */
11167 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
11168
11169 pVCpu->hmr0.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Some host state messed up by VMX needs restoring. */
11170 pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
11171#ifdef VBOX_STRICT
11172 hmR0VmxCheckHostEferMsr(pVmcsInfo); /* Verify that the host EFER MSR wasn't modified. */
11173#endif
11174 Assert(!ASMIntAreEnabled());
11175 ASMSetFlags(pVmxTransient->fEFlags); /* Enable interrupts. */
11176 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
11177
11178#ifdef HMVMX_ALWAYS_CLEAN_TRANSIENT
11179 /*
11180 * Clean all the VMCS fields in the transient structure before reading
11181 * anything from the VMCS.
11182 */
11183 pVmxTransient->uExitReason = 0;
11184 pVmxTransient->uExitIntErrorCode = 0;
11185 pVmxTransient->uExitQual = 0;
11186 pVmxTransient->uGuestLinearAddr = 0;
11187 pVmxTransient->uExitIntInfo = 0;
11188 pVmxTransient->cbExitInstr = 0;
11189 pVmxTransient->ExitInstrInfo.u = 0;
11190 pVmxTransient->uEntryIntInfo = 0;
11191 pVmxTransient->uEntryXcptErrorCode = 0;
11192 pVmxTransient->cbEntryInstr = 0;
11193 pVmxTransient->uIdtVectoringInfo = 0;
11194 pVmxTransient->uIdtVectoringErrorCode = 0;
11195#endif
11196
11197 /*
11198 * Save the basic VM-exit reason and check if the VM-entry failed.
11199 * See Intel spec. 24.9.1 "Basic VM-exit Information".
11200 */
11201 uint32_t uExitReason;
11202 int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON, &uExitReason);
11203 AssertRC(rc);
11204 pVmxTransient->uExitReason = VMX_EXIT_REASON_BASIC(uExitReason);
11205 pVmxTransient->fVMEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(uExitReason);
11206
11207 /*
11208 * Log the VM-exit before logging anything else as otherwise it might be a
11209 * tad confusing what happens before and after the world-switch.
11210 */
11211 HMVMX_LOG_EXIT(pVCpu, uExitReason);
11212
11213 /*
11214 * Remove the TSC_AUX MSR from the auto-load/store MSR area and reset any MSR
11215 * bitmap permissions, if it was added before VM-entry.
11216 */
11217 if (pVmxTransient->fRemoveTscAuxMsr)
11218 {
11219 hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, pVmxTransient, MSR_K8_TSC_AUX);
11220 pVmxTransient->fRemoveTscAuxMsr = false;
11221 }
11222
11223 /*
11224 * Check if VMLAUNCH/VMRESUME succeeded.
11225 * If this failed, we cause a guru meditation and cease further execution.
11226 *
11227 * However, if we are executing a nested-guest we might fail if we use the
11228 * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
11229 */
11230 if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
11231 {
11232 /*
11233 * Update the VM-exit history array here even if the VM-entry failed due to:
11234 * - Invalid guest state.
11235 * - MSR loading.
11236 * - Machine-check event.
11237 *
11238 * In any of the above cases we will still have a "valid" VM-exit reason
11239 * despite @a fVMEntryFailed being false.
11240 *
11241 * See Intel spec. 26.7 "VM-Entry failures during or after loading guest state".
11242 *
11243 * Note! We don't have CS or RIP at this point. Will probably address that later
11244 * by amending the history entry added here.
11245 */
11246 EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_VMX, pVmxTransient->uExitReason & EMEXIT_F_TYPE_MASK),
11247 UINT64_MAX, pVCpu->hmr0.s.uTscExit);
11248
11249 if (RT_LIKELY(!pVmxTransient->fVMEntryFailed))
11250 {
11251 VMMRZCallRing3Enable(pVCpu);
11252 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
11253
11254#ifdef HMVMX_ALWAYS_SAVE_RO_GUEST_STATE
11255 hmR0VmxReadAllRoFieldsVmcs(pVmxTransient);
11256#endif
11257
11258 /*
11259 * Import the guest-interruptibility state always as we need it while evaluating
11260 * injecting events on re-entry.
11261 *
11262 * We don't import CR0 (when unrestricted guest execution is unavailable) despite
11263 * checking for real-mode while exporting the state because all bits that cause
11264 * mode changes wrt CR0 are intercepted.
11265 */
11266 uint64_t const fImportMask = CPUMCTX_EXTRN_HM_VMX_INT_STATE
11267#if defined(HMVMX_ALWAYS_SYNC_FULL_GUEST_STATE) || defined(HMVMX_ALWAYS_SAVE_FULL_GUEST_STATE)
11268 | HMVMX_CPUMCTX_EXTRN_ALL
11269#elif defined(HMVMX_ALWAYS_SAVE_GUEST_RFLAGS)
11270 | CPUMCTX_EXTRN_RFLAGS
11271#endif
11272 ;
11273 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImportMask);
11274 AssertRC(rc);
11275
11276 /*
11277 * Sync the TPR shadow with our APIC state.
11278 */
11279 if ( !pVmxTransient->fIsNestedGuest
11280 && (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
11281 {
11282 Assert(pVmcsInfo->pbVirtApic);
11283 if (pVmxTransient->u8GuestTpr != pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR])
11284 {
11285 rc = APICSetTpr(pVCpu, pVmcsInfo->pbVirtApic[XAPIC_OFF_TPR]);
11286 AssertRC(rc);
11287 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
11288 }
11289 }
11290
11291 Assert(VMMRZCallRing3IsEnabled(pVCpu));
11292 Assert( pVmxTransient->fWasGuestDebugStateActive == false
11293 || pVmxTransient->fWasHyperDebugStateActive == false);
11294 return;
11295 }
11296 }
11297#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11298 else if (pVmxTransient->fIsNestedGuest)
11299 AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
11300#endif
11301 else
11302 Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
11303
11304 VMMRZCallRing3Enable(pVCpu);
11305}
11306
11307
11308/**
11309 * Runs the guest code using hardware-assisted VMX the normal way.
11310 *
11311 * @returns VBox status code.
11312 * @param pVCpu The cross context virtual CPU structure.
11313 * @param pcLoops Pointer to the number of executed loops.
11314 */
11315static VBOXSTRICTRC hmR0VmxRunGuestCodeNormal(PVMCPUCC pVCpu, uint32_t *pcLoops)
11316{
11317 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
11318 Assert(pcLoops);
11319 Assert(*pcLoops <= cMaxResumeLoops);
11320 Assert(!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
11321
11322#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11323 /*
11324 * Switch to the guest VMCS as we may have transitioned from executing the nested-guest
11325 * without leaving ring-0. Otherwise, if we came from ring-3 we would have loaded the
11326 * guest VMCS while entering the VMX ring-0 session.
11327 */
11328 if (pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
11329 {
11330 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, false /* fSwitchToNstGstVmcs */);
11331 if (RT_SUCCESS(rc))
11332 { /* likely */ }
11333 else
11334 {
11335 LogRelFunc(("Failed to switch to the guest VMCS. rc=%Rrc\n", rc));
11336 return rc;
11337 }
11338 }
11339#endif
11340
11341 VMXTRANSIENT VmxTransient;
11342 RT_ZERO(VmxTransient);
11343 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
11344
11345 /* Paranoia. */
11346 Assert(VmxTransient.pVmcsInfo == &pVCpu->hmr0.s.vmx.VmcsInfo);
11347
11348 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
11349 for (;;)
11350 {
11351 Assert(!HMR0SuspendPending());
11352 HMVMX_ASSERT_CPU_SAFE(pVCpu);
11353 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
11354
11355 /*
11356 * Preparatory work for running nested-guest code, this may force us to
11357 * return to ring-3.
11358 *
11359 * Warning! This bugger disables interrupts on VINF_SUCCESS!
11360 */
11361 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
11362 if (rcStrict != VINF_SUCCESS)
11363 break;
11364
11365 /* Interrupts are disabled at this point! */
11366 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
11367 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
11368 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
11369 /* Interrupts are re-enabled at this point! */
11370
11371 /*
11372 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
11373 */
11374 if (RT_SUCCESS(rcRun))
11375 { /* very likely */ }
11376 else
11377 {
11378 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
11379 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
11380 return rcRun;
11381 }
11382
11383 /*
11384 * Profile the VM-exit.
11385 */
11386 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
11387 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
11388 STAM_COUNTER_INC(&pVCpu->hm.s.aStatExitReason[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
11389 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
11390 HMVMX_START_EXIT_DISPATCH_PROF();
11391
11392 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
11393
11394 /*
11395 * Handle the VM-exit.
11396 */
11397#ifdef HMVMX_USE_FUNCTION_TABLE
11398 rcStrict = g_aVMExitHandlers[VmxTransient.uExitReason].pfn(pVCpu, &VmxTransient);
11399#else
11400 rcStrict = hmR0VmxHandleExit(pVCpu, &VmxTransient);
11401#endif
11402 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
11403 if (rcStrict == VINF_SUCCESS)
11404 {
11405 if (++(*pcLoops) <= cMaxResumeLoops)
11406 continue;
11407 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
11408 rcStrict = VINF_EM_RAW_INTERRUPT;
11409 }
11410 break;
11411 }
11412
11413 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11414 return rcStrict;
11415}
11416
11417
11418#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
11419/**
11420 * Runs the nested-guest code using hardware-assisted VMX.
11421 *
11422 * @returns VBox status code.
11423 * @param pVCpu The cross context virtual CPU structure.
11424 * @param pcLoops Pointer to the number of executed loops.
11425 *
11426 * @sa hmR0VmxRunGuestCodeNormal.
11427 */
11428static VBOXSTRICTRC hmR0VmxRunGuestCodeNested(PVMCPUCC pVCpu, uint32_t *pcLoops)
11429{
11430 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
11431 Assert(pcLoops);
11432 Assert(*pcLoops <= cMaxResumeLoops);
11433 Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
11434
11435 /*
11436 * Switch to the nested-guest VMCS as we may have transitioned from executing the
11437 * guest without leaving ring-0. Otherwise, if we came from ring-3 we would have
11438 * loaded the nested-guest VMCS while entering the VMX ring-0 session.
11439 */
11440 if (!pVCpu->hmr0.s.vmx.fSwitchedToNstGstVmcs)
11441 {
11442 int rc = hmR0VmxSwitchToGstOrNstGstVmcs(pVCpu, true /* fSwitchToNstGstVmcs */);
11443 if (RT_SUCCESS(rc))
11444 { /* likely */ }
11445 else
11446 {
11447 LogRelFunc(("Failed to switch to the nested-guest VMCS. rc=%Rrc\n", rc));
11448 return rc;
11449 }
11450 }
11451
11452 VMXTRANSIENT VmxTransient;
11453 RT_ZERO(VmxTransient);
11454 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
11455 VmxTransient.fIsNestedGuest = true;
11456
11457 /* Paranoia. */
11458 Assert(VmxTransient.pVmcsInfo == &pVCpu->hmr0.s.vmx.VmcsInfoNstGst);
11459
11460 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
11461 for (;;)
11462 {
11463 Assert(!HMR0SuspendPending());
11464 HMVMX_ASSERT_CPU_SAFE(pVCpu);
11465 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
11466
11467 /*
11468 * Preparatory work for running guest code, this may force us to
11469 * return to ring-3.
11470 *
11471 * Warning! This bugger disables interrupts on VINF_SUCCESS!
11472 */
11473 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, false /* fStepping */);
11474 if (rcStrict != VINF_SUCCESS)
11475 break;
11476
11477 /* Interrupts are disabled at this point! */
11478 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
11479 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
11480 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
11481 /* Interrupts are re-enabled at this point! */
11482
11483 /*
11484 * Check for errors with running the VM (VMLAUNCH/VMRESUME).
11485 */
11486 if (RT_SUCCESS(rcRun))
11487 { /* very likely */ }
11488 else
11489 {
11490 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
11491 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
11492 return rcRun;
11493 }
11494
11495 /*
11496 * Profile the VM-exit.
11497 */
11498 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
11499 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
11500 STAM_COUNTER_INC(&pVCpu->hm.s.StatNestedExitAll);
11501 STAM_COUNTER_INC(&pVCpu->hm.s.aStatNestedExitReason[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
11502 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
11503 HMVMX_START_EXIT_DISPATCH_PROF();
11504
11505 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
11506
11507 /*
11508 * Handle the VM-exit.
11509 */
11510 rcStrict = hmR0VmxHandleExitNested(pVCpu, &VmxTransient);
11511 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
11512 if (rcStrict == VINF_SUCCESS)
11513 {
11514 if (!CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
11515 {
11516 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchNstGstVmexit);
11517 rcStrict = VINF_VMX_VMEXIT;
11518 }
11519 else
11520 {
11521 if (++(*pcLoops) <= cMaxResumeLoops)
11522 continue;
11523 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
11524 rcStrict = VINF_EM_RAW_INTERRUPT;
11525 }
11526 }
11527 else
11528 Assert(rcStrict != VINF_VMX_VMEXIT);
11529 break;
11530 }
11531
11532 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
11533 return rcStrict;
11534}
11535#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
11536
11537
11538/** @name Execution loop for single stepping, DBGF events and expensive Dtrace
11539 * probes.
11540 *
11541 * The following few functions and associated structure contains the bloat
11542 * necessary for providing detailed debug events and dtrace probes as well as
11543 * reliable host side single stepping. This works on the principle of
11544 * "subclassing" the normal execution loop and workers. We replace the loop
11545 * method completely and override selected helpers to add necessary adjustments
11546 * to their core operation.
11547 *
11548 * The goal is to keep the "parent" code lean and mean, so as not to sacrifice
11549 * any performance for debug and analysis features.
11550 *
11551 * @{
11552 */
11553
11554/**
11555 * Transient per-VCPU debug state of VMCS and related info. we save/restore in
11556 * the debug run loop.
11557 */
11558typedef struct VMXRUNDBGSTATE
11559{
11560 /** The RIP we started executing at. This is for detecting that we stepped. */
11561 uint64_t uRipStart;
11562 /** The CS we started executing with. */
11563 uint16_t uCsStart;
11564
11565 /** Whether we've actually modified the 1st execution control field. */
11566 bool fModifiedProcCtls : 1;
11567 /** Whether we've actually modified the 2nd execution control field. */
11568 bool fModifiedProcCtls2 : 1;
11569 /** Whether we've actually modified the exception bitmap. */
11570 bool fModifiedXcptBitmap : 1;
11571
11572 /** We desire the modified the CR0 mask to be cleared. */
11573 bool fClearCr0Mask : 1;
11574 /** We desire the modified the CR4 mask to be cleared. */
11575 bool fClearCr4Mask : 1;
11576 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC. */
11577 uint32_t fCpe1Extra;
11578 /** Stuff we do not want in VMX_VMCS32_CTRL_PROC_EXEC. */
11579 uint32_t fCpe1Unwanted;
11580 /** Stuff we need in VMX_VMCS32_CTRL_PROC_EXEC2. */
11581 uint32_t fCpe2Extra;
11582 /** Extra stuff we need in VMX_VMCS32_CTRL_EXCEPTION_BITMAP. */
11583 uint32_t bmXcptExtra;
11584 /** The sequence number of the Dtrace provider settings the state was
11585 * configured against. */
11586 uint32_t uDtraceSettingsSeqNo;
11587 /** VM-exits to check (one bit per VM-exit). */
11588 uint32_t bmExitsToCheck[3];
11589
11590 /** The initial VMX_VMCS32_CTRL_PROC_EXEC value (helps with restore). */
11591 uint32_t fProcCtlsInitial;
11592 /** The initial VMX_VMCS32_CTRL_PROC_EXEC2 value (helps with restore). */
11593 uint32_t fProcCtls2Initial;
11594 /** The initial VMX_VMCS32_CTRL_EXCEPTION_BITMAP value (helps with restore). */
11595 uint32_t bmXcptInitial;
11596} VMXRUNDBGSTATE;
11597AssertCompileMemberSize(VMXRUNDBGSTATE, bmExitsToCheck, (VMX_EXIT_MAX + 1 + 31) / 32 * 4);
11598typedef VMXRUNDBGSTATE *PVMXRUNDBGSTATE;
11599
11600
11601/**
11602 * Initializes the VMXRUNDBGSTATE structure.
11603 *
11604 * @param pVCpu The cross context virtual CPU structure of the
11605 * calling EMT.
11606 * @param pVmxTransient The VMX-transient structure.
11607 * @param pDbgState The debug state to initialize.
11608 */
11609static void hmR0VmxRunDebugStateInit(PVMCPUCC pVCpu, PCVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11610{
11611 pDbgState->uRipStart = pVCpu->cpum.GstCtx.rip;
11612 pDbgState->uCsStart = pVCpu->cpum.GstCtx.cs.Sel;
11613
11614 pDbgState->fModifiedProcCtls = false;
11615 pDbgState->fModifiedProcCtls2 = false;
11616 pDbgState->fModifiedXcptBitmap = false;
11617 pDbgState->fClearCr0Mask = false;
11618 pDbgState->fClearCr4Mask = false;
11619 pDbgState->fCpe1Extra = 0;
11620 pDbgState->fCpe1Unwanted = 0;
11621 pDbgState->fCpe2Extra = 0;
11622 pDbgState->bmXcptExtra = 0;
11623 pDbgState->fProcCtlsInitial = pVmxTransient->pVmcsInfo->u32ProcCtls;
11624 pDbgState->fProcCtls2Initial = pVmxTransient->pVmcsInfo->u32ProcCtls2;
11625 pDbgState->bmXcptInitial = pVmxTransient->pVmcsInfo->u32XcptBitmap;
11626}
11627
11628
11629/**
11630 * Updates the VMSC fields with changes requested by @a pDbgState.
11631 *
11632 * This is performed after hmR0VmxPreRunGuestDebugStateUpdate as well
11633 * immediately before executing guest code, i.e. when interrupts are disabled.
11634 * We don't check status codes here as we cannot easily assert or return in the
11635 * latter case.
11636 *
11637 * @param pVCpu The cross context virtual CPU structure.
11638 * @param pVmxTransient The VMX-transient structure.
11639 * @param pDbgState The debug state.
11640 */
11641static void hmR0VmxPreRunGuestDebugStateApply(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11642{
11643 /*
11644 * Ensure desired flags in VMCS control fields are set.
11645 * (Ignoring write failure here, as we're committed and it's just debug extras.)
11646 *
11647 * Note! We load the shadow CR0 & CR4 bits when we flag the clearing, so
11648 * there should be no stale data in pCtx at this point.
11649 */
11650 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11651 if ( (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Extra) != pDbgState->fCpe1Extra
11652 || (pVmcsInfo->u32ProcCtls & pDbgState->fCpe1Unwanted))
11653 {
11654 pVmcsInfo->u32ProcCtls |= pDbgState->fCpe1Extra;
11655 pVmcsInfo->u32ProcCtls &= ~pDbgState->fCpe1Unwanted;
11656 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
11657 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC: %#RX32\n", pVmcsInfo->u32ProcCtls));
11658 pDbgState->fModifiedProcCtls = true;
11659 }
11660
11661 if ((pVmcsInfo->u32ProcCtls2 & pDbgState->fCpe2Extra) != pDbgState->fCpe2Extra)
11662 {
11663 pVmcsInfo->u32ProcCtls2 |= pDbgState->fCpe2Extra;
11664 VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pVmcsInfo->u32ProcCtls2);
11665 Log6Func(("VMX_VMCS32_CTRL_PROC_EXEC2: %#RX32\n", pVmcsInfo->u32ProcCtls2));
11666 pDbgState->fModifiedProcCtls2 = true;
11667 }
11668
11669 if ((pVmcsInfo->u32XcptBitmap & pDbgState->bmXcptExtra) != pDbgState->bmXcptExtra)
11670 {
11671 pVmcsInfo->u32XcptBitmap |= pDbgState->bmXcptExtra;
11672 VMXWriteVmcs32(VMX_VMCS32_CTRL_EXCEPTION_BITMAP, pVmcsInfo->u32XcptBitmap);
11673 Log6Func(("VMX_VMCS32_CTRL_EXCEPTION_BITMAP: %#RX32\n", pVmcsInfo->u32XcptBitmap));
11674 pDbgState->fModifiedXcptBitmap = true;
11675 }
11676
11677 if (pDbgState->fClearCr0Mask && pVmcsInfo->u64Cr0Mask != 0)
11678 {
11679 pVmcsInfo->u64Cr0Mask = 0;
11680 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR0_MASK, 0);
11681 Log6Func(("VMX_VMCS_CTRL_CR0_MASK: 0\n"));
11682 }
11683
11684 if (pDbgState->fClearCr4Mask && pVmcsInfo->u64Cr4Mask != 0)
11685 {
11686 pVmcsInfo->u64Cr4Mask = 0;
11687 VMXWriteVmcsNw(VMX_VMCS_CTRL_CR4_MASK, 0);
11688 Log6Func(("VMX_VMCS_CTRL_CR4_MASK: 0\n"));
11689 }
11690
11691 NOREF(pVCpu);
11692}
11693
11694
11695/**
11696 * Restores VMCS fields that were changed by hmR0VmxPreRunGuestDebugStateApply for
11697 * re-entry next time around.
11698 *
11699 * @returns Strict VBox status code (i.e. informational status codes too).
11700 * @param pVCpu The cross context virtual CPU structure.
11701 * @param pVmxTransient The VMX-transient structure.
11702 * @param pDbgState The debug state.
11703 * @param rcStrict The return code from executing the guest using single
11704 * stepping.
11705 */
11706static VBOXSTRICTRC hmR0VmxRunDebugStateRevert(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState,
11707 VBOXSTRICTRC rcStrict)
11708{
11709 /*
11710 * Restore VM-exit control settings as we may not reenter this function the
11711 * next time around.
11712 */
11713 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
11714
11715 /* We reload the initial value, trigger what we can of recalculations the
11716 next time around. From the looks of things, that's all that's required atm. */
11717 if (pDbgState->fModifiedProcCtls)
11718 {
11719 if (!(pDbgState->fProcCtlsInitial & VMX_PROC_CTLS_MOV_DR_EXIT) && CPUMIsHyperDebugStateActive(pVCpu))
11720 pDbgState->fProcCtlsInitial |= VMX_PROC_CTLS_MOV_DR_EXIT; /* Avoid assertion in hmR0VmxLeave */
11721 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pDbgState->fProcCtlsInitial);
11722 AssertRC(rc2);
11723 pVmcsInfo->u32ProcCtls = pDbgState->fProcCtlsInitial;
11724 }
11725
11726 /* We're currently the only ones messing with this one, so just restore the
11727 cached value and reload the field. */
11728 if ( pDbgState->fModifiedProcCtls2
11729 && pVmcsInfo->u32ProcCtls2 != pDbgState->fProcCtls2Initial)
11730 {
11731 int rc2 = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, pDbgState->fProcCtls2Initial);
11732 AssertRC(rc2);
11733 pVmcsInfo->u32ProcCtls2 = pDbgState->fProcCtls2Initial;
11734 }
11735
11736 /* If we've modified the exception bitmap, we restore it and trigger
11737 reloading and partial recalculation the next time around. */
11738 if (pDbgState->fModifiedXcptBitmap)
11739 pVmcsInfo->u32XcptBitmap = pDbgState->bmXcptInitial;
11740
11741 return rcStrict;
11742}
11743
11744
11745/**
11746 * Configures VM-exit controls for current DBGF and DTrace settings.
11747 *
11748 * This updates @a pDbgState and the VMCS execution control fields to reflect
11749 * the necessary VM-exits demanded by DBGF and DTrace.
11750 *
11751 * @param pVCpu The cross context virtual CPU structure.
11752 * @param pVmxTransient The VMX-transient structure. May update
11753 * fUpdatedTscOffsettingAndPreemptTimer.
11754 * @param pDbgState The debug state.
11755 */
11756static void hmR0VmxPreRunGuestDebugStateUpdate(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
11757{
11758 /*
11759 * Take down the dtrace serial number so we can spot changes.
11760 */
11761 pDbgState->uDtraceSettingsSeqNo = VBOXVMM_GET_SETTINGS_SEQ_NO();
11762 ASMCompilerBarrier();
11763
11764 /*
11765 * We'll rebuild most of the middle block of data members (holding the
11766 * current settings) as we go along here, so start by clearing it all.
11767 */
11768 pDbgState->bmXcptExtra = 0;
11769 pDbgState->fCpe1Extra = 0;
11770 pDbgState->fCpe1Unwanted = 0;
11771 pDbgState->fCpe2Extra = 0;
11772 for (unsigned i = 0; i < RT_ELEMENTS(pDbgState->bmExitsToCheck); i++)
11773 pDbgState->bmExitsToCheck[i] = 0;
11774
11775 /*
11776 * Software interrupts (INT XXh) - no idea how to trigger these...
11777 */
11778 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
11779 if ( DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_INTERRUPT_SOFTWARE)
11780 || VBOXVMM_INT_SOFTWARE_ENABLED())
11781 {
11782 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11783 }
11784
11785 /*
11786 * INT3 breakpoints - triggered by #BP exceptions.
11787 */
11788 if (pVM->dbgf.ro.cEnabledInt3Breakpoints > 0)
11789 pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11790
11791 /*
11792 * Exception bitmap and XCPT events+probes.
11793 */
11794 for (int iXcpt = 0; iXcpt < (DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST + 1); iXcpt++)
11795 if (DBGF_IS_EVENT_ENABLED(pVM, (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + iXcpt)))
11796 pDbgState->bmXcptExtra |= RT_BIT_32(iXcpt);
11797
11798 if (VBOXVMM_XCPT_DE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DE);
11799 if (VBOXVMM_XCPT_DB_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DB);
11800 if (VBOXVMM_XCPT_BP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BP);
11801 if (VBOXVMM_XCPT_OF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_OF);
11802 if (VBOXVMM_XCPT_BR_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_BR);
11803 if (VBOXVMM_XCPT_UD_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_UD);
11804 if (VBOXVMM_XCPT_NM_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NM);
11805 if (VBOXVMM_XCPT_DF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_DF);
11806 if (VBOXVMM_XCPT_TS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_TS);
11807 if (VBOXVMM_XCPT_NP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_NP);
11808 if (VBOXVMM_XCPT_SS_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SS);
11809 if (VBOXVMM_XCPT_GP_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_GP);
11810 if (VBOXVMM_XCPT_PF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_PF);
11811 if (VBOXVMM_XCPT_MF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_MF);
11812 if (VBOXVMM_XCPT_AC_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_AC);
11813 if (VBOXVMM_XCPT_XF_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_XF);
11814 if (VBOXVMM_XCPT_VE_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_VE);
11815 if (VBOXVMM_XCPT_SX_ENABLED()) pDbgState->bmXcptExtra |= RT_BIT_32(X86_XCPT_SX);
11816
11817 if (pDbgState->bmXcptExtra)
11818 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_XCPT_OR_NMI);
11819
11820 /*
11821 * Process events and probes for VM-exits, making sure we get the wanted VM-exits.
11822 *
11823 * Note! This is the reverse of what hmR0VmxHandleExitDtraceEvents does.
11824 * So, when adding/changing/removing please don't forget to update it.
11825 *
11826 * Some of the macros are picking up local variables to save horizontal space,
11827 * (being able to see it in a table is the lesser evil here).
11828 */
11829#define IS_EITHER_ENABLED(a_pVM, a_EventSubName) \
11830 ( DBGF_IS_EVENT_ENABLED(a_pVM, RT_CONCAT(DBGFEVENT_, a_EventSubName)) \
11831 || RT_CONCAT3(VBOXVMM_, a_EventSubName, _ENABLED)() )
11832#define SET_ONLY_XBM_IF_EITHER_EN(a_EventSubName, a_uExit) \
11833 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11834 { AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11835 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11836 } else do { } while (0)
11837#define SET_CPE1_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec) \
11838 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11839 { \
11840 (pDbgState)->fCpe1Extra |= (a_fCtrlProcExec); \
11841 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11842 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11843 } else do { } while (0)
11844#define SET_CPEU_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fUnwantedCtrlProcExec) \
11845 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11846 { \
11847 (pDbgState)->fCpe1Unwanted |= (a_fUnwantedCtrlProcExec); \
11848 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11849 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11850 } else do { } while (0)
11851#define SET_CPE2_XBM_IF_EITHER_EN(a_EventSubName, a_uExit, a_fCtrlProcExec2) \
11852 if (IS_EITHER_ENABLED(pVM, a_EventSubName)) \
11853 { \
11854 (pDbgState)->fCpe2Extra |= (a_fCtrlProcExec2); \
11855 AssertCompile((unsigned)(a_uExit) < sizeof(pDbgState->bmExitsToCheck) * 8); \
11856 ASMBitSet((pDbgState)->bmExitsToCheck, a_uExit); \
11857 } else do { } while (0)
11858
11859 SET_ONLY_XBM_IF_EITHER_EN(EXIT_TASK_SWITCH, VMX_EXIT_TASK_SWITCH); /* unconditional */
11860 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_VIOLATION, VMX_EXIT_EPT_VIOLATION); /* unconditional */
11861 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_EPT_MISCONFIG, VMX_EXIT_EPT_MISCONFIG); /* unconditional (unless #VE) */
11862 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_ACCESS, VMX_EXIT_APIC_ACCESS); /* feature dependent, nothing to enable here */
11863 SET_ONLY_XBM_IF_EITHER_EN(EXIT_VMX_VAPIC_WRITE, VMX_EXIT_APIC_WRITE); /* feature dependent, nothing to enable here */
11864
11865 SET_ONLY_XBM_IF_EITHER_EN(INSTR_CPUID, VMX_EXIT_CPUID); /* unconditional */
11866 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CPUID, VMX_EXIT_CPUID);
11867 SET_ONLY_XBM_IF_EITHER_EN(INSTR_GETSEC, VMX_EXIT_GETSEC); /* unconditional */
11868 SET_ONLY_XBM_IF_EITHER_EN( EXIT_GETSEC, VMX_EXIT_GETSEC);
11869 SET_CPE1_XBM_IF_EITHER_EN(INSTR_HALT, VMX_EXIT_HLT, VMX_PROC_CTLS_HLT_EXIT); /* paranoia */
11870 SET_ONLY_XBM_IF_EITHER_EN( EXIT_HALT, VMX_EXIT_HLT);
11871 SET_ONLY_XBM_IF_EITHER_EN(INSTR_INVD, VMX_EXIT_INVD); /* unconditional */
11872 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVD, VMX_EXIT_INVD);
11873 SET_CPE1_XBM_IF_EITHER_EN(INSTR_INVLPG, VMX_EXIT_INVLPG, VMX_PROC_CTLS_INVLPG_EXIT);
11874 SET_ONLY_XBM_IF_EITHER_EN( EXIT_INVLPG, VMX_EXIT_INVLPG);
11875 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDPMC, VMX_EXIT_RDPMC, VMX_PROC_CTLS_RDPMC_EXIT);
11876 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDPMC, VMX_EXIT_RDPMC);
11877 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSC, VMX_EXIT_RDTSC, VMX_PROC_CTLS_RDTSC_EXIT);
11878 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSC, VMX_EXIT_RDTSC);
11879 SET_ONLY_XBM_IF_EITHER_EN(INSTR_RSM, VMX_EXIT_RSM); /* unconditional */
11880 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RSM, VMX_EXIT_RSM);
11881 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMM_CALL, VMX_EXIT_VMCALL); /* unconditional */
11882 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMM_CALL, VMX_EXIT_VMCALL);
11883 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMCLEAR, VMX_EXIT_VMCLEAR); /* unconditional */
11884 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMCLEAR, VMX_EXIT_VMCLEAR);
11885 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH); /* unconditional */
11886 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMLAUNCH, VMX_EXIT_VMLAUNCH);
11887 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRLD, VMX_EXIT_VMPTRLD); /* unconditional */
11888 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRLD, VMX_EXIT_VMPTRLD);
11889 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMPTRST, VMX_EXIT_VMPTRST); /* unconditional */
11890 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMPTRST, VMX_EXIT_VMPTRST);
11891 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMREAD, VMX_EXIT_VMREAD); /* unconditional */
11892 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMREAD, VMX_EXIT_VMREAD);
11893 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMRESUME, VMX_EXIT_VMRESUME); /* unconditional */
11894 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMRESUME, VMX_EXIT_VMRESUME);
11895 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMWRITE, VMX_EXIT_VMWRITE); /* unconditional */
11896 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMWRITE, VMX_EXIT_VMWRITE);
11897 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXOFF, VMX_EXIT_VMXOFF); /* unconditional */
11898 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXOFF, VMX_EXIT_VMXOFF);
11899 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMXON, VMX_EXIT_VMXON); /* unconditional */
11900 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMXON, VMX_EXIT_VMXON);
11901
11902 if ( IS_EITHER_ENABLED(pVM, INSTR_CRX_READ)
11903 || IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11904 {
11905 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR4
11906 | CPUMCTX_EXTRN_APIC_TPR);
11907 AssertRC(rc);
11908
11909#if 0 /** @todo fix me */
11910 pDbgState->fClearCr0Mask = true;
11911 pDbgState->fClearCr4Mask = true;
11912#endif
11913 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_READ))
11914 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_STORE_EXIT | VMX_PROC_CTLS_CR8_STORE_EXIT;
11915 if (IS_EITHER_ENABLED(pVM, INSTR_CRX_WRITE))
11916 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_CR3_LOAD_EXIT | VMX_PROC_CTLS_CR8_LOAD_EXIT;
11917 pDbgState->fCpe1Unwanted |= VMX_PROC_CTLS_USE_TPR_SHADOW; /* risky? */
11918 /* Note! We currently don't use VMX_VMCS32_CTRL_CR3_TARGET_COUNT. It would
11919 require clearing here and in the loop if we start using it. */
11920 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_CRX);
11921 }
11922 else
11923 {
11924 if (pDbgState->fClearCr0Mask)
11925 {
11926 pDbgState->fClearCr0Mask = false;
11927 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR0);
11928 }
11929 if (pDbgState->fClearCr4Mask)
11930 {
11931 pDbgState->fClearCr4Mask = false;
11932 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_CR4);
11933 }
11934 }
11935 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_READ, VMX_EXIT_MOV_CRX);
11936 SET_ONLY_XBM_IF_EITHER_EN( EXIT_CRX_WRITE, VMX_EXIT_MOV_CRX);
11937
11938 if ( IS_EITHER_ENABLED(pVM, INSTR_DRX_READ)
11939 || IS_EITHER_ENABLED(pVM, INSTR_DRX_WRITE))
11940 {
11941 /** @todo later, need to fix handler as it assumes this won't usually happen. */
11942 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_MOV_DRX);
11943 }
11944 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_READ, VMX_EXIT_MOV_DRX);
11945 SET_ONLY_XBM_IF_EITHER_EN( EXIT_DRX_WRITE, VMX_EXIT_MOV_DRX);
11946
11947 SET_CPEU_XBM_IF_EITHER_EN(INSTR_RDMSR, VMX_EXIT_RDMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS); /* risky clearing this? */
11948 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDMSR, VMX_EXIT_RDMSR);
11949 SET_CPEU_XBM_IF_EITHER_EN(INSTR_WRMSR, VMX_EXIT_WRMSR, VMX_PROC_CTLS_USE_MSR_BITMAPS);
11950 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WRMSR, VMX_EXIT_WRMSR);
11951 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MWAIT, VMX_EXIT_MWAIT, VMX_PROC_CTLS_MWAIT_EXIT); /* paranoia */
11952 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MWAIT, VMX_EXIT_MWAIT);
11953 SET_CPE1_XBM_IF_EITHER_EN(INSTR_MONITOR, VMX_EXIT_MONITOR, VMX_PROC_CTLS_MONITOR_EXIT); /* paranoia */
11954 SET_ONLY_XBM_IF_EITHER_EN( EXIT_MONITOR, VMX_EXIT_MONITOR);
11955#if 0 /** @todo too slow, fix handler. */
11956 SET_CPE1_XBM_IF_EITHER_EN(INSTR_PAUSE, VMX_EXIT_PAUSE, VMX_PROC_CTLS_PAUSE_EXIT);
11957#endif
11958 SET_ONLY_XBM_IF_EITHER_EN( EXIT_PAUSE, VMX_EXIT_PAUSE);
11959
11960 if ( IS_EITHER_ENABLED(pVM, INSTR_SGDT)
11961 || IS_EITHER_ENABLED(pVM, INSTR_SIDT)
11962 || IS_EITHER_ENABLED(pVM, INSTR_LGDT)
11963 || IS_EITHER_ENABLED(pVM, INSTR_LIDT))
11964 {
11965 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11966 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_GDTR_IDTR_ACCESS);
11967 }
11968 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11969 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11970 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LGDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11971 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LIDT, VMX_EXIT_GDTR_IDTR_ACCESS);
11972
11973 if ( IS_EITHER_ENABLED(pVM, INSTR_SLDT)
11974 || IS_EITHER_ENABLED(pVM, INSTR_STR)
11975 || IS_EITHER_ENABLED(pVM, INSTR_LLDT)
11976 || IS_EITHER_ENABLED(pVM, INSTR_LTR))
11977 {
11978 pDbgState->fCpe2Extra |= VMX_PROC_CTLS2_DESC_TABLE_EXIT;
11979 ASMBitSet(pDbgState->bmExitsToCheck, VMX_EXIT_LDTR_TR_ACCESS);
11980 }
11981 SET_ONLY_XBM_IF_EITHER_EN( EXIT_SLDT, VMX_EXIT_LDTR_TR_ACCESS);
11982 SET_ONLY_XBM_IF_EITHER_EN( EXIT_STR, VMX_EXIT_LDTR_TR_ACCESS);
11983 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LLDT, VMX_EXIT_LDTR_TR_ACCESS);
11984 SET_ONLY_XBM_IF_EITHER_EN( EXIT_LTR, VMX_EXIT_LDTR_TR_ACCESS);
11985
11986 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVEPT, VMX_EXIT_INVEPT); /* unconditional */
11987 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVEPT, VMX_EXIT_INVEPT);
11988 SET_CPE1_XBM_IF_EITHER_EN(INSTR_RDTSCP, VMX_EXIT_RDTSCP, VMX_PROC_CTLS_RDTSC_EXIT);
11989 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDTSCP, VMX_EXIT_RDTSCP);
11990 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_INVVPID, VMX_EXIT_INVVPID); /* unconditional */
11991 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVVPID, VMX_EXIT_INVVPID);
11992 SET_CPE2_XBM_IF_EITHER_EN(INSTR_WBINVD, VMX_EXIT_WBINVD, VMX_PROC_CTLS2_WBINVD_EXIT);
11993 SET_ONLY_XBM_IF_EITHER_EN( EXIT_WBINVD, VMX_EXIT_WBINVD);
11994 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSETBV, VMX_EXIT_XSETBV); /* unconditional */
11995 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XSETBV, VMX_EXIT_XSETBV);
11996 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDRAND, VMX_EXIT_RDRAND, VMX_PROC_CTLS2_RDRAND_EXIT);
11997 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDRAND, VMX_EXIT_RDRAND);
11998 SET_CPE1_XBM_IF_EITHER_EN(INSTR_VMX_INVPCID, VMX_EXIT_INVPCID, VMX_PROC_CTLS_INVLPG_EXIT);
11999 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_INVPCID, VMX_EXIT_INVPCID);
12000 SET_ONLY_XBM_IF_EITHER_EN(INSTR_VMX_VMFUNC, VMX_EXIT_VMFUNC); /* unconditional for the current setup */
12001 SET_ONLY_XBM_IF_EITHER_EN( EXIT_VMX_VMFUNC, VMX_EXIT_VMFUNC);
12002 SET_CPE2_XBM_IF_EITHER_EN(INSTR_RDSEED, VMX_EXIT_RDSEED, VMX_PROC_CTLS2_RDSEED_EXIT);
12003 SET_ONLY_XBM_IF_EITHER_EN( EXIT_RDSEED, VMX_EXIT_RDSEED);
12004 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XSAVES, VMX_EXIT_XSAVES); /* unconditional (enabled by host, guest cfg) */
12005 SET_ONLY_XBM_IF_EITHER_EN(EXIT_XSAVES, VMX_EXIT_XSAVES);
12006 SET_ONLY_XBM_IF_EITHER_EN(INSTR_XRSTORS, VMX_EXIT_XRSTORS); /* unconditional (enabled by host, guest cfg) */
12007 SET_ONLY_XBM_IF_EITHER_EN( EXIT_XRSTORS, VMX_EXIT_XRSTORS);
12008
12009#undef IS_EITHER_ENABLED
12010#undef SET_ONLY_XBM_IF_EITHER_EN
12011#undef SET_CPE1_XBM_IF_EITHER_EN
12012#undef SET_CPEU_XBM_IF_EITHER_EN
12013#undef SET_CPE2_XBM_IF_EITHER_EN
12014
12015 /*
12016 * Sanitize the control stuff.
12017 */
12018 pDbgState->fCpe2Extra &= g_HmMsrs.u.vmx.ProcCtls2.n.allowed1;
12019 if (pDbgState->fCpe2Extra)
12020 pDbgState->fCpe1Extra |= VMX_PROC_CTLS_USE_SECONDARY_CTLS;
12021 pDbgState->fCpe1Extra &= g_HmMsrs.u.vmx.ProcCtls.n.allowed1;
12022 pDbgState->fCpe1Unwanted &= ~g_HmMsrs.u.vmx.ProcCtls.n.allowed0;
12023 if (pVCpu->hmr0.s.fDebugWantRdTscExit != RT_BOOL(pDbgState->fCpe1Extra & VMX_PROC_CTLS_RDTSC_EXIT))
12024 {
12025 pVCpu->hmr0.s.fDebugWantRdTscExit ^= true;
12026 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
12027 }
12028
12029 Log6(("HM: debug state: cpe1=%#RX32 cpeu=%#RX32 cpe2=%#RX32%s%s\n",
12030 pDbgState->fCpe1Extra, pDbgState->fCpe1Unwanted, pDbgState->fCpe2Extra,
12031 pDbgState->fClearCr0Mask ? " clr-cr0" : "",
12032 pDbgState->fClearCr4Mask ? " clr-cr4" : ""));
12033}
12034
12035
12036/**
12037 * Fires off DBGF events and dtrace probes for a VM-exit, when it's
12038 * appropriate.
12039 *
12040 * The caller has checked the VM-exit against the
12041 * VMXRUNDBGSTATE::bmExitsToCheck bitmap. The caller has checked for NMIs
12042 * already, so we don't have to do that either.
12043 *
12044 * @returns Strict VBox status code (i.e. informational status codes too).
12045 * @param pVCpu The cross context virtual CPU structure.
12046 * @param pVmxTransient The VMX-transient structure.
12047 * @param uExitReason The VM-exit reason.
12048 *
12049 * @remarks The name of this function is displayed by dtrace, so keep it short
12050 * and to the point. No longer than 33 chars long, please.
12051 */
12052static VBOXSTRICTRC hmR0VmxHandleExitDtraceEvents(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uExitReason)
12053{
12054 /*
12055 * Translate the event into a DBGF event (enmEvent + uEventArg) and at the
12056 * same time check whether any corresponding Dtrace event is enabled (fDtrace).
12057 *
12058 * Note! This is the reverse operation of what hmR0VmxPreRunGuestDebugStateUpdate
12059 * does. Must add/change/remove both places. Same ordering, please.
12060 *
12061 * Added/removed events must also be reflected in the next section
12062 * where we dispatch dtrace events.
12063 */
12064 bool fDtrace1 = false;
12065 bool fDtrace2 = false;
12066 DBGFEVENTTYPE enmEvent1 = DBGFEVENT_END;
12067 DBGFEVENTTYPE enmEvent2 = DBGFEVENT_END;
12068 uint32_t uEventArg = 0;
12069#define SET_EXIT(a_EventSubName) \
12070 do { \
12071 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
12072 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
12073 } while (0)
12074#define SET_BOTH(a_EventSubName) \
12075 do { \
12076 enmEvent1 = RT_CONCAT(DBGFEVENT_INSTR_, a_EventSubName); \
12077 enmEvent2 = RT_CONCAT(DBGFEVENT_EXIT_, a_EventSubName); \
12078 fDtrace1 = RT_CONCAT3(VBOXVMM_INSTR_, a_EventSubName, _ENABLED)(); \
12079 fDtrace2 = RT_CONCAT3(VBOXVMM_EXIT_, a_EventSubName, _ENABLED)(); \
12080 } while (0)
12081 switch (uExitReason)
12082 {
12083 case VMX_EXIT_MTF:
12084 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
12085
12086 case VMX_EXIT_XCPT_OR_NMI:
12087 {
12088 uint8_t const idxVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
12089 switch (VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo))
12090 {
12091 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
12092 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
12093 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
12094 if (idxVector <= (unsigned)(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST))
12095 {
12096 if (VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uExitIntInfo))
12097 {
12098 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
12099 uEventArg = pVmxTransient->uExitIntErrorCode;
12100 }
12101 enmEvent1 = (DBGFEVENTTYPE)(DBGFEVENT_XCPT_FIRST + idxVector);
12102 switch (enmEvent1)
12103 {
12104 case DBGFEVENT_XCPT_DE: fDtrace1 = VBOXVMM_XCPT_DE_ENABLED(); break;
12105 case DBGFEVENT_XCPT_DB: fDtrace1 = VBOXVMM_XCPT_DB_ENABLED(); break;
12106 case DBGFEVENT_XCPT_BP: fDtrace1 = VBOXVMM_XCPT_BP_ENABLED(); break;
12107 case DBGFEVENT_XCPT_OF: fDtrace1 = VBOXVMM_XCPT_OF_ENABLED(); break;
12108 case DBGFEVENT_XCPT_BR: fDtrace1 = VBOXVMM_XCPT_BR_ENABLED(); break;
12109 case DBGFEVENT_XCPT_UD: fDtrace1 = VBOXVMM_XCPT_UD_ENABLED(); break;
12110 case DBGFEVENT_XCPT_NM: fDtrace1 = VBOXVMM_XCPT_NM_ENABLED(); break;
12111 case DBGFEVENT_XCPT_DF: fDtrace1 = VBOXVMM_XCPT_DF_ENABLED(); break;
12112 case DBGFEVENT_XCPT_TS: fDtrace1 = VBOXVMM_XCPT_TS_ENABLED(); break;
12113 case DBGFEVENT_XCPT_NP: fDtrace1 = VBOXVMM_XCPT_NP_ENABLED(); break;
12114 case DBGFEVENT_XCPT_SS: fDtrace1 = VBOXVMM_XCPT_SS_ENABLED(); break;
12115 case DBGFEVENT_XCPT_GP: fDtrace1 = VBOXVMM_XCPT_GP_ENABLED(); break;
12116 case DBGFEVENT_XCPT_PF: fDtrace1 = VBOXVMM_XCPT_PF_ENABLED(); break;
12117 case DBGFEVENT_XCPT_MF: fDtrace1 = VBOXVMM_XCPT_MF_ENABLED(); break;
12118 case DBGFEVENT_XCPT_AC: fDtrace1 = VBOXVMM_XCPT_AC_ENABLED(); break;
12119 case DBGFEVENT_XCPT_XF: fDtrace1 = VBOXVMM_XCPT_XF_ENABLED(); break;
12120 case DBGFEVENT_XCPT_VE: fDtrace1 = VBOXVMM_XCPT_VE_ENABLED(); break;
12121 case DBGFEVENT_XCPT_SX: fDtrace1 = VBOXVMM_XCPT_SX_ENABLED(); break;
12122 default: break;
12123 }
12124 }
12125 else
12126 AssertFailed();
12127 break;
12128
12129 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
12130 uEventArg = idxVector;
12131 enmEvent1 = DBGFEVENT_INTERRUPT_SOFTWARE;
12132 fDtrace1 = VBOXVMM_INT_SOFTWARE_ENABLED();
12133 break;
12134 }
12135 break;
12136 }
12137
12138 case VMX_EXIT_TRIPLE_FAULT:
12139 enmEvent1 = DBGFEVENT_TRIPLE_FAULT;
12140 //fDtrace1 = VBOXVMM_EXIT_TRIPLE_FAULT_ENABLED();
12141 break;
12142 case VMX_EXIT_TASK_SWITCH: SET_EXIT(TASK_SWITCH); break;
12143 case VMX_EXIT_EPT_VIOLATION: SET_EXIT(VMX_EPT_VIOLATION); break;
12144 case VMX_EXIT_EPT_MISCONFIG: SET_EXIT(VMX_EPT_MISCONFIG); break;
12145 case VMX_EXIT_APIC_ACCESS: SET_EXIT(VMX_VAPIC_ACCESS); break;
12146 case VMX_EXIT_APIC_WRITE: SET_EXIT(VMX_VAPIC_WRITE); break;
12147
12148 /* Instruction specific VM-exits: */
12149 case VMX_EXIT_CPUID: SET_BOTH(CPUID); break;
12150 case VMX_EXIT_GETSEC: SET_BOTH(GETSEC); break;
12151 case VMX_EXIT_HLT: SET_BOTH(HALT); break;
12152 case VMX_EXIT_INVD: SET_BOTH(INVD); break;
12153 case VMX_EXIT_INVLPG: SET_BOTH(INVLPG); break;
12154 case VMX_EXIT_RDPMC: SET_BOTH(RDPMC); break;
12155 case VMX_EXIT_RDTSC: SET_BOTH(RDTSC); break;
12156 case VMX_EXIT_RSM: SET_BOTH(RSM); break;
12157 case VMX_EXIT_VMCALL: SET_BOTH(VMM_CALL); break;
12158 case VMX_EXIT_VMCLEAR: SET_BOTH(VMX_VMCLEAR); break;
12159 case VMX_EXIT_VMLAUNCH: SET_BOTH(VMX_VMLAUNCH); break;
12160 case VMX_EXIT_VMPTRLD: SET_BOTH(VMX_VMPTRLD); break;
12161 case VMX_EXIT_VMPTRST: SET_BOTH(VMX_VMPTRST); break;
12162 case VMX_EXIT_VMREAD: SET_BOTH(VMX_VMREAD); break;
12163 case VMX_EXIT_VMRESUME: SET_BOTH(VMX_VMRESUME); break;
12164 case VMX_EXIT_VMWRITE: SET_BOTH(VMX_VMWRITE); break;
12165 case VMX_EXIT_VMXOFF: SET_BOTH(VMX_VMXOFF); break;
12166 case VMX_EXIT_VMXON: SET_BOTH(VMX_VMXON); break;
12167 case VMX_EXIT_MOV_CRX:
12168 hmR0VmxReadExitQualVmcs(pVmxTransient);
12169 if (VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_CRX_ACCESS_READ)
12170 SET_BOTH(CRX_READ);
12171 else
12172 SET_BOTH(CRX_WRITE);
12173 uEventArg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
12174 break;
12175 case VMX_EXIT_MOV_DRX:
12176 hmR0VmxReadExitQualVmcs(pVmxTransient);
12177 if ( VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual)
12178 == VMX_EXIT_QUAL_DRX_DIRECTION_READ)
12179 SET_BOTH(DRX_READ);
12180 else
12181 SET_BOTH(DRX_WRITE);
12182 uEventArg = VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual);
12183 break;
12184 case VMX_EXIT_RDMSR: SET_BOTH(RDMSR); break;
12185 case VMX_EXIT_WRMSR: SET_BOTH(WRMSR); break;
12186 case VMX_EXIT_MWAIT: SET_BOTH(MWAIT); break;
12187 case VMX_EXIT_MONITOR: SET_BOTH(MONITOR); break;
12188 case VMX_EXIT_PAUSE: SET_BOTH(PAUSE); break;
12189 case VMX_EXIT_GDTR_IDTR_ACCESS:
12190 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12191 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_XDTR_INSINFO_INSTR_ID))
12192 {
12193 case VMX_XDTR_INSINFO_II_SGDT: SET_BOTH(SGDT); break;
12194 case VMX_XDTR_INSINFO_II_SIDT: SET_BOTH(SIDT); break;
12195 case VMX_XDTR_INSINFO_II_LGDT: SET_BOTH(LGDT); break;
12196 case VMX_XDTR_INSINFO_II_LIDT: SET_BOTH(LIDT); break;
12197 }
12198 break;
12199
12200 case VMX_EXIT_LDTR_TR_ACCESS:
12201 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
12202 switch (RT_BF_GET(pVmxTransient->ExitInstrInfo.u, VMX_BF_YYTR_INSINFO_INSTR_ID))
12203 {
12204 case VMX_YYTR_INSINFO_II_SLDT: SET_BOTH(SLDT); break;
12205 case VMX_YYTR_INSINFO_II_STR: SET_BOTH(STR); break;
12206 case VMX_YYTR_INSINFO_II_LLDT: SET_BOTH(LLDT); break;
12207 case VMX_YYTR_INSINFO_II_LTR: SET_BOTH(LTR); break;
12208 }
12209 break;
12210
12211 case VMX_EXIT_INVEPT: SET_BOTH(VMX_INVEPT); break;
12212 case VMX_EXIT_RDTSCP: SET_BOTH(RDTSCP); break;
12213 case VMX_EXIT_INVVPID: SET_BOTH(VMX_INVVPID); break;
12214 case VMX_EXIT_WBINVD: SET_BOTH(WBINVD); break;
12215 case VMX_EXIT_XSETBV: SET_BOTH(XSETBV); break;
12216 case VMX_EXIT_RDRAND: SET_BOTH(RDRAND); break;
12217 case VMX_EXIT_INVPCID: SET_BOTH(VMX_INVPCID); break;
12218 case VMX_EXIT_VMFUNC: SET_BOTH(VMX_VMFUNC); break;
12219 case VMX_EXIT_RDSEED: SET_BOTH(RDSEED); break;
12220 case VMX_EXIT_XSAVES: SET_BOTH(XSAVES); break;
12221 case VMX_EXIT_XRSTORS: SET_BOTH(XRSTORS); break;
12222
12223 /* Events that aren't relevant at this point. */
12224 case VMX_EXIT_EXT_INT:
12225 case VMX_EXIT_INT_WINDOW:
12226 case VMX_EXIT_NMI_WINDOW:
12227 case VMX_EXIT_TPR_BELOW_THRESHOLD:
12228 case VMX_EXIT_PREEMPT_TIMER:
12229 case VMX_EXIT_IO_INSTR:
12230 break;
12231
12232 /* Errors and unexpected events. */
12233 case VMX_EXIT_INIT_SIGNAL:
12234 case VMX_EXIT_SIPI:
12235 case VMX_EXIT_IO_SMI:
12236 case VMX_EXIT_SMI:
12237 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12238 case VMX_EXIT_ERR_MSR_LOAD:
12239 case VMX_EXIT_ERR_MACHINE_CHECK:
12240 case VMX_EXIT_PML_FULL:
12241 case VMX_EXIT_VIRTUALIZED_EOI:
12242 break;
12243
12244 default:
12245 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12246 break;
12247 }
12248#undef SET_BOTH
12249#undef SET_EXIT
12250
12251 /*
12252 * Dtrace tracepoints go first. We do them here at once so we don't
12253 * have to copy the guest state saving and stuff a few dozen times.
12254 * Down side is that we've got to repeat the switch, though this time
12255 * we use enmEvent since the probes are a subset of what DBGF does.
12256 */
12257 if (fDtrace1 || fDtrace2)
12258 {
12259 hmR0VmxReadExitQualVmcs(pVmxTransient);
12260 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12261 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12262 switch (enmEvent1)
12263 {
12264 /** @todo consider which extra parameters would be helpful for each probe. */
12265 case DBGFEVENT_END: break;
12266 case DBGFEVENT_XCPT_DE: VBOXVMM_XCPT_DE(pVCpu, pCtx); break;
12267 case DBGFEVENT_XCPT_DB: VBOXVMM_XCPT_DB(pVCpu, pCtx, pCtx->dr[6]); break;
12268 case DBGFEVENT_XCPT_BP: VBOXVMM_XCPT_BP(pVCpu, pCtx); break;
12269 case DBGFEVENT_XCPT_OF: VBOXVMM_XCPT_OF(pVCpu, pCtx); break;
12270 case DBGFEVENT_XCPT_BR: VBOXVMM_XCPT_BR(pVCpu, pCtx); break;
12271 case DBGFEVENT_XCPT_UD: VBOXVMM_XCPT_UD(pVCpu, pCtx); break;
12272 case DBGFEVENT_XCPT_NM: VBOXVMM_XCPT_NM(pVCpu, pCtx); break;
12273 case DBGFEVENT_XCPT_DF: VBOXVMM_XCPT_DF(pVCpu, pCtx); break;
12274 case DBGFEVENT_XCPT_TS: VBOXVMM_XCPT_TS(pVCpu, pCtx, uEventArg); break;
12275 case DBGFEVENT_XCPT_NP: VBOXVMM_XCPT_NP(pVCpu, pCtx, uEventArg); break;
12276 case DBGFEVENT_XCPT_SS: VBOXVMM_XCPT_SS(pVCpu, pCtx, uEventArg); break;
12277 case DBGFEVENT_XCPT_GP: VBOXVMM_XCPT_GP(pVCpu, pCtx, uEventArg); break;
12278 case DBGFEVENT_XCPT_PF: VBOXVMM_XCPT_PF(pVCpu, pCtx, uEventArg, pCtx->cr2); break;
12279 case DBGFEVENT_XCPT_MF: VBOXVMM_XCPT_MF(pVCpu, pCtx); break;
12280 case DBGFEVENT_XCPT_AC: VBOXVMM_XCPT_AC(pVCpu, pCtx); break;
12281 case DBGFEVENT_XCPT_XF: VBOXVMM_XCPT_XF(pVCpu, pCtx); break;
12282 case DBGFEVENT_XCPT_VE: VBOXVMM_XCPT_VE(pVCpu, pCtx); break;
12283 case DBGFEVENT_XCPT_SX: VBOXVMM_XCPT_SX(pVCpu, pCtx, uEventArg); break;
12284 case DBGFEVENT_INTERRUPT_SOFTWARE: VBOXVMM_INT_SOFTWARE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12285 case DBGFEVENT_INSTR_CPUID: VBOXVMM_INSTR_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
12286 case DBGFEVENT_INSTR_GETSEC: VBOXVMM_INSTR_GETSEC(pVCpu, pCtx); break;
12287 case DBGFEVENT_INSTR_HALT: VBOXVMM_INSTR_HALT(pVCpu, pCtx); break;
12288 case DBGFEVENT_INSTR_INVD: VBOXVMM_INSTR_INVD(pVCpu, pCtx); break;
12289 case DBGFEVENT_INSTR_INVLPG: VBOXVMM_INSTR_INVLPG(pVCpu, pCtx); break;
12290 case DBGFEVENT_INSTR_RDPMC: VBOXVMM_INSTR_RDPMC(pVCpu, pCtx); break;
12291 case DBGFEVENT_INSTR_RDTSC: VBOXVMM_INSTR_RDTSC(pVCpu, pCtx); break;
12292 case DBGFEVENT_INSTR_RSM: VBOXVMM_INSTR_RSM(pVCpu, pCtx); break;
12293 case DBGFEVENT_INSTR_CRX_READ: VBOXVMM_INSTR_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12294 case DBGFEVENT_INSTR_CRX_WRITE: VBOXVMM_INSTR_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12295 case DBGFEVENT_INSTR_DRX_READ: VBOXVMM_INSTR_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12296 case DBGFEVENT_INSTR_DRX_WRITE: VBOXVMM_INSTR_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12297 case DBGFEVENT_INSTR_RDMSR: VBOXVMM_INSTR_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
12298 case DBGFEVENT_INSTR_WRMSR: VBOXVMM_INSTR_WRMSR(pVCpu, pCtx, pCtx->ecx,
12299 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
12300 case DBGFEVENT_INSTR_MWAIT: VBOXVMM_INSTR_MWAIT(pVCpu, pCtx); break;
12301 case DBGFEVENT_INSTR_MONITOR: VBOXVMM_INSTR_MONITOR(pVCpu, pCtx); break;
12302 case DBGFEVENT_INSTR_PAUSE: VBOXVMM_INSTR_PAUSE(pVCpu, pCtx); break;
12303 case DBGFEVENT_INSTR_SGDT: VBOXVMM_INSTR_SGDT(pVCpu, pCtx); break;
12304 case DBGFEVENT_INSTR_SIDT: VBOXVMM_INSTR_SIDT(pVCpu, pCtx); break;
12305 case DBGFEVENT_INSTR_LGDT: VBOXVMM_INSTR_LGDT(pVCpu, pCtx); break;
12306 case DBGFEVENT_INSTR_LIDT: VBOXVMM_INSTR_LIDT(pVCpu, pCtx); break;
12307 case DBGFEVENT_INSTR_SLDT: VBOXVMM_INSTR_SLDT(pVCpu, pCtx); break;
12308 case DBGFEVENT_INSTR_STR: VBOXVMM_INSTR_STR(pVCpu, pCtx); break;
12309 case DBGFEVENT_INSTR_LLDT: VBOXVMM_INSTR_LLDT(pVCpu, pCtx); break;
12310 case DBGFEVENT_INSTR_LTR: VBOXVMM_INSTR_LTR(pVCpu, pCtx); break;
12311 case DBGFEVENT_INSTR_RDTSCP: VBOXVMM_INSTR_RDTSCP(pVCpu, pCtx); break;
12312 case DBGFEVENT_INSTR_WBINVD: VBOXVMM_INSTR_WBINVD(pVCpu, pCtx); break;
12313 case DBGFEVENT_INSTR_XSETBV: VBOXVMM_INSTR_XSETBV(pVCpu, pCtx); break;
12314 case DBGFEVENT_INSTR_RDRAND: VBOXVMM_INSTR_RDRAND(pVCpu, pCtx); break;
12315 case DBGFEVENT_INSTR_RDSEED: VBOXVMM_INSTR_RDSEED(pVCpu, pCtx); break;
12316 case DBGFEVENT_INSTR_XSAVES: VBOXVMM_INSTR_XSAVES(pVCpu, pCtx); break;
12317 case DBGFEVENT_INSTR_XRSTORS: VBOXVMM_INSTR_XRSTORS(pVCpu, pCtx); break;
12318 case DBGFEVENT_INSTR_VMM_CALL: VBOXVMM_INSTR_VMM_CALL(pVCpu, pCtx); break;
12319 case DBGFEVENT_INSTR_VMX_VMCLEAR: VBOXVMM_INSTR_VMX_VMCLEAR(pVCpu, pCtx); break;
12320 case DBGFEVENT_INSTR_VMX_VMLAUNCH: VBOXVMM_INSTR_VMX_VMLAUNCH(pVCpu, pCtx); break;
12321 case DBGFEVENT_INSTR_VMX_VMPTRLD: VBOXVMM_INSTR_VMX_VMPTRLD(pVCpu, pCtx); break;
12322 case DBGFEVENT_INSTR_VMX_VMPTRST: VBOXVMM_INSTR_VMX_VMPTRST(pVCpu, pCtx); break;
12323 case DBGFEVENT_INSTR_VMX_VMREAD: VBOXVMM_INSTR_VMX_VMREAD(pVCpu, pCtx); break;
12324 case DBGFEVENT_INSTR_VMX_VMRESUME: VBOXVMM_INSTR_VMX_VMRESUME(pVCpu, pCtx); break;
12325 case DBGFEVENT_INSTR_VMX_VMWRITE: VBOXVMM_INSTR_VMX_VMWRITE(pVCpu, pCtx); break;
12326 case DBGFEVENT_INSTR_VMX_VMXOFF: VBOXVMM_INSTR_VMX_VMXOFF(pVCpu, pCtx); break;
12327 case DBGFEVENT_INSTR_VMX_VMXON: VBOXVMM_INSTR_VMX_VMXON(pVCpu, pCtx); break;
12328 case DBGFEVENT_INSTR_VMX_INVEPT: VBOXVMM_INSTR_VMX_INVEPT(pVCpu, pCtx); break;
12329 case DBGFEVENT_INSTR_VMX_INVVPID: VBOXVMM_INSTR_VMX_INVVPID(pVCpu, pCtx); break;
12330 case DBGFEVENT_INSTR_VMX_INVPCID: VBOXVMM_INSTR_VMX_INVPCID(pVCpu, pCtx); break;
12331 case DBGFEVENT_INSTR_VMX_VMFUNC: VBOXVMM_INSTR_VMX_VMFUNC(pVCpu, pCtx); break;
12332 default: AssertMsgFailed(("enmEvent1=%d uExitReason=%d\n", enmEvent1, uExitReason)); break;
12333 }
12334 switch (enmEvent2)
12335 {
12336 /** @todo consider which extra parameters would be helpful for each probe. */
12337 case DBGFEVENT_END: break;
12338 case DBGFEVENT_EXIT_TASK_SWITCH: VBOXVMM_EXIT_TASK_SWITCH(pVCpu, pCtx); break;
12339 case DBGFEVENT_EXIT_CPUID: VBOXVMM_EXIT_CPUID(pVCpu, pCtx, pCtx->eax, pCtx->ecx); break;
12340 case DBGFEVENT_EXIT_GETSEC: VBOXVMM_EXIT_GETSEC(pVCpu, pCtx); break;
12341 case DBGFEVENT_EXIT_HALT: VBOXVMM_EXIT_HALT(pVCpu, pCtx); break;
12342 case DBGFEVENT_EXIT_INVD: VBOXVMM_EXIT_INVD(pVCpu, pCtx); break;
12343 case DBGFEVENT_EXIT_INVLPG: VBOXVMM_EXIT_INVLPG(pVCpu, pCtx); break;
12344 case DBGFEVENT_EXIT_RDPMC: VBOXVMM_EXIT_RDPMC(pVCpu, pCtx); break;
12345 case DBGFEVENT_EXIT_RDTSC: VBOXVMM_EXIT_RDTSC(pVCpu, pCtx); break;
12346 case DBGFEVENT_EXIT_RSM: VBOXVMM_EXIT_RSM(pVCpu, pCtx); break;
12347 case DBGFEVENT_EXIT_CRX_READ: VBOXVMM_EXIT_CRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12348 case DBGFEVENT_EXIT_CRX_WRITE: VBOXVMM_EXIT_CRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12349 case DBGFEVENT_EXIT_DRX_READ: VBOXVMM_EXIT_DRX_READ(pVCpu, pCtx, (uint8_t)uEventArg); break;
12350 case DBGFEVENT_EXIT_DRX_WRITE: VBOXVMM_EXIT_DRX_WRITE(pVCpu, pCtx, (uint8_t)uEventArg); break;
12351 case DBGFEVENT_EXIT_RDMSR: VBOXVMM_EXIT_RDMSR(pVCpu, pCtx, pCtx->ecx); break;
12352 case DBGFEVENT_EXIT_WRMSR: VBOXVMM_EXIT_WRMSR(pVCpu, pCtx, pCtx->ecx,
12353 RT_MAKE_U64(pCtx->eax, pCtx->edx)); break;
12354 case DBGFEVENT_EXIT_MWAIT: VBOXVMM_EXIT_MWAIT(pVCpu, pCtx); break;
12355 case DBGFEVENT_EXIT_MONITOR: VBOXVMM_EXIT_MONITOR(pVCpu, pCtx); break;
12356 case DBGFEVENT_EXIT_PAUSE: VBOXVMM_EXIT_PAUSE(pVCpu, pCtx); break;
12357 case DBGFEVENT_EXIT_SGDT: VBOXVMM_EXIT_SGDT(pVCpu, pCtx); break;
12358 case DBGFEVENT_EXIT_SIDT: VBOXVMM_EXIT_SIDT(pVCpu, pCtx); break;
12359 case DBGFEVENT_EXIT_LGDT: VBOXVMM_EXIT_LGDT(pVCpu, pCtx); break;
12360 case DBGFEVENT_EXIT_LIDT: VBOXVMM_EXIT_LIDT(pVCpu, pCtx); break;
12361 case DBGFEVENT_EXIT_SLDT: VBOXVMM_EXIT_SLDT(pVCpu, pCtx); break;
12362 case DBGFEVENT_EXIT_STR: VBOXVMM_EXIT_STR(pVCpu, pCtx); break;
12363 case DBGFEVENT_EXIT_LLDT: VBOXVMM_EXIT_LLDT(pVCpu, pCtx); break;
12364 case DBGFEVENT_EXIT_LTR: VBOXVMM_EXIT_LTR(pVCpu, pCtx); break;
12365 case DBGFEVENT_EXIT_RDTSCP: VBOXVMM_EXIT_RDTSCP(pVCpu, pCtx); break;
12366 case DBGFEVENT_EXIT_WBINVD: VBOXVMM_EXIT_WBINVD(pVCpu, pCtx); break;
12367 case DBGFEVENT_EXIT_XSETBV: VBOXVMM_EXIT_XSETBV(pVCpu, pCtx); break;
12368 case DBGFEVENT_EXIT_RDRAND: VBOXVMM_EXIT_RDRAND(pVCpu, pCtx); break;
12369 case DBGFEVENT_EXIT_RDSEED: VBOXVMM_EXIT_RDSEED(pVCpu, pCtx); break;
12370 case DBGFEVENT_EXIT_XSAVES: VBOXVMM_EXIT_XSAVES(pVCpu, pCtx); break;
12371 case DBGFEVENT_EXIT_XRSTORS: VBOXVMM_EXIT_XRSTORS(pVCpu, pCtx); break;
12372 case DBGFEVENT_EXIT_VMM_CALL: VBOXVMM_EXIT_VMM_CALL(pVCpu, pCtx); break;
12373 case DBGFEVENT_EXIT_VMX_VMCLEAR: VBOXVMM_EXIT_VMX_VMCLEAR(pVCpu, pCtx); break;
12374 case DBGFEVENT_EXIT_VMX_VMLAUNCH: VBOXVMM_EXIT_VMX_VMLAUNCH(pVCpu, pCtx); break;
12375 case DBGFEVENT_EXIT_VMX_VMPTRLD: VBOXVMM_EXIT_VMX_VMPTRLD(pVCpu, pCtx); break;
12376 case DBGFEVENT_EXIT_VMX_VMPTRST: VBOXVMM_EXIT_VMX_VMPTRST(pVCpu, pCtx); break;
12377 case DBGFEVENT_EXIT_VMX_VMREAD: VBOXVMM_EXIT_VMX_VMREAD(pVCpu, pCtx); break;
12378 case DBGFEVENT_EXIT_VMX_VMRESUME: VBOXVMM_EXIT_VMX_VMRESUME(pVCpu, pCtx); break;
12379 case DBGFEVENT_EXIT_VMX_VMWRITE: VBOXVMM_EXIT_VMX_VMWRITE(pVCpu, pCtx); break;
12380 case DBGFEVENT_EXIT_VMX_VMXOFF: VBOXVMM_EXIT_VMX_VMXOFF(pVCpu, pCtx); break;
12381 case DBGFEVENT_EXIT_VMX_VMXON: VBOXVMM_EXIT_VMX_VMXON(pVCpu, pCtx); break;
12382 case DBGFEVENT_EXIT_VMX_INVEPT: VBOXVMM_EXIT_VMX_INVEPT(pVCpu, pCtx); break;
12383 case DBGFEVENT_EXIT_VMX_INVVPID: VBOXVMM_EXIT_VMX_INVVPID(pVCpu, pCtx); break;
12384 case DBGFEVENT_EXIT_VMX_INVPCID: VBOXVMM_EXIT_VMX_INVPCID(pVCpu, pCtx); break;
12385 case DBGFEVENT_EXIT_VMX_VMFUNC: VBOXVMM_EXIT_VMX_VMFUNC(pVCpu, pCtx); break;
12386 case DBGFEVENT_EXIT_VMX_EPT_MISCONFIG: VBOXVMM_EXIT_VMX_EPT_MISCONFIG(pVCpu, pCtx); break;
12387 case DBGFEVENT_EXIT_VMX_EPT_VIOLATION: VBOXVMM_EXIT_VMX_EPT_VIOLATION(pVCpu, pCtx); break;
12388 case DBGFEVENT_EXIT_VMX_VAPIC_ACCESS: VBOXVMM_EXIT_VMX_VAPIC_ACCESS(pVCpu, pCtx); break;
12389 case DBGFEVENT_EXIT_VMX_VAPIC_WRITE: VBOXVMM_EXIT_VMX_VAPIC_WRITE(pVCpu, pCtx); break;
12390 default: AssertMsgFailed(("enmEvent2=%d uExitReason=%d\n", enmEvent2, uExitReason)); break;
12391 }
12392 }
12393
12394 /*
12395 * Fire of the DBGF event, if enabled (our check here is just a quick one,
12396 * the DBGF call will do a full check).
12397 *
12398 * Note! DBGF sets DBGFEVENT_INTERRUPT_SOFTWARE in the bitmap.
12399 * Note! If we have to events, we prioritize the first, i.e. the instruction
12400 * one, in order to avoid event nesting.
12401 */
12402 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
12403 if ( enmEvent1 != DBGFEVENT_END
12404 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent1))
12405 {
12406 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12407 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent1, DBGFEVENTCTX_HM, 1, uEventArg);
12408 if (rcStrict != VINF_SUCCESS)
12409 return rcStrict;
12410 }
12411 else if ( enmEvent2 != DBGFEVENT_END
12412 && DBGF_IS_EVENT_ENABLED(pVM, enmEvent2))
12413 {
12414 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12415 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, enmEvent2, DBGFEVENTCTX_HM, 1, uEventArg);
12416 if (rcStrict != VINF_SUCCESS)
12417 return rcStrict;
12418 }
12419
12420 return VINF_SUCCESS;
12421}
12422
12423
12424/**
12425 * Single-stepping VM-exit filtering.
12426 *
12427 * This is preprocessing the VM-exits and deciding whether we've gotten far
12428 * enough to return VINF_EM_DBG_STEPPED already. If not, normal VM-exit
12429 * handling is performed.
12430 *
12431 * @returns Strict VBox status code (i.e. informational status codes too).
12432 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
12433 * @param pVmxTransient The VMX-transient structure.
12434 * @param pDbgState The debug state.
12435 */
12436DECLINLINE(VBOXSTRICTRC) hmR0VmxRunDebugHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PVMXRUNDBGSTATE pDbgState)
12437{
12438 /*
12439 * Expensive (saves context) generic dtrace VM-exit probe.
12440 */
12441 uint32_t const uExitReason = pVmxTransient->uExitReason;
12442 if (!VBOXVMM_R0_HMVMX_VMEXIT_ENABLED())
12443 { /* more likely */ }
12444 else
12445 {
12446 hmR0VmxReadExitQualVmcs(pVmxTransient);
12447 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
12448 AssertRC(rc);
12449 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, &pVCpu->cpum.GstCtx, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
12450 }
12451
12452 /*
12453 * Check for host NMI, just to get that out of the way.
12454 */
12455 if (uExitReason != VMX_EXIT_XCPT_OR_NMI)
12456 { /* normally likely */ }
12457 else
12458 {
12459 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
12460 uint32_t const uIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
12461 if (uIntType == VMX_EXIT_INT_INFO_TYPE_NMI)
12462 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
12463 }
12464
12465 /*
12466 * Check for single stepping event if we're stepping.
12467 */
12468 if (pVCpu->hm.s.fSingleInstruction)
12469 {
12470 switch (uExitReason)
12471 {
12472 case VMX_EXIT_MTF:
12473 return hmR0VmxExitMtf(pVCpu, pVmxTransient);
12474
12475 /* Various events: */
12476 case VMX_EXIT_XCPT_OR_NMI:
12477 case VMX_EXIT_EXT_INT:
12478 case VMX_EXIT_TRIPLE_FAULT:
12479 case VMX_EXIT_INT_WINDOW:
12480 case VMX_EXIT_NMI_WINDOW:
12481 case VMX_EXIT_TASK_SWITCH:
12482 case VMX_EXIT_TPR_BELOW_THRESHOLD:
12483 case VMX_EXIT_APIC_ACCESS:
12484 case VMX_EXIT_EPT_VIOLATION:
12485 case VMX_EXIT_EPT_MISCONFIG:
12486 case VMX_EXIT_PREEMPT_TIMER:
12487
12488 /* Instruction specific VM-exits: */
12489 case VMX_EXIT_CPUID:
12490 case VMX_EXIT_GETSEC:
12491 case VMX_EXIT_HLT:
12492 case VMX_EXIT_INVD:
12493 case VMX_EXIT_INVLPG:
12494 case VMX_EXIT_RDPMC:
12495 case VMX_EXIT_RDTSC:
12496 case VMX_EXIT_RSM:
12497 case VMX_EXIT_VMCALL:
12498 case VMX_EXIT_VMCLEAR:
12499 case VMX_EXIT_VMLAUNCH:
12500 case VMX_EXIT_VMPTRLD:
12501 case VMX_EXIT_VMPTRST:
12502 case VMX_EXIT_VMREAD:
12503 case VMX_EXIT_VMRESUME:
12504 case VMX_EXIT_VMWRITE:
12505 case VMX_EXIT_VMXOFF:
12506 case VMX_EXIT_VMXON:
12507 case VMX_EXIT_MOV_CRX:
12508 case VMX_EXIT_MOV_DRX:
12509 case VMX_EXIT_IO_INSTR:
12510 case VMX_EXIT_RDMSR:
12511 case VMX_EXIT_WRMSR:
12512 case VMX_EXIT_MWAIT:
12513 case VMX_EXIT_MONITOR:
12514 case VMX_EXIT_PAUSE:
12515 case VMX_EXIT_GDTR_IDTR_ACCESS:
12516 case VMX_EXIT_LDTR_TR_ACCESS:
12517 case VMX_EXIT_INVEPT:
12518 case VMX_EXIT_RDTSCP:
12519 case VMX_EXIT_INVVPID:
12520 case VMX_EXIT_WBINVD:
12521 case VMX_EXIT_XSETBV:
12522 case VMX_EXIT_RDRAND:
12523 case VMX_EXIT_INVPCID:
12524 case VMX_EXIT_VMFUNC:
12525 case VMX_EXIT_RDSEED:
12526 case VMX_EXIT_XSAVES:
12527 case VMX_EXIT_XRSTORS:
12528 {
12529 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12530 AssertRCReturn(rc, rc);
12531 if ( pVCpu->cpum.GstCtx.rip != pDbgState->uRipStart
12532 || pVCpu->cpum.GstCtx.cs.Sel != pDbgState->uCsStart)
12533 return VINF_EM_DBG_STEPPED;
12534 break;
12535 }
12536
12537 /* Errors and unexpected events: */
12538 case VMX_EXIT_INIT_SIGNAL:
12539 case VMX_EXIT_SIPI:
12540 case VMX_EXIT_IO_SMI:
12541 case VMX_EXIT_SMI:
12542 case VMX_EXIT_ERR_INVALID_GUEST_STATE:
12543 case VMX_EXIT_ERR_MSR_LOAD:
12544 case VMX_EXIT_ERR_MACHINE_CHECK:
12545 case VMX_EXIT_PML_FULL:
12546 case VMX_EXIT_VIRTUALIZED_EOI:
12547 case VMX_EXIT_APIC_WRITE: /* Some talk about this being fault like, so I guess we must process it? */
12548 break;
12549
12550 default:
12551 AssertMsgFailed(("Unexpected VM-exit=%#x\n", uExitReason));
12552 break;
12553 }
12554 }
12555
12556 /*
12557 * Check for debugger event breakpoints and dtrace probes.
12558 */
12559 if ( uExitReason < RT_ELEMENTS(pDbgState->bmExitsToCheck) * 32U
12560 && ASMBitTest(pDbgState->bmExitsToCheck, uExitReason) )
12561 {
12562 VBOXSTRICTRC rcStrict = hmR0VmxHandleExitDtraceEvents(pVCpu, pVmxTransient, uExitReason);
12563 if (rcStrict != VINF_SUCCESS)
12564 return rcStrict;
12565 }
12566
12567 /*
12568 * Normal processing.
12569 */
12570#ifdef HMVMX_USE_FUNCTION_TABLE
12571 return g_aVMExitHandlers[uExitReason].pfn(pVCpu, pVmxTransient);
12572#else
12573 return hmR0VmxHandleExit(pVCpu, pVmxTransient, uExitReason);
12574#endif
12575}
12576
12577
12578/**
12579 * Single steps guest code using hardware-assisted VMX.
12580 *
12581 * This is -not- the same as the guest single-stepping itself (say using EFLAGS.TF)
12582 * but single-stepping through the hypervisor debugger.
12583 *
12584 * @returns Strict VBox status code (i.e. informational status codes too).
12585 * @param pVCpu The cross context virtual CPU structure.
12586 * @param pcLoops Pointer to the number of executed loops.
12587 *
12588 * @note Mostly the same as hmR0VmxRunGuestCodeNormal().
12589 */
12590static VBOXSTRICTRC hmR0VmxRunGuestCodeDebug(PVMCPUCC pVCpu, uint32_t *pcLoops)
12591{
12592 uint32_t const cMaxResumeLoops = pVCpu->CTX_SUFF(pVM)->hmr0.s.cMaxResumeLoops;
12593 Assert(pcLoops);
12594 Assert(*pcLoops <= cMaxResumeLoops);
12595
12596 VMXTRANSIENT VmxTransient;
12597 RT_ZERO(VmxTransient);
12598 VmxTransient.pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
12599
12600 /* Set HMCPU indicators. */
12601 bool const fSavedSingleInstruction = pVCpu->hm.s.fSingleInstruction;
12602 pVCpu->hm.s.fSingleInstruction = pVCpu->hm.s.fSingleInstruction || DBGFIsStepping(pVCpu);
12603 pVCpu->hmr0.s.fDebugWantRdTscExit = false;
12604 pVCpu->hmr0.s.fUsingDebugLoop = true;
12605
12606 /* State we keep to help modify and later restore the VMCS fields we alter, and for detecting steps. */
12607 VMXRUNDBGSTATE DbgState;
12608 hmR0VmxRunDebugStateInit(pVCpu, &VmxTransient, &DbgState);
12609 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12610
12611 /*
12612 * The loop.
12613 */
12614 VBOXSTRICTRC rcStrict = VERR_INTERNAL_ERROR_5;
12615 for (;;)
12616 {
12617 Assert(!HMR0SuspendPending());
12618 HMVMX_ASSERT_CPU_SAFE(pVCpu);
12619 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
12620 bool fStepping = pVCpu->hm.s.fSingleInstruction;
12621
12622 /* Set up VM-execution controls the next two can respond to. */
12623 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12624
12625 /*
12626 * Preparatory work for running guest code, this may force us to
12627 * return to ring-3.
12628 *
12629 * Warning! This bugger disables interrupts on VINF_SUCCESS!
12630 */
12631 rcStrict = hmR0VmxPreRunGuest(pVCpu, &VmxTransient, fStepping);
12632 if (rcStrict != VINF_SUCCESS)
12633 break;
12634
12635 /* Interrupts are disabled at this point! */
12636 hmR0VmxPreRunGuestCommitted(pVCpu, &VmxTransient);
12637
12638 /* Override any obnoxious code in the above two calls. */
12639 hmR0VmxPreRunGuestDebugStateApply(pVCpu, &VmxTransient, &DbgState);
12640
12641 /*
12642 * Finally execute the guest.
12643 */
12644 int rcRun = hmR0VmxRunGuest(pVCpu, &VmxTransient);
12645
12646 hmR0VmxPostRunGuest(pVCpu, &VmxTransient, rcRun);
12647 /* Interrupts are re-enabled at this point! */
12648
12649 /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
12650 if (RT_SUCCESS(rcRun))
12651 { /* very likely */ }
12652 else
12653 {
12654 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatPreExit, x);
12655 hmR0VmxReportWorldSwitchError(pVCpu, rcRun, &VmxTransient);
12656 return rcRun;
12657 }
12658
12659 /* Profile the VM-exit. */
12660 AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
12661 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
12662 STAM_COUNTER_INC(&pVCpu->hm.s.aStatExitReason[VmxTransient.uExitReason & MASK_EXITREASON_STAT]);
12663 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatPreExit, &pVCpu->hm.s.StatExitHandling, x);
12664 HMVMX_START_EXIT_DISPATCH_PROF();
12665
12666 VBOXVMM_R0_HMVMX_VMEXIT_NOCTX(pVCpu, &pVCpu->cpum.GstCtx, VmxTransient.uExitReason);
12667
12668 /*
12669 * Handle the VM-exit - we quit earlier on certain VM-exits, see hmR0VmxHandleExitDebug().
12670 */
12671 rcStrict = hmR0VmxRunDebugHandleExit(pVCpu, &VmxTransient, &DbgState);
12672 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitHandling, x);
12673 if (rcStrict != VINF_SUCCESS)
12674 break;
12675 if (++(*pcLoops) > cMaxResumeLoops)
12676 {
12677 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
12678 rcStrict = VINF_EM_RAW_INTERRUPT;
12679 break;
12680 }
12681
12682 /*
12683 * Stepping: Did the RIP change, if so, consider it a single step.
12684 * Otherwise, make sure one of the TFs gets set.
12685 */
12686 if (fStepping)
12687 {
12688 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
12689 AssertRC(rc);
12690 if ( pVCpu->cpum.GstCtx.rip != DbgState.uRipStart
12691 || pVCpu->cpum.GstCtx.cs.Sel != DbgState.uCsStart)
12692 {
12693 rcStrict = VINF_EM_DBG_STEPPED;
12694 break;
12695 }
12696 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
12697 }
12698
12699 /*
12700 * Update when dtrace settings changes (DBGF kicks us, so no need to check).
12701 */
12702 if (VBOXVMM_GET_SETTINGS_SEQ_NO() != DbgState.uDtraceSettingsSeqNo)
12703 hmR0VmxPreRunGuestDebugStateUpdate(pVCpu, &VmxTransient, &DbgState);
12704
12705 /* Restore all controls applied by hmR0VmxPreRunGuestDebugStateApply above. */
12706 rcStrict = hmR0VmxRunDebugStateRevert(pVCpu, &VmxTransient, &DbgState, rcStrict);
12707 Assert(rcStrict == VINF_SUCCESS);
12708 }
12709
12710 /*
12711 * Clear the X86_EFL_TF if necessary.
12712 */
12713 if (pVCpu->hmr0.s.fClearTrapFlag)
12714 {
12715 int rc = hmR0VmxImportGuestState(pVCpu, VmxTransient.pVmcsInfo, CPUMCTX_EXTRN_RFLAGS);
12716 AssertRC(rc);
12717 pVCpu->hmr0.s.fClearTrapFlag = false;
12718 pVCpu->cpum.GstCtx.eflags.Bits.u1TF = 0;
12719 }
12720 /** @todo there seems to be issues with the resume flag when the monitor trap
12721 * flag is pending without being used. Seen early in bios init when
12722 * accessing APIC page in protected mode. */
12723
12724 /* Restore HMCPU indicators. */
12725 pVCpu->hmr0.s.fUsingDebugLoop = false;
12726 pVCpu->hmr0.s.fDebugWantRdTscExit = false;
12727 pVCpu->hm.s.fSingleInstruction = fSavedSingleInstruction;
12728
12729 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
12730 return rcStrict;
12731}
12732
12733
12734/** @} */
12735
12736
12737/**
12738 * Checks if any expensive dtrace probes are enabled and we should go to the
12739 * debug loop.
12740 *
12741 * @returns true if we should use debug loop, false if not.
12742 */
12743static bool hmR0VmxAnyExpensiveProbesEnabled(void)
12744{
12745 /* It's probably faster to OR the raw 32-bit counter variables together.
12746 Since the variables are in an array and the probes are next to one
12747 another (more or less), we have good locality. So, better read
12748 eight-nine cache lines ever time and only have one conditional, than
12749 128+ conditionals, right? */
12750 return ( VBOXVMM_R0_HMVMX_VMEXIT_ENABLED_RAW() /* expensive too due to context */
12751 | VBOXVMM_XCPT_DE_ENABLED_RAW()
12752 | VBOXVMM_XCPT_DB_ENABLED_RAW()
12753 | VBOXVMM_XCPT_BP_ENABLED_RAW()
12754 | VBOXVMM_XCPT_OF_ENABLED_RAW()
12755 | VBOXVMM_XCPT_BR_ENABLED_RAW()
12756 | VBOXVMM_XCPT_UD_ENABLED_RAW()
12757 | VBOXVMM_XCPT_NM_ENABLED_RAW()
12758 | VBOXVMM_XCPT_DF_ENABLED_RAW()
12759 | VBOXVMM_XCPT_TS_ENABLED_RAW()
12760 | VBOXVMM_XCPT_NP_ENABLED_RAW()
12761 | VBOXVMM_XCPT_SS_ENABLED_RAW()
12762 | VBOXVMM_XCPT_GP_ENABLED_RAW()
12763 | VBOXVMM_XCPT_PF_ENABLED_RAW()
12764 | VBOXVMM_XCPT_MF_ENABLED_RAW()
12765 | VBOXVMM_XCPT_AC_ENABLED_RAW()
12766 | VBOXVMM_XCPT_XF_ENABLED_RAW()
12767 | VBOXVMM_XCPT_VE_ENABLED_RAW()
12768 | VBOXVMM_XCPT_SX_ENABLED_RAW()
12769 | VBOXVMM_INT_SOFTWARE_ENABLED_RAW()
12770 | VBOXVMM_INT_HARDWARE_ENABLED_RAW()
12771 ) != 0
12772 || ( VBOXVMM_INSTR_HALT_ENABLED_RAW()
12773 | VBOXVMM_INSTR_MWAIT_ENABLED_RAW()
12774 | VBOXVMM_INSTR_MONITOR_ENABLED_RAW()
12775 | VBOXVMM_INSTR_CPUID_ENABLED_RAW()
12776 | VBOXVMM_INSTR_INVD_ENABLED_RAW()
12777 | VBOXVMM_INSTR_WBINVD_ENABLED_RAW()
12778 | VBOXVMM_INSTR_INVLPG_ENABLED_RAW()
12779 | VBOXVMM_INSTR_RDTSC_ENABLED_RAW()
12780 | VBOXVMM_INSTR_RDTSCP_ENABLED_RAW()
12781 | VBOXVMM_INSTR_RDPMC_ENABLED_RAW()
12782 | VBOXVMM_INSTR_RDMSR_ENABLED_RAW()
12783 | VBOXVMM_INSTR_WRMSR_ENABLED_RAW()
12784 | VBOXVMM_INSTR_CRX_READ_ENABLED_RAW()
12785 | VBOXVMM_INSTR_CRX_WRITE_ENABLED_RAW()
12786 | VBOXVMM_INSTR_DRX_READ_ENABLED_RAW()
12787 | VBOXVMM_INSTR_DRX_WRITE_ENABLED_RAW()
12788 | VBOXVMM_INSTR_PAUSE_ENABLED_RAW()
12789 | VBOXVMM_INSTR_XSETBV_ENABLED_RAW()
12790 | VBOXVMM_INSTR_SIDT_ENABLED_RAW()
12791 | VBOXVMM_INSTR_LIDT_ENABLED_RAW()
12792 | VBOXVMM_INSTR_SGDT_ENABLED_RAW()
12793 | VBOXVMM_INSTR_LGDT_ENABLED_RAW()
12794 | VBOXVMM_INSTR_SLDT_ENABLED_RAW()
12795 | VBOXVMM_INSTR_LLDT_ENABLED_RAW()
12796 | VBOXVMM_INSTR_STR_ENABLED_RAW()
12797 | VBOXVMM_INSTR_LTR_ENABLED_RAW()
12798 | VBOXVMM_INSTR_GETSEC_ENABLED_RAW()
12799 | VBOXVMM_INSTR_RSM_ENABLED_RAW()
12800 | VBOXVMM_INSTR_RDRAND_ENABLED_RAW()
12801 | VBOXVMM_INSTR_RDSEED_ENABLED_RAW()
12802 | VBOXVMM_INSTR_XSAVES_ENABLED_RAW()
12803 | VBOXVMM_INSTR_XRSTORS_ENABLED_RAW()
12804 | VBOXVMM_INSTR_VMM_CALL_ENABLED_RAW()
12805 | VBOXVMM_INSTR_VMX_VMCLEAR_ENABLED_RAW()
12806 | VBOXVMM_INSTR_VMX_VMLAUNCH_ENABLED_RAW()
12807 | VBOXVMM_INSTR_VMX_VMPTRLD_ENABLED_RAW()
12808 | VBOXVMM_INSTR_VMX_VMPTRST_ENABLED_RAW()
12809 | VBOXVMM_INSTR_VMX_VMREAD_ENABLED_RAW()
12810 | VBOXVMM_INSTR_VMX_VMRESUME_ENABLED_RAW()
12811 | VBOXVMM_INSTR_VMX_VMWRITE_ENABLED_RAW()
12812 | VBOXVMM_INSTR_VMX_VMXOFF_ENABLED_RAW()
12813 | VBOXVMM_INSTR_VMX_VMXON_ENABLED_RAW()
12814 | VBOXVMM_INSTR_VMX_VMFUNC_ENABLED_RAW()
12815 | VBOXVMM_INSTR_VMX_INVEPT_ENABLED_RAW()
12816 | VBOXVMM_INSTR_VMX_INVVPID_ENABLED_RAW()
12817 | VBOXVMM_INSTR_VMX_INVPCID_ENABLED_RAW()
12818 ) != 0
12819 || ( VBOXVMM_EXIT_TASK_SWITCH_ENABLED_RAW()
12820 | VBOXVMM_EXIT_HALT_ENABLED_RAW()
12821 | VBOXVMM_EXIT_MWAIT_ENABLED_RAW()
12822 | VBOXVMM_EXIT_MONITOR_ENABLED_RAW()
12823 | VBOXVMM_EXIT_CPUID_ENABLED_RAW()
12824 | VBOXVMM_EXIT_INVD_ENABLED_RAW()
12825 | VBOXVMM_EXIT_WBINVD_ENABLED_RAW()
12826 | VBOXVMM_EXIT_INVLPG_ENABLED_RAW()
12827 | VBOXVMM_EXIT_RDTSC_ENABLED_RAW()
12828 | VBOXVMM_EXIT_RDTSCP_ENABLED_RAW()
12829 | VBOXVMM_EXIT_RDPMC_ENABLED_RAW()
12830 | VBOXVMM_EXIT_RDMSR_ENABLED_RAW()
12831 | VBOXVMM_EXIT_WRMSR_ENABLED_RAW()
12832 | VBOXVMM_EXIT_CRX_READ_ENABLED_RAW()
12833 | VBOXVMM_EXIT_CRX_WRITE_ENABLED_RAW()
12834 | VBOXVMM_EXIT_DRX_READ_ENABLED_RAW()
12835 | VBOXVMM_EXIT_DRX_WRITE_ENABLED_RAW()
12836 | VBOXVMM_EXIT_PAUSE_ENABLED_RAW()
12837 | VBOXVMM_EXIT_XSETBV_ENABLED_RAW()
12838 | VBOXVMM_EXIT_SIDT_ENABLED_RAW()
12839 | VBOXVMM_EXIT_LIDT_ENABLED_RAW()
12840 | VBOXVMM_EXIT_SGDT_ENABLED_RAW()
12841 | VBOXVMM_EXIT_LGDT_ENABLED_RAW()
12842 | VBOXVMM_EXIT_SLDT_ENABLED_RAW()
12843 | VBOXVMM_EXIT_LLDT_ENABLED_RAW()
12844 | VBOXVMM_EXIT_STR_ENABLED_RAW()
12845 | VBOXVMM_EXIT_LTR_ENABLED_RAW()
12846 | VBOXVMM_EXIT_GETSEC_ENABLED_RAW()
12847 | VBOXVMM_EXIT_RSM_ENABLED_RAW()
12848 | VBOXVMM_EXIT_RDRAND_ENABLED_RAW()
12849 | VBOXVMM_EXIT_RDSEED_ENABLED_RAW()
12850 | VBOXVMM_EXIT_XSAVES_ENABLED_RAW()
12851 | VBOXVMM_EXIT_XRSTORS_ENABLED_RAW()
12852 | VBOXVMM_EXIT_VMM_CALL_ENABLED_RAW()
12853 | VBOXVMM_EXIT_VMX_VMCLEAR_ENABLED_RAW()
12854 | VBOXVMM_EXIT_VMX_VMLAUNCH_ENABLED_RAW()
12855 | VBOXVMM_EXIT_VMX_VMPTRLD_ENABLED_RAW()
12856 | VBOXVMM_EXIT_VMX_VMPTRST_ENABLED_RAW()
12857 | VBOXVMM_EXIT_VMX_VMREAD_ENABLED_RAW()
12858 | VBOXVMM_EXIT_VMX_VMRESUME_ENABLED_RAW()
12859 | VBOXVMM_EXIT_VMX_VMWRITE_ENABLED_RAW()
12860 | VBOXVMM_EXIT_VMX_VMXOFF_ENABLED_RAW()
12861 | VBOXVMM_EXIT_VMX_VMXON_ENABLED_RAW()
12862 | VBOXVMM_EXIT_VMX_VMFUNC_ENABLED_RAW()
12863 | VBOXVMM_EXIT_VMX_INVEPT_ENABLED_RAW()
12864 | VBOXVMM_EXIT_VMX_INVVPID_ENABLED_RAW()
12865 | VBOXVMM_EXIT_VMX_INVPCID_ENABLED_RAW()
12866 | VBOXVMM_EXIT_VMX_EPT_VIOLATION_ENABLED_RAW()
12867 | VBOXVMM_EXIT_VMX_EPT_MISCONFIG_ENABLED_RAW()
12868 | VBOXVMM_EXIT_VMX_VAPIC_ACCESS_ENABLED_RAW()
12869 | VBOXVMM_EXIT_VMX_VAPIC_WRITE_ENABLED_RAW()
12870 ) != 0;
12871}
12872
12873
12874/**
12875 * Runs the guest using hardware-assisted VMX.
12876 *
12877 * @returns Strict VBox status code (i.e. informational status codes too).
12878 * @param pVCpu The cross context virtual CPU structure.
12879 */
12880VMMR0DECL(VBOXSTRICTRC) VMXR0RunGuestCode(PVMCPUCC pVCpu)
12881{
12882 AssertPtr(pVCpu);
12883 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
12884 Assert(VMMRZCallRing3IsEnabled(pVCpu));
12885 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12886 HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
12887
12888 VBOXSTRICTRC rcStrict;
12889 uint32_t cLoops = 0;
12890 for (;;)
12891 {
12892#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12893 bool const fInNestedGuestMode = CPUMIsGuestInVmxNonRootMode(pCtx);
12894#else
12895 NOREF(pCtx);
12896 bool const fInNestedGuestMode = false;
12897#endif
12898 if (!fInNestedGuestMode)
12899 {
12900 if ( !pVCpu->hm.s.fUseDebugLoop
12901 && (!VBOXVMM_ANY_PROBES_ENABLED() || !hmR0VmxAnyExpensiveProbesEnabled())
12902 && !DBGFIsStepping(pVCpu)
12903 && !pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
12904 rcStrict = hmR0VmxRunGuestCodeNormal(pVCpu, &cLoops);
12905 else
12906 rcStrict = hmR0VmxRunGuestCodeDebug(pVCpu, &cLoops);
12907 }
12908#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
12909 else
12910 rcStrict = hmR0VmxRunGuestCodeNested(pVCpu, &cLoops);
12911
12912 if (rcStrict == VINF_VMX_VMLAUNCH_VMRESUME)
12913 {
12914 Assert(CPUMIsGuestInVmxNonRootMode(pCtx));
12915 continue;
12916 }
12917 if (rcStrict == VINF_VMX_VMEXIT)
12918 {
12919 Assert(!CPUMIsGuestInVmxNonRootMode(pCtx));
12920 continue;
12921 }
12922#endif
12923 break;
12924 }
12925
12926 int const rcLoop = VBOXSTRICTRC_VAL(rcStrict);
12927 switch (rcLoop)
12928 {
12929 case VERR_EM_INTERPRETER: rcStrict = VINF_EM_RAW_EMULATE_INSTR; break;
12930 case VINF_EM_RESET: rcStrict = VINF_EM_TRIPLE_FAULT; break;
12931 }
12932
12933 int rc2 = hmR0VmxExitToRing3(pVCpu, rcStrict);
12934 if (RT_FAILURE(rc2))
12935 {
12936 pVCpu->hm.s.u32HMError = (uint32_t)VBOXSTRICTRC_VAL(rcStrict);
12937 rcStrict = rc2;
12938 }
12939 Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
12940 Assert(!VMMR0AssertionIsNotificationSet(pVCpu));
12941 return rcStrict;
12942}
12943
12944
12945#ifndef HMVMX_USE_FUNCTION_TABLE
12946/**
12947 * Handles a guest VM-exit from hardware-assisted VMX execution.
12948 *
12949 * @returns Strict VBox status code (i.e. informational status codes too).
12950 * @param pVCpu The cross context virtual CPU structure.
12951 * @param pVmxTransient The VMX-transient structure.
12952 */
12953DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExit(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
12954{
12955#ifdef DEBUG_ramshankar
12956# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) \
12957 do { \
12958 if (a_fSave != 0) \
12959 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
12960 VBOXSTRICTRC rcStrict = a_CallExpr; \
12961 if (a_fSave != 0) \
12962 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST); \
12963 return rcStrict; \
12964 } while (0)
12965#else
12966# define VMEXIT_CALL_RET(a_fSave, a_CallExpr) return a_CallExpr
12967#endif
12968 uint32_t const uExitReason = pVmxTransient->uExitReason;
12969 switch (uExitReason)
12970 {
12971 case VMX_EXIT_EPT_MISCONFIG: VMEXIT_CALL_RET(0, hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient));
12972 case VMX_EXIT_EPT_VIOLATION: VMEXIT_CALL_RET(0, hmR0VmxExitEptViolation(pVCpu, pVmxTransient));
12973 case VMX_EXIT_IO_INSTR: VMEXIT_CALL_RET(0, hmR0VmxExitIoInstr(pVCpu, pVmxTransient));
12974 case VMX_EXIT_CPUID: VMEXIT_CALL_RET(0, hmR0VmxExitCpuid(pVCpu, pVmxTransient));
12975 case VMX_EXIT_RDTSC: VMEXIT_CALL_RET(0, hmR0VmxExitRdtsc(pVCpu, pVmxTransient));
12976 case VMX_EXIT_RDTSCP: VMEXIT_CALL_RET(0, hmR0VmxExitRdtscp(pVCpu, pVmxTransient));
12977 case VMX_EXIT_APIC_ACCESS: VMEXIT_CALL_RET(0, hmR0VmxExitApicAccess(pVCpu, pVmxTransient));
12978 case VMX_EXIT_XCPT_OR_NMI: VMEXIT_CALL_RET(0, hmR0VmxExitXcptOrNmi(pVCpu, pVmxTransient));
12979 case VMX_EXIT_MOV_CRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovCRx(pVCpu, pVmxTransient));
12980 case VMX_EXIT_EXT_INT: VMEXIT_CALL_RET(0, hmR0VmxExitExtInt(pVCpu, pVmxTransient));
12981 case VMX_EXIT_INT_WINDOW: VMEXIT_CALL_RET(0, hmR0VmxExitIntWindow(pVCpu, pVmxTransient));
12982 case VMX_EXIT_TPR_BELOW_THRESHOLD: VMEXIT_CALL_RET(0, hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient));
12983 case VMX_EXIT_MWAIT: VMEXIT_CALL_RET(0, hmR0VmxExitMwait(pVCpu, pVmxTransient));
12984 case VMX_EXIT_MONITOR: VMEXIT_CALL_RET(0, hmR0VmxExitMonitor(pVCpu, pVmxTransient));
12985 case VMX_EXIT_TASK_SWITCH: VMEXIT_CALL_RET(0, hmR0VmxExitTaskSwitch(pVCpu, pVmxTransient));
12986 case VMX_EXIT_PREEMPT_TIMER: VMEXIT_CALL_RET(0, hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient));
12987 case VMX_EXIT_RDMSR: VMEXIT_CALL_RET(0, hmR0VmxExitRdmsr(pVCpu, pVmxTransient));
12988 case VMX_EXIT_WRMSR: VMEXIT_CALL_RET(0, hmR0VmxExitWrmsr(pVCpu, pVmxTransient));
12989 case VMX_EXIT_VMCALL: VMEXIT_CALL_RET(0, hmR0VmxExitVmcall(pVCpu, pVmxTransient));
12990 case VMX_EXIT_MOV_DRX: VMEXIT_CALL_RET(0, hmR0VmxExitMovDRx(pVCpu, pVmxTransient));
12991 case VMX_EXIT_HLT: VMEXIT_CALL_RET(0, hmR0VmxExitHlt(pVCpu, pVmxTransient));
12992 case VMX_EXIT_INVD: VMEXIT_CALL_RET(0, hmR0VmxExitInvd(pVCpu, pVmxTransient));
12993 case VMX_EXIT_INVLPG: VMEXIT_CALL_RET(0, hmR0VmxExitInvlpg(pVCpu, pVmxTransient));
12994 case VMX_EXIT_MTF: VMEXIT_CALL_RET(0, hmR0VmxExitMtf(pVCpu, pVmxTransient));
12995 case VMX_EXIT_PAUSE: VMEXIT_CALL_RET(0, hmR0VmxExitPause(pVCpu, pVmxTransient));
12996 case VMX_EXIT_WBINVD: VMEXIT_CALL_RET(0, hmR0VmxExitWbinvd(pVCpu, pVmxTransient));
12997 case VMX_EXIT_XSETBV: VMEXIT_CALL_RET(0, hmR0VmxExitXsetbv(pVCpu, pVmxTransient));
12998 case VMX_EXIT_INVPCID: VMEXIT_CALL_RET(0, hmR0VmxExitInvpcid(pVCpu, pVmxTransient));
12999 case VMX_EXIT_GETSEC: VMEXIT_CALL_RET(0, hmR0VmxExitGetsec(pVCpu, pVmxTransient));
13000 case VMX_EXIT_RDPMC: VMEXIT_CALL_RET(0, hmR0VmxExitRdpmc(pVCpu, pVmxTransient));
13001#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13002 case VMX_EXIT_VMCLEAR: VMEXIT_CALL_RET(0, hmR0VmxExitVmclear(pVCpu, pVmxTransient));
13003 case VMX_EXIT_VMLAUNCH: VMEXIT_CALL_RET(0, hmR0VmxExitVmlaunch(pVCpu, pVmxTransient));
13004 case VMX_EXIT_VMPTRLD: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrld(pVCpu, pVmxTransient));
13005 case VMX_EXIT_VMPTRST: VMEXIT_CALL_RET(0, hmR0VmxExitVmptrst(pVCpu, pVmxTransient));
13006 case VMX_EXIT_VMREAD: VMEXIT_CALL_RET(0, hmR0VmxExitVmread(pVCpu, pVmxTransient));
13007 case VMX_EXIT_VMRESUME: VMEXIT_CALL_RET(0, hmR0VmxExitVmwrite(pVCpu, pVmxTransient));
13008 case VMX_EXIT_VMWRITE: VMEXIT_CALL_RET(0, hmR0VmxExitVmresume(pVCpu, pVmxTransient));
13009 case VMX_EXIT_VMXOFF: VMEXIT_CALL_RET(0, hmR0VmxExitVmxoff(pVCpu, pVmxTransient));
13010 case VMX_EXIT_VMXON: VMEXIT_CALL_RET(0, hmR0VmxExitVmxon(pVCpu, pVmxTransient));
13011 case VMX_EXIT_INVVPID: VMEXIT_CALL_RET(0, hmR0VmxExitInvvpid(pVCpu, pVmxTransient));
13012 case VMX_EXIT_INVEPT: VMEXIT_CALL_RET(0, hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient));
13013#else
13014 case VMX_EXIT_VMCLEAR:
13015 case VMX_EXIT_VMLAUNCH:
13016 case VMX_EXIT_VMPTRLD:
13017 case VMX_EXIT_VMPTRST:
13018 case VMX_EXIT_VMREAD:
13019 case VMX_EXIT_VMRESUME:
13020 case VMX_EXIT_VMWRITE:
13021 case VMX_EXIT_VMXOFF:
13022 case VMX_EXIT_VMXON:
13023 case VMX_EXIT_INVVPID:
13024 case VMX_EXIT_INVEPT:
13025 return hmR0VmxExitSetPendingXcptUD(pVCpu, pVmxTransient);
13026#endif
13027
13028 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFault(pVCpu, pVmxTransient);
13029 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindow(pVCpu, pVmxTransient);
13030 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
13031
13032 case VMX_EXIT_INIT_SIGNAL:
13033 case VMX_EXIT_SIPI:
13034 case VMX_EXIT_IO_SMI:
13035 case VMX_EXIT_SMI:
13036 case VMX_EXIT_ERR_MSR_LOAD:
13037 case VMX_EXIT_ERR_MACHINE_CHECK:
13038 case VMX_EXIT_PML_FULL:
13039 case VMX_EXIT_VIRTUALIZED_EOI:
13040 case VMX_EXIT_GDTR_IDTR_ACCESS:
13041 case VMX_EXIT_LDTR_TR_ACCESS:
13042 case VMX_EXIT_APIC_WRITE:
13043 case VMX_EXIT_RDRAND:
13044 case VMX_EXIT_RSM:
13045 case VMX_EXIT_VMFUNC:
13046 case VMX_EXIT_ENCLS:
13047 case VMX_EXIT_RDSEED:
13048 case VMX_EXIT_XSAVES:
13049 case VMX_EXIT_XRSTORS:
13050 case VMX_EXIT_UMWAIT:
13051 case VMX_EXIT_TPAUSE:
13052 case VMX_EXIT_LOADIWKEY:
13053 default:
13054 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
13055 }
13056#undef VMEXIT_CALL_RET
13057}
13058#endif /* !HMVMX_USE_FUNCTION_TABLE */
13059
13060
13061#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13062/**
13063 * Handles a nested-guest VM-exit from hardware-assisted VMX execution.
13064 *
13065 * @returns Strict VBox status code (i.e. informational status codes too).
13066 * @param pVCpu The cross context virtual CPU structure.
13067 * @param pVmxTransient The VMX-transient structure.
13068 */
13069DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13070{
13071 uint32_t const uExitReason = pVmxTransient->uExitReason;
13072 switch (uExitReason)
13073 {
13074 case VMX_EXIT_EPT_MISCONFIG: return hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
13075 case VMX_EXIT_EPT_VIOLATION: return hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
13076 case VMX_EXIT_XCPT_OR_NMI: return hmR0VmxExitXcptOrNmiNested(pVCpu, pVmxTransient);
13077 case VMX_EXIT_IO_INSTR: return hmR0VmxExitIoInstrNested(pVCpu, pVmxTransient);
13078 case VMX_EXIT_HLT: return hmR0VmxExitHltNested(pVCpu, pVmxTransient);
13079
13080 /*
13081 * We shouldn't direct host physical interrupts to the nested-guest.
13082 */
13083 case VMX_EXIT_EXT_INT:
13084 return hmR0VmxExitExtInt(pVCpu, pVmxTransient);
13085
13086 /*
13087 * Instructions that cause VM-exits unconditionally or the condition is
13088 * always is taken solely from the nested hypervisor (meaning if the VM-exit
13089 * happens, it's guaranteed to be a nested-guest VM-exit).
13090 *
13091 * - Provides VM-exit instruction length ONLY.
13092 */
13093 case VMX_EXIT_CPUID: /* Unconditional. */
13094 case VMX_EXIT_VMCALL:
13095 case VMX_EXIT_GETSEC:
13096 case VMX_EXIT_INVD:
13097 case VMX_EXIT_XSETBV:
13098 case VMX_EXIT_VMLAUNCH:
13099 case VMX_EXIT_VMRESUME:
13100 case VMX_EXIT_VMXOFF:
13101 case VMX_EXIT_ENCLS: /* Condition specified solely by nested hypervisor. */
13102 case VMX_EXIT_VMFUNC:
13103 return hmR0VmxExitInstrNested(pVCpu, pVmxTransient);
13104
13105 /*
13106 * Instructions that cause VM-exits unconditionally or the condition is
13107 * always is taken solely from the nested hypervisor (meaning if the VM-exit
13108 * happens, it's guaranteed to be a nested-guest VM-exit).
13109 *
13110 * - Provides VM-exit instruction length.
13111 * - Provides VM-exit information.
13112 * - Optionally provides Exit qualification.
13113 *
13114 * Since Exit qualification is 0 for all VM-exits where it is not
13115 * applicable, reading and passing it to the guest should produce
13116 * defined behavior.
13117 *
13118 * See Intel spec. 27.2.1 "Basic VM-Exit Information".
13119 */
13120 case VMX_EXIT_INVEPT: /* Unconditional. */
13121 case VMX_EXIT_INVVPID:
13122 case VMX_EXIT_VMCLEAR:
13123 case VMX_EXIT_VMPTRLD:
13124 case VMX_EXIT_VMPTRST:
13125 case VMX_EXIT_VMXON:
13126 case VMX_EXIT_GDTR_IDTR_ACCESS: /* Condition specified solely by nested hypervisor. */
13127 case VMX_EXIT_LDTR_TR_ACCESS:
13128 case VMX_EXIT_RDRAND:
13129 case VMX_EXIT_RDSEED:
13130 case VMX_EXIT_XSAVES:
13131 case VMX_EXIT_XRSTORS:
13132 case VMX_EXIT_UMWAIT:
13133 case VMX_EXIT_TPAUSE:
13134 return hmR0VmxExitInstrWithInfoNested(pVCpu, pVmxTransient);
13135
13136 case VMX_EXIT_RDTSC: return hmR0VmxExitRdtscNested(pVCpu, pVmxTransient);
13137 case VMX_EXIT_RDTSCP: return hmR0VmxExitRdtscpNested(pVCpu, pVmxTransient);
13138 case VMX_EXIT_RDMSR: return hmR0VmxExitRdmsrNested(pVCpu, pVmxTransient);
13139 case VMX_EXIT_WRMSR: return hmR0VmxExitWrmsrNested(pVCpu, pVmxTransient);
13140 case VMX_EXIT_INVLPG: return hmR0VmxExitInvlpgNested(pVCpu, pVmxTransient);
13141 case VMX_EXIT_INVPCID: return hmR0VmxExitInvpcidNested(pVCpu, pVmxTransient);
13142 case VMX_EXIT_TASK_SWITCH: return hmR0VmxExitTaskSwitchNested(pVCpu, pVmxTransient);
13143 case VMX_EXIT_WBINVD: return hmR0VmxExitWbinvdNested(pVCpu, pVmxTransient);
13144 case VMX_EXIT_MTF: return hmR0VmxExitMtfNested(pVCpu, pVmxTransient);
13145 case VMX_EXIT_APIC_ACCESS: return hmR0VmxExitApicAccessNested(pVCpu, pVmxTransient);
13146 case VMX_EXIT_APIC_WRITE: return hmR0VmxExitApicWriteNested(pVCpu, pVmxTransient);
13147 case VMX_EXIT_VIRTUALIZED_EOI: return hmR0VmxExitVirtEoiNested(pVCpu, pVmxTransient);
13148 case VMX_EXIT_MOV_CRX: return hmR0VmxExitMovCRxNested(pVCpu, pVmxTransient);
13149 case VMX_EXIT_INT_WINDOW: return hmR0VmxExitIntWindowNested(pVCpu, pVmxTransient);
13150 case VMX_EXIT_NMI_WINDOW: return hmR0VmxExitNmiWindowNested(pVCpu, pVmxTransient);
13151 case VMX_EXIT_TPR_BELOW_THRESHOLD: return hmR0VmxExitTprBelowThresholdNested(pVCpu, pVmxTransient);
13152 case VMX_EXIT_MWAIT: return hmR0VmxExitMwaitNested(pVCpu, pVmxTransient);
13153 case VMX_EXIT_MONITOR: return hmR0VmxExitMonitorNested(pVCpu, pVmxTransient);
13154 case VMX_EXIT_PAUSE: return hmR0VmxExitPauseNested(pVCpu, pVmxTransient);
13155
13156 case VMX_EXIT_PREEMPT_TIMER:
13157 {
13158 /** @todo NSTVMX: Preempt timer. */
13159 return hmR0VmxExitPreemptTimer(pVCpu, pVmxTransient);
13160 }
13161
13162 case VMX_EXIT_MOV_DRX: return hmR0VmxExitMovDRxNested(pVCpu, pVmxTransient);
13163 case VMX_EXIT_RDPMC: return hmR0VmxExitRdpmcNested(pVCpu, pVmxTransient);
13164
13165 case VMX_EXIT_VMREAD:
13166 case VMX_EXIT_VMWRITE: return hmR0VmxExitVmreadVmwriteNested(pVCpu, pVmxTransient);
13167
13168 case VMX_EXIT_TRIPLE_FAULT: return hmR0VmxExitTripleFaultNested(pVCpu, pVmxTransient);
13169 case VMX_EXIT_ERR_INVALID_GUEST_STATE: return hmR0VmxExitErrInvalidGuestStateNested(pVCpu, pVmxTransient);
13170
13171 case VMX_EXIT_INIT_SIGNAL:
13172 case VMX_EXIT_SIPI:
13173 case VMX_EXIT_IO_SMI:
13174 case VMX_EXIT_SMI:
13175 case VMX_EXIT_ERR_MSR_LOAD:
13176 case VMX_EXIT_ERR_MACHINE_CHECK:
13177 case VMX_EXIT_PML_FULL:
13178 case VMX_EXIT_RSM:
13179 default:
13180 return hmR0VmxExitErrUnexpected(pVCpu, pVmxTransient);
13181 }
13182}
13183#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13184
13185
13186/** @name VM-exit helpers.
13187 * @{
13188 */
13189/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13190/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= VM-exit helpers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
13191/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
13192
13193/** Macro for VM-exits called unexpectedly. */
13194#define HMVMX_UNEXPECTED_EXIT_RET(a_pVCpu, a_HmError) \
13195 do { \
13196 (a_pVCpu)->hm.s.u32HMError = (a_HmError); \
13197 return VERR_VMX_UNEXPECTED_EXIT; \
13198 } while (0)
13199
13200#ifdef VBOX_STRICT
13201/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
13202# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
13203 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
13204
13205# define HMVMX_ASSERT_PREEMPT_CPUID() \
13206 do { \
13207 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
13208 AssertMsg(idAssertCpu == idAssertCpuNow, ("VMX %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
13209 } while (0)
13210
13211# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13212 do { \
13213 AssertPtr((a_pVCpu)); \
13214 AssertPtr((a_pVmxTransient)); \
13215 Assert((a_pVmxTransient)->fVMEntryFailed == false); \
13216 Assert((a_pVmxTransient)->pVmcsInfo); \
13217 Assert(ASMIntAreEnabled()); \
13218 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
13219 HMVMX_ASSERT_PREEMPT_CPUID_VAR(); \
13220 Log4Func(("vcpu[%RU32]\n", (a_pVCpu)->idCpu)); \
13221 HMVMX_ASSERT_PREEMPT_SAFE(a_pVCpu); \
13222 if (!VMMRZCallRing3IsEnabled((a_pVCpu))) \
13223 HMVMX_ASSERT_PREEMPT_CPUID(); \
13224 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
13225 } while (0)
13226
13227# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13228 do { \
13229 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); \
13230 Assert((a_pVmxTransient)->fIsNestedGuest); \
13231 } while (0)
13232
13233# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13234 do { \
13235 Log4Func(("\n")); \
13236 } while (0)
13237#else
13238# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13239 do { \
13240 HMVMX_STOP_EXIT_DISPATCH_PROF(); \
13241 NOREF((a_pVCpu)); NOREF((a_pVmxTransient)); \
13242 } while (0)
13243
13244# define HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) \
13245 do { HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient); } while (0)
13246
13247# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(a_pVCpu, a_pVmxTransient) do { } while (0)
13248#endif
13249
13250#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13251/** Macro that does the necessary privilege checks and intercepted VM-exits for
13252 * guests that attempted to execute a VMX instruction. */
13253# define HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(a_pVCpu, a_uExitReason) \
13254 do \
13255 { \
13256 VBOXSTRICTRC rcStrictTmp = hmR0VmxCheckExitDueToVmxInstr((a_pVCpu), (a_uExitReason)); \
13257 if (rcStrictTmp == VINF_SUCCESS) \
13258 { /* likely */ } \
13259 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
13260 { \
13261 Assert((a_pVCpu)->hm.s.Event.fPending); \
13262 Log4Func(("Privilege checks failed -> %#x\n", VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo))); \
13263 return VINF_SUCCESS; \
13264 } \
13265 else \
13266 { \
13267 int rcTmp = VBOXSTRICTRC_VAL(rcStrictTmp); \
13268 AssertMsgFailedReturn(("Unexpected failure. rc=%Rrc", rcTmp), rcTmp); \
13269 } \
13270 } while (0)
13271
13272/** Macro that decodes a memory operand for an VM-exit caused by an instruction. */
13273# define HMVMX_DECODE_MEM_OPERAND(a_pVCpu, a_uExitInstrInfo, a_uExitQual, a_enmMemAccess, a_pGCPtrEffAddr) \
13274 do \
13275 { \
13276 VBOXSTRICTRC rcStrictTmp = hmR0VmxDecodeMemOperand((a_pVCpu), (a_uExitInstrInfo), (a_uExitQual), (a_enmMemAccess), \
13277 (a_pGCPtrEffAddr)); \
13278 if (rcStrictTmp == VINF_SUCCESS) \
13279 { /* likely */ } \
13280 else if (rcStrictTmp == VINF_HM_PENDING_XCPT) \
13281 { \
13282 uint8_t const uXcptTmp = VMX_ENTRY_INT_INFO_VECTOR((a_pVCpu)->hm.s.Event.u64IntInfo); \
13283 Log4Func(("Memory operand decoding failed, raising xcpt %#x\n", uXcptTmp)); \
13284 NOREF(uXcptTmp); \
13285 return VINF_SUCCESS; \
13286 } \
13287 else \
13288 { \
13289 Log4Func(("hmR0VmxDecodeMemOperand failed. rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrictTmp))); \
13290 return rcStrictTmp; \
13291 } \
13292 } while (0)
13293#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13294
13295
13296/**
13297 * Advances the guest RIP by the specified number of bytes.
13298 *
13299 * @param pVCpu The cross context virtual CPU structure.
13300 * @param cbInstr Number of bytes to advance the RIP by.
13301 *
13302 * @remarks No-long-jump zone!!!
13303 */
13304DECLINLINE(void) hmR0VmxAdvanceGuestRipBy(PVMCPUCC pVCpu, uint32_t cbInstr)
13305{
13306 /* Advance the RIP. */
13307 pVCpu->cpum.GstCtx.rip += cbInstr;
13308 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
13309
13310 /* Update interrupt inhibition. */
13311 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
13312 && pVCpu->cpum.GstCtx.rip != EMGetInhibitInterruptsPC(pVCpu))
13313 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
13314}
13315
13316
13317/**
13318 * Advances the guest RIP after reading it from the VMCS.
13319 *
13320 * @returns VBox status code, no informational status codes.
13321 * @param pVCpu The cross context virtual CPU structure.
13322 * @param pVmxTransient The VMX-transient structure.
13323 *
13324 * @remarks No-long-jump zone!!!
13325 */
13326static int hmR0VmxAdvanceGuestRip(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13327{
13328 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
13329 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
13330 AssertRCReturn(rc, rc);
13331
13332 hmR0VmxAdvanceGuestRipBy(pVCpu, pVmxTransient->cbExitInstr);
13333 return VINF_SUCCESS;
13334}
13335
13336
13337/**
13338 * Handle a condition that occurred while delivering an event through the guest or
13339 * nested-guest IDT.
13340 *
13341 * @returns Strict VBox status code (i.e. informational status codes too).
13342 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13343 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought
13344 * to continue execution of the guest which will delivery the \#DF.
13345 * @retval VINF_EM_RESET if we detected a triple-fault condition.
13346 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
13347 *
13348 * @param pVCpu The cross context virtual CPU structure.
13349 * @param pVmxTransient The VMX-transient structure.
13350 *
13351 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13352 * Additionally, HMVMX_READ_EXIT_QUALIFICATION is required if the VM-exit
13353 * is due to an EPT violation, PML full or SPP-related event.
13354 *
13355 * @remarks No-long-jump zone!!!
13356 */
13357static VBOXSTRICTRC hmR0VmxCheckExitDueToEventDelivery(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13358{
13359 Assert(!pVCpu->hm.s.Event.fPending);
13360 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
13361 if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13362 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13363 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13364 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_EXIT_QUALIFICATION);
13365
13366 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
13367 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
13368 uint32_t const uIdtVectorInfo = pVmxTransient->uIdtVectoringInfo;
13369 uint32_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
13370 if (VMX_IDT_VECTORING_INFO_IS_VALID(uIdtVectorInfo))
13371 {
13372 uint32_t const uIdtVector = VMX_IDT_VECTORING_INFO_VECTOR(uIdtVectorInfo);
13373 uint32_t const uIdtVectorType = VMX_IDT_VECTORING_INFO_TYPE(uIdtVectorInfo);
13374
13375 /*
13376 * If the event was a software interrupt (generated with INT n) or a software exception
13377 * (generated by INT3/INTO) or a privileged software exception (generated by INT1), we
13378 * can handle the VM-exit and continue guest execution which will re-execute the
13379 * instruction rather than re-injecting the exception, as that can cause premature
13380 * trips to ring-3 before injection and involve TRPM which currently has no way of
13381 * storing that these exceptions were caused by these instructions (ICEBP's #DB poses
13382 * the problem).
13383 */
13384 IEMXCPTRAISE enmRaise;
13385 IEMXCPTRAISEINFO fRaiseInfo;
13386 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_INT
13387 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT
13388 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT)
13389 {
13390 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
13391 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
13392 }
13393 else if (VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo))
13394 {
13395 uint32_t const uExitVectorType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
13396 uint8_t const uExitVector = VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo);
13397 Assert(uExitVectorType == VMX_EXIT_INT_INFO_TYPE_HW_XCPT);
13398
13399 uint32_t const fIdtVectorFlags = hmR0VmxGetIemXcptFlags(uIdtVector, uIdtVectorType);
13400 uint32_t const fExitVectorFlags = hmR0VmxGetIemXcptFlags(uExitVector, uExitVectorType);
13401
13402 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
13403
13404 /* Determine a vectoring #PF condition, see comment in hmR0VmxExitXcptPF(). */
13405 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
13406 {
13407 pVmxTransient->fVectoringPF = true;
13408 enmRaise = IEMXCPTRAISE_PREV_EVENT;
13409 }
13410 }
13411 else
13412 {
13413 /*
13414 * If an exception or hardware interrupt delivery caused an EPT violation/misconfig or APIC access
13415 * VM-exit, then the VM-exit interruption-information will not be valid and we end up here.
13416 * It is sufficient to reflect the original event to the guest after handling the VM-exit.
13417 */
13418 Assert( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT
13419 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
13420 || uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_EXT_INT);
13421 enmRaise = IEMXCPTRAISE_PREV_EVENT;
13422 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
13423 }
13424
13425 /*
13426 * On CPUs that support Virtual NMIs, if this VM-exit (be it an exception or EPT violation/misconfig
13427 * etc.) occurred while delivering the NMI, we need to clear the block-by-NMI field in the guest
13428 * interruptibility-state before re-delivering the NMI after handling the VM-exit. Otherwise the
13429 * subsequent VM-entry would fail, see @bugref{7445}.
13430 *
13431 * See Intel spec. 30.7.1.2 "Resuming Guest Software after Handling an Exception".
13432 */
13433 if ( uIdtVectorType == VMX_IDT_VECTORING_INFO_TYPE_NMI
13434 && enmRaise == IEMXCPTRAISE_PREV_EVENT
13435 && (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13436 && CPUMIsGuestNmiBlocking(pVCpu))
13437 {
13438 CPUMSetGuestNmiBlocking(pVCpu, false);
13439 }
13440
13441 switch (enmRaise)
13442 {
13443 case IEMXCPTRAISE_CURRENT_XCPT:
13444 {
13445 Log4Func(("IDT: Pending secondary Xcpt: idtinfo=%#RX64 exitinfo=%#RX64\n", uIdtVectorInfo, uExitIntInfo));
13446 Assert(rcStrict == VINF_SUCCESS);
13447 break;
13448 }
13449
13450 case IEMXCPTRAISE_PREV_EVENT:
13451 {
13452 uint32_t u32ErrCode;
13453 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(uIdtVectorInfo))
13454 u32ErrCode = pVmxTransient->uIdtVectoringErrorCode;
13455 else
13456 u32ErrCode = 0;
13457
13458 /* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF, see hmR0VmxExitXcptPF(). */
13459 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflect);
13460 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(uIdtVectorInfo), 0 /* cbInstr */,
13461 u32ErrCode, pVCpu->cpum.GstCtx.cr2);
13462
13463 Log4Func(("IDT: Pending vectoring event %#RX64 Err=%#RX32\n", pVCpu->hm.s.Event.u64IntInfo,
13464 pVCpu->hm.s.Event.u32ErrCode));
13465 Assert(rcStrict == VINF_SUCCESS);
13466 break;
13467 }
13468
13469 case IEMXCPTRAISE_REEXEC_INSTR:
13470 Assert(rcStrict == VINF_SUCCESS);
13471 break;
13472
13473 case IEMXCPTRAISE_DOUBLE_FAULT:
13474 {
13475 /*
13476 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
13477 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
13478 */
13479 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
13480 {
13481 pVmxTransient->fVectoringDoublePF = true;
13482 Log4Func(("IDT: Vectoring double #PF %#RX64 cr2=%#RX64\n", pVCpu->hm.s.Event.u64IntInfo,
13483 pVCpu->cpum.GstCtx.cr2));
13484 rcStrict = VINF_SUCCESS;
13485 }
13486 else
13487 {
13488 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectConvertDF);
13489 hmR0VmxSetPendingXcptDF(pVCpu);
13490 Log4Func(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
13491 uIdtVector, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
13492 rcStrict = VINF_HM_DOUBLE_FAULT;
13493 }
13494 break;
13495 }
13496
13497 case IEMXCPTRAISE_TRIPLE_FAULT:
13498 {
13499 Log4Func(("IDT: Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", uIdtVector,
13500 VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo)));
13501 rcStrict = VINF_EM_RESET;
13502 break;
13503 }
13504
13505 case IEMXCPTRAISE_CPU_HANG:
13506 {
13507 Log4Func(("IDT: Bad guest! Entering CPU hang. fRaiseInfo=%#x\n", fRaiseInfo));
13508 rcStrict = VERR_EM_GUEST_CPU_HANG;
13509 break;
13510 }
13511
13512 default:
13513 {
13514 AssertMsgFailed(("IDT: vcpu[%RU32] Unexpected/invalid value! enmRaise=%#x\n", pVCpu->idCpu, enmRaise));
13515 rcStrict = VERR_VMX_IPE_2;
13516 break;
13517 }
13518 }
13519 }
13520 else if ( (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
13521 && !CPUMIsGuestNmiBlocking(pVCpu))
13522 {
13523 if ( VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo)
13524 && VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo) != X86_XCPT_DF
13525 && VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(uExitIntInfo))
13526 {
13527 /*
13528 * Execution of IRET caused a fault when NMI blocking was in effect (i.e we're in
13529 * the guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13530 * that virtual NMIs remain blocked until the IRET execution is completed.
13531 *
13532 * See Intel spec. 31.7.1.2 "Resuming Guest Software After Handling An Exception".
13533 */
13534 CPUMSetGuestNmiBlocking(pVCpu, true);
13535 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13536 }
13537 else if ( pVmxTransient->uExitReason == VMX_EXIT_EPT_VIOLATION
13538 || pVmxTransient->uExitReason == VMX_EXIT_PML_FULL
13539 || pVmxTransient->uExitReason == VMX_EXIT_SPP_EVENT)
13540 {
13541 /*
13542 * Execution of IRET caused an EPT violation, page-modification log-full event or
13543 * SPP-related event VM-exit when NMI blocking was in effect (i.e. we're in the
13544 * guest or nested-guest NMI handler). We need to set the block-by-NMI field so
13545 * that virtual NMIs remain blocked until the IRET execution is completed.
13546 *
13547 * See Intel spec. 27.2.3 "Information about NMI unblocking due to IRET"
13548 */
13549 if (VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(pVmxTransient->uExitQual))
13550 {
13551 CPUMSetGuestNmiBlocking(pVCpu, true);
13552 Log4Func(("Set NMI blocking. uExitReason=%u\n", pVmxTransient->uExitReason));
13553 }
13554 }
13555 }
13556
13557 Assert( rcStrict == VINF_SUCCESS || rcStrict == VINF_HM_DOUBLE_FAULT
13558 || rcStrict == VINF_EM_RESET || rcStrict == VERR_EM_GUEST_CPU_HANG);
13559 return rcStrict;
13560}
13561
13562
13563#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
13564/**
13565 * Perform the relevant VMX instruction checks for VM-exits that occurred due to the
13566 * guest attempting to execute a VMX instruction.
13567 *
13568 * @returns Strict VBox status code (i.e. informational status codes too).
13569 * @retval VINF_SUCCESS if we should continue handling the VM-exit.
13570 * @retval VINF_HM_PENDING_XCPT if an exception was raised.
13571 *
13572 * @param pVCpu The cross context virtual CPU structure.
13573 * @param uExitReason The VM-exit reason.
13574 *
13575 * @todo NSTVMX: Document other error codes when VM-exit is implemented.
13576 * @remarks No-long-jump zone!!!
13577 */
13578static VBOXSTRICTRC hmR0VmxCheckExitDueToVmxInstr(PVMCPUCC pVCpu, uint32_t uExitReason)
13579{
13580 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS
13581 | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
13582
13583 /*
13584 * The physical CPU would have already checked the CPU mode/code segment.
13585 * We shall just assert here for paranoia.
13586 * See Intel spec. 25.1.1 "Relative Priority of Faults and VM Exits".
13587 */
13588 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13589 Assert( !CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx)
13590 || CPUMIsGuestIn64BitCodeEx(&pVCpu->cpum.GstCtx));
13591
13592 if (uExitReason == VMX_EXIT_VMXON)
13593 {
13594 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4);
13595
13596 /*
13597 * We check CR4.VMXE because it is required to be always set while in VMX operation
13598 * by physical CPUs and our CR4 read-shadow is only consulted when executing specific
13599 * instructions (CLTS, LMSW, MOV CR, and SMSW) and thus doesn't affect CPU operation
13600 * otherwise (i.e. physical CPU won't automatically #UD if Cr4Shadow.VMXE is 0).
13601 */
13602 if (!CPUMIsGuestVmxEnabled(&pVCpu->cpum.GstCtx))
13603 {
13604 Log4Func(("CR4.VMXE is not set -> #UD\n"));
13605 hmR0VmxSetPendingXcptUD(pVCpu);
13606 return VINF_HM_PENDING_XCPT;
13607 }
13608 }
13609 else if (!CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx))
13610 {
13611 /*
13612 * The guest has not entered VMX operation but attempted to execute a VMX instruction
13613 * (other than VMXON), we need to raise a #UD.
13614 */
13615 Log4Func(("Not in VMX root mode -> #UD\n"));
13616 hmR0VmxSetPendingXcptUD(pVCpu);
13617 return VINF_HM_PENDING_XCPT;
13618 }
13619
13620 /* All other checks (including VM-exit intercepts) are handled by IEM instruction emulation. */
13621 return VINF_SUCCESS;
13622}
13623
13624
13625/**
13626 * Decodes the memory operand of an instruction that caused a VM-exit.
13627 *
13628 * The Exit qualification field provides the displacement field for memory
13629 * operand instructions, if any.
13630 *
13631 * @returns Strict VBox status code (i.e. informational status codes too).
13632 * @retval VINF_SUCCESS if the operand was successfully decoded.
13633 * @retval VINF_HM_PENDING_XCPT if an exception was raised while decoding the
13634 * operand.
13635 * @param pVCpu The cross context virtual CPU structure.
13636 * @param uExitInstrInfo The VM-exit instruction information field.
13637 * @param enmMemAccess The memory operand's access type (read or write).
13638 * @param GCPtrDisp The instruction displacement field, if any. For
13639 * RIP-relative addressing pass RIP + displacement here.
13640 * @param pGCPtrMem Where to store the effective destination memory address.
13641 *
13642 * @remarks Warning! This function ASSUMES the instruction cannot be used in real or
13643 * virtual-8086 mode hence skips those checks while verifying if the
13644 * segment is valid.
13645 */
13646static VBOXSTRICTRC hmR0VmxDecodeMemOperand(PVMCPUCC pVCpu, uint32_t uExitInstrInfo, RTGCPTR GCPtrDisp, VMXMEMACCESS enmMemAccess,
13647 PRTGCPTR pGCPtrMem)
13648{
13649 Assert(pGCPtrMem);
13650 Assert(!CPUMIsGuestInRealOrV86Mode(pVCpu));
13651 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_EFER
13652 | CPUMCTX_EXTRN_CR0);
13653
13654 static uint64_t const s_auAddrSizeMasks[] = { UINT64_C(0xffff), UINT64_C(0xffffffff), UINT64_C(0xffffffffffffffff) };
13655 static uint64_t const s_auAccessSizeMasks[] = { sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t) };
13656 AssertCompile(RT_ELEMENTS(s_auAccessSizeMasks) == RT_ELEMENTS(s_auAddrSizeMasks));
13657
13658 VMXEXITINSTRINFO ExitInstrInfo;
13659 ExitInstrInfo.u = uExitInstrInfo;
13660 uint8_t const uAddrSize = ExitInstrInfo.All.u3AddrSize;
13661 uint8_t const iSegReg = ExitInstrInfo.All.iSegReg;
13662 bool const fIdxRegValid = !ExitInstrInfo.All.fIdxRegInvalid;
13663 uint8_t const iIdxReg = ExitInstrInfo.All.iIdxReg;
13664 uint8_t const uScale = ExitInstrInfo.All.u2Scaling;
13665 bool const fBaseRegValid = !ExitInstrInfo.All.fBaseRegInvalid;
13666 uint8_t const iBaseReg = ExitInstrInfo.All.iBaseReg;
13667 bool const fIsMemOperand = !ExitInstrInfo.All.fIsRegOperand;
13668 bool const fIsLongMode = CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx);
13669
13670 /*
13671 * Validate instruction information.
13672 * This shouldn't happen on real hardware but useful while testing our nested hardware-virtualization code.
13673 */
13674 AssertLogRelMsgReturn(uAddrSize < RT_ELEMENTS(s_auAddrSizeMasks),
13675 ("Invalid address size. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_1);
13676 AssertLogRelMsgReturn(iSegReg < X86_SREG_COUNT,
13677 ("Invalid segment register. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_2);
13678 AssertLogRelMsgReturn(fIsMemOperand,
13679 ("Expected memory operand. ExitInstrInfo=%#RX32\n", ExitInstrInfo.u), VERR_VMX_IPE_3);
13680
13681 /*
13682 * Compute the complete effective address.
13683 *
13684 * See AMD instruction spec. 1.4.2 "SIB Byte Format"
13685 * See AMD spec. 4.5.2 "Segment Registers".
13686 */
13687 RTGCPTR GCPtrMem = GCPtrDisp;
13688 if (fBaseRegValid)
13689 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iBaseReg].u64;
13690 if (fIdxRegValid)
13691 GCPtrMem += pVCpu->cpum.GstCtx.aGRegs[iIdxReg].u64 << uScale;
13692
13693 RTGCPTR const GCPtrOff = GCPtrMem;
13694 if ( !fIsLongMode
13695 || iSegReg >= X86_SREG_FS)
13696 GCPtrMem += pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
13697 GCPtrMem &= s_auAddrSizeMasks[uAddrSize];
13698
13699 /*
13700 * Validate effective address.
13701 * See AMD spec. 4.5.3 "Segment Registers in 64-Bit Mode".
13702 */
13703 uint8_t const cbAccess = s_auAccessSizeMasks[uAddrSize];
13704 Assert(cbAccess > 0);
13705 if (fIsLongMode)
13706 {
13707 if (X86_IS_CANONICAL(GCPtrMem))
13708 {
13709 *pGCPtrMem = GCPtrMem;
13710 return VINF_SUCCESS;
13711 }
13712
13713 /** @todo r=ramshankar: We should probably raise \#SS or \#GP. See AMD spec. 4.12.2
13714 * "Data Limit Checks in 64-bit Mode". */
13715 Log4Func(("Long mode effective address is not canonical GCPtrMem=%#RX64\n", GCPtrMem));
13716 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13717 return VINF_HM_PENDING_XCPT;
13718 }
13719
13720 /*
13721 * This is a watered down version of iemMemApplySegment().
13722 * Parts that are not applicable for VMX instructions like real-or-v8086 mode
13723 * and segment CPL/DPL checks are skipped.
13724 */
13725 RTGCPTR32 const GCPtrFirst32 = (RTGCPTR32)GCPtrOff;
13726 RTGCPTR32 const GCPtrLast32 = GCPtrFirst32 + cbAccess - 1;
13727 PCCPUMSELREG pSel = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
13728
13729 /* Check if the segment is present and usable. */
13730 if ( pSel->Attr.n.u1Present
13731 && !pSel->Attr.n.u1Unusable)
13732 {
13733 Assert(pSel->Attr.n.u1DescType);
13734 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
13735 {
13736 /* Check permissions for the data segment. */
13737 if ( enmMemAccess == VMXMEMACCESS_WRITE
13738 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_WRITE))
13739 {
13740 Log4Func(("Data segment access invalid. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13741 hmR0VmxSetPendingXcptGP(pVCpu, iSegReg);
13742 return VINF_HM_PENDING_XCPT;
13743 }
13744
13745 /* Check limits if it's a normal data segment. */
13746 if (!(pSel->Attr.n.u4Type & X86_SEL_TYPE_DOWN))
13747 {
13748 if ( GCPtrFirst32 > pSel->u32Limit
13749 || GCPtrLast32 > pSel->u32Limit)
13750 {
13751 Log4Func(("Data segment limit exceeded. "
13752 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13753 GCPtrLast32, pSel->u32Limit));
13754 if (iSegReg == X86_SREG_SS)
13755 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13756 else
13757 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13758 return VINF_HM_PENDING_XCPT;
13759 }
13760 }
13761 else
13762 {
13763 /* Check limits if it's an expand-down data segment.
13764 Note! The upper boundary is defined by the B bit, not the G bit! */
13765 if ( GCPtrFirst32 < pSel->u32Limit + UINT32_C(1)
13766 || GCPtrLast32 > (pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT32_C(0xffff)))
13767 {
13768 Log4Func(("Expand-down data segment limit exceeded. "
13769 "iSegReg=%#x GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n", iSegReg, GCPtrFirst32,
13770 GCPtrLast32, pSel->u32Limit));
13771 if (iSegReg == X86_SREG_SS)
13772 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13773 else
13774 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13775 return VINF_HM_PENDING_XCPT;
13776 }
13777 }
13778 }
13779 else
13780 {
13781 /* Check permissions for the code segment. */
13782 if ( enmMemAccess == VMXMEMACCESS_WRITE
13783 || ( enmMemAccess == VMXMEMACCESS_READ
13784 && !(pSel->Attr.n.u4Type & X86_SEL_TYPE_READ)))
13785 {
13786 Log4Func(("Code segment access invalid. Attr=%#RX32\n", pSel->Attr.u));
13787 Assert(!CPUMIsGuestInRealOrV86ModeEx(&pVCpu->cpum.GstCtx));
13788 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13789 return VINF_HM_PENDING_XCPT;
13790 }
13791
13792 /* Check limits for the code segment (normal/expand-down not applicable for code segments). */
13793 if ( GCPtrFirst32 > pSel->u32Limit
13794 || GCPtrLast32 > pSel->u32Limit)
13795 {
13796 Log4Func(("Code segment limit exceeded. GCPtrFirst32=%#RX32 GCPtrLast32=%#RX32 u32Limit=%#RX32\n",
13797 GCPtrFirst32, GCPtrLast32, pSel->u32Limit));
13798 if (iSegReg == X86_SREG_SS)
13799 hmR0VmxSetPendingXcptSS(pVCpu, 0);
13800 else
13801 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13802 return VINF_HM_PENDING_XCPT;
13803 }
13804 }
13805 }
13806 else
13807 {
13808 Log4Func(("Not present or unusable segment. iSegReg=%#x Attr=%#RX32\n", iSegReg, pSel->Attr.u));
13809 hmR0VmxSetPendingXcptGP(pVCpu, 0);
13810 return VINF_HM_PENDING_XCPT;
13811 }
13812
13813 *pGCPtrMem = GCPtrMem;
13814 return VINF_SUCCESS;
13815}
13816#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
13817
13818
13819/**
13820 * VM-exit helper for LMSW.
13821 */
13822static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
13823{
13824 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13825 AssertRCReturn(rc, rc);
13826
13827 VBOXSTRICTRC rcStrict = IEMExecDecodedLmsw(pVCpu, cbInstr, uMsw, GCPtrEffDst);
13828 AssertMsg( rcStrict == VINF_SUCCESS
13829 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13830
13831 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13832 if (rcStrict == VINF_IEM_RAISED_XCPT)
13833 {
13834 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13835 rcStrict = VINF_SUCCESS;
13836 }
13837
13838 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitLmsw);
13839 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13840 return rcStrict;
13841}
13842
13843
13844/**
13845 * VM-exit helper for CLTS.
13846 */
13847static VBOXSTRICTRC hmR0VmxExitClts(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
13848{
13849 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13850 AssertRCReturn(rc, rc);
13851
13852 VBOXSTRICTRC rcStrict = IEMExecDecodedClts(pVCpu, cbInstr);
13853 AssertMsg( rcStrict == VINF_SUCCESS
13854 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13855
13856 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0);
13857 if (rcStrict == VINF_IEM_RAISED_XCPT)
13858 {
13859 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13860 rcStrict = VINF_SUCCESS;
13861 }
13862
13863 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClts);
13864 Log4Func(("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13865 return rcStrict;
13866}
13867
13868
13869/**
13870 * VM-exit helper for MOV from CRx (CRx read).
13871 */
13872static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPUCC pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13873{
13874 Assert(iCrReg < 16);
13875 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
13876
13877 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
13878 AssertRCReturn(rc, rc);
13879
13880 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
13881 AssertMsg( rcStrict == VINF_SUCCESS
13882 || rcStrict == VINF_IEM_RAISED_XCPT, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13883
13884 if (iGReg == X86_GREG_xSP)
13885 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_RSP);
13886 else
13887 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
13888#ifdef VBOX_WITH_STATISTICS
13889 switch (iCrReg)
13890 {
13891 case 0: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Read); break;
13892 case 2: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Read); break;
13893 case 3: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Read); break;
13894 case 4: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Read); break;
13895 case 8: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Read); break;
13896 }
13897#endif
13898 Log4Func(("CR%d Read access rcStrict=%Rrc\n", iCrReg, VBOXSTRICTRC_VAL(rcStrict)));
13899 return rcStrict;
13900}
13901
13902
13903/**
13904 * VM-exit helper for MOV to CRx (CRx write).
13905 */
13906static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
13907{
13908 HMVMX_CPUMCTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_MUST_MASK);
13909
13910 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
13911 AssertMsg( rcStrict == VINF_SUCCESS
13912 || rcStrict == VINF_IEM_RAISED_XCPT
13913 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
13914
13915 switch (iCrReg)
13916 {
13917 case 0:
13918 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR0
13919 | HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
13920 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR0Write);
13921 Log4Func(("CR0 write. rcStrict=%Rrc CR0=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr0));
13922 break;
13923
13924 case 2:
13925 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR2Write);
13926 /* Nothing to do here, CR2 it's not part of the VMCS. */
13927 break;
13928
13929 case 3:
13930 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR3);
13931 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR3Write);
13932 Log4Func(("CR3 write. rcStrict=%Rrc CR3=%#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cr3));
13933 break;
13934
13935 case 4:
13936 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_CR4);
13937 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR4Write);
13938 Log4Func(("CR4 write. rc=%Rrc CR4=%#RX64 fLoadSaveGuestXcr0=%u\n", VBOXSTRICTRC_VAL(rcStrict),
13939 pVCpu->cpum.GstCtx.cr4, pVCpu->hmr0.s.fLoadSaveGuestXcr0));
13940 break;
13941
13942 case 8:
13943 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
13944 HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_APIC_TPR);
13945 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCR8Write);
13946 break;
13947
13948 default:
13949 AssertMsgFailed(("Invalid CRx register %#x\n", iCrReg));
13950 break;
13951 }
13952
13953 if (rcStrict == VINF_IEM_RAISED_XCPT)
13954 {
13955 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
13956 rcStrict = VINF_SUCCESS;
13957 }
13958 return rcStrict;
13959}
13960
13961
13962/**
13963 * VM-exit exception handler for \#PF (Page-fault exception).
13964 *
13965 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
13966 */
13967static VBOXSTRICTRC hmR0VmxExitXcptPF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
13968{
13969 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
13970 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
13971 hmR0VmxReadExitQualVmcs(pVmxTransient);
13972
13973 if (!pVM->hmr0.s.fNestedPaging)
13974 { /* likely */ }
13975 else
13976 {
13977#if !defined(HMVMX_ALWAYS_TRAP_ALL_XCPTS) && !defined(HMVMX_ALWAYS_TRAP_PF)
13978 Assert(pVmxTransient->fIsNestedGuest || pVCpu->hmr0.s.fUsingDebugLoop);
13979#endif
13980 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
13981 if (!pVmxTransient->fVectoringDoublePF)
13982 {
13983 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
13984 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual);
13985 }
13986 else
13987 {
13988 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
13989 Assert(!pVmxTransient->fIsNestedGuest);
13990 hmR0VmxSetPendingXcptDF(pVCpu);
13991 Log4Func(("Pending #DF due to vectoring #PF w/ NestedPaging\n"));
13992 }
13993 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
13994 return VINF_SUCCESS;
13995 }
13996
13997 Assert(!pVmxTransient->fIsNestedGuest);
13998
13999 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
14000 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
14001 if (pVmxTransient->fVectoringPF)
14002 {
14003 Assert(pVCpu->hm.s.Event.fPending);
14004 return VINF_EM_RAW_INJECT_TRPM_EVENT;
14005 }
14006
14007 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14008 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14009 AssertRCReturn(rc, rc);
14010
14011 Log4Func(("#PF: cs:rip=%#04x:%#RX64 err_code=%#RX32 exit_qual=%#RX64 cr3=%#RX64\n", pCtx->cs.Sel, pCtx->rip,
14012 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual, pCtx->cr3));
14013
14014 TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQual, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
14015 rc = PGMTrap0eHandler(pVCpu, pVmxTransient->uExitIntErrorCode, CPUMCTX2CORE(pCtx), (RTGCPTR)pVmxTransient->uExitQual);
14016
14017 Log4Func(("#PF: rc=%Rrc\n", rc));
14018 if (rc == VINF_SUCCESS)
14019 {
14020 /*
14021 * This is typically a shadow page table sync or a MMIO instruction. But we may have
14022 * emulated something like LTR or a far jump. Any part of the CPU context may have changed.
14023 */
14024 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14025 TRPMResetTrap(pVCpu);
14026 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
14027 return rc;
14028 }
14029
14030 if (rc == VINF_EM_RAW_GUEST_TRAP)
14031 {
14032 if (!pVmxTransient->fVectoringDoublePF)
14033 {
14034 /* It's a guest page fault and needs to be reflected to the guest. */
14035 uint32_t const uGstErrorCode = TRPMGetErrorCode(pVCpu);
14036 TRPMResetTrap(pVCpu);
14037 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory #PF. */
14038 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), 0 /* cbInstr */,
14039 uGstErrorCode, pVmxTransient->uExitQual);
14040 }
14041 else
14042 {
14043 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
14044 TRPMResetTrap(pVCpu);
14045 pVCpu->hm.s.Event.fPending = false; /* Clear pending #PF to replace it with #DF. */
14046 hmR0VmxSetPendingXcptDF(pVCpu);
14047 Log4Func(("#PF: Pending #DF due to vectoring #PF\n"));
14048 }
14049
14050 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
14051 return VINF_SUCCESS;
14052 }
14053
14054 TRPMResetTrap(pVCpu);
14055 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
14056 return rc;
14057}
14058
14059
14060/**
14061 * VM-exit exception handler for \#MF (Math Fault: floating point exception).
14062 *
14063 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14064 */
14065static VBOXSTRICTRC hmR0VmxExitXcptMF(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14066{
14067 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14068 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
14069
14070 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR0);
14071 AssertRCReturn(rc, rc);
14072
14073 if (!(pVCpu->cpum.GstCtx.cr0 & X86_CR0_NE))
14074 {
14075 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
14076 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
14077
14078 /** @todo r=ramshankar: The Intel spec. does -not- specify that this VM-exit
14079 * provides VM-exit instruction length. If this causes problem later,
14080 * disassemble the instruction like it's done on AMD-V. */
14081 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14082 AssertRCReturn(rc2, rc2);
14083 return rc;
14084 }
14085
14086 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo), pVmxTransient->cbExitInstr,
14087 pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14088 return VINF_SUCCESS;
14089}
14090
14091
14092/**
14093 * VM-exit exception handler for \#BP (Breakpoint exception).
14094 *
14095 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14096 */
14097static VBOXSTRICTRC hmR0VmxExitXcptBP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14098{
14099 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14100 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP);
14101
14102 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14103 AssertRCReturn(rc, rc);
14104
14105 if (!pVmxTransient->fIsNestedGuest)
14106 rc = DBGFTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(&pVCpu->cpum.GstCtx));
14107 else
14108 rc = VINF_EM_RAW_GUEST_TRAP;
14109
14110 if (rc == VINF_EM_RAW_GUEST_TRAP)
14111 {
14112 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14113 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14114 rc = VINF_SUCCESS;
14115 }
14116
14117 Assert(rc == VINF_SUCCESS || rc == VINF_EM_DBG_BREAKPOINT);
14118 return rc;
14119}
14120
14121
14122/**
14123 * VM-exit exception handler for \#AC (Alignment-check exception).
14124 *
14125 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14126 */
14127static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14128{
14129 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14130
14131 /*
14132 * Detect #ACs caused by host having enabled split-lock detection.
14133 * Emulate such instructions.
14134 */
14135 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo,
14136 CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS);
14137 AssertRCReturn(rc, rc);
14138 /** @todo detect split lock in cpu feature? */
14139 if ( /* 1. If 486-style alignment checks aren't enabled, then this must be a split-lock exception */
14140 !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_AM)
14141 /* 2. #AC cannot happen in rings 0-2 except for split-lock detection. */
14142 || CPUMGetGuestCPL(pVCpu) != 3
14143 /* 3. When the EFLAGS.AC != 0 this can only be a split-lock case. */
14144 || !(pVCpu->cpum.GstCtx.eflags.u & X86_EFL_AC) )
14145 {
14146 /*
14147 * Check for debug/trace events and import state accordingly.
14148 */
14149 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitGuestACSplitLock);
14150 PVMCC pVM = pVCpu->pVMR0;
14151 if ( !DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_VMX_SPLIT_LOCK)
14152 && !VBOXVMM_VMX_SPLIT_LOCK_ENABLED())
14153 {
14154 if (pVM->cCpus == 1)
14155 {
14156#if 0 /** @todo r=bird: This is potentially wrong. Might have to just do a whole state sync above and mark everything changed to be safe... */
14157 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14158#else
14159 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14160#endif
14161 AssertRCReturn(rc, rc);
14162 }
14163 }
14164 else
14165 {
14166 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14167 AssertRCReturn(rc, rc);
14168
14169 VBOXVMM_XCPT_DF(pVCpu, &pVCpu->cpum.GstCtx);
14170
14171 if (DBGF_IS_EVENT_ENABLED(pVM, DBGFEVENT_VMX_SPLIT_LOCK))
14172 {
14173 VBOXSTRICTRC rcStrict = DBGFEventGenericWithArgs(pVM, pVCpu, DBGFEVENT_VMX_SPLIT_LOCK, DBGFEVENTCTX_HM, 0);
14174 if (rcStrict != VINF_SUCCESS)
14175 return rcStrict;
14176 }
14177 }
14178
14179 /*
14180 * Emulate the instruction.
14181 *
14182 * We have to ignore the LOCK prefix here as we must not retrigger the
14183 * detection on the host. This isn't all that satisfactory, though...
14184 */
14185 if (pVM->cCpus == 1)
14186 {
14187 Log8Func(("cs:rip=%#04x:%#RX64 rflags=%#RX64 cr0=%#RX64 split-lock #AC\n", pVCpu->cpum.GstCtx.cs.Sel,
14188 pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags, pVCpu->cpum.GstCtx.cr0));
14189
14190 /** @todo For SMP configs we should do a rendezvous here. */
14191 VBOXSTRICTRC rcStrict = IEMExecOneIgnoreLock(pVCpu);
14192 if (rcStrict == VINF_SUCCESS)
14193#if 0 /** @todo r=bird: This is potentially wrong. Might have to just do a whole state sync above and mark everything changed to be safe... */
14194 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged,
14195 HM_CHANGED_GUEST_RIP
14196 | HM_CHANGED_GUEST_RFLAGS
14197 | HM_CHANGED_GUEST_GPRS_MASK
14198 | HM_CHANGED_GUEST_CS
14199 | HM_CHANGED_GUEST_SS);
14200#else
14201 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14202#endif
14203 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14204 {
14205 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14206 rcStrict = VINF_SUCCESS;
14207 }
14208 return rcStrict;
14209 }
14210 Log8Func(("cs:rip=%#04x:%#RX64 rflags=%#RX64 cr0=%#RX64 split-lock #AC -> VINF_EM_EMULATE_SPLIT_LOCK\n",
14211 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.rflags, pVCpu->cpum.GstCtx.cr0));
14212 return VINF_EM_EMULATE_SPLIT_LOCK;
14213 }
14214
14215 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC);
14216 Log8Func(("cs:rip=%#04x:%#RX64 rflags=%#RX64 cr0=%#RX64 cpl=%d -> #AC\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14217 pVCpu->cpum.GstCtx.rflags, pVCpu->cpum.GstCtx.cr0, CPUMGetGuestCPL(pVCpu) ));
14218
14219 /* Re-inject it. We'll detect any nesting before getting here. */
14220 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14221 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14222 return VINF_SUCCESS;
14223}
14224
14225
14226/**
14227 * VM-exit exception handler for \#DB (Debug exception).
14228 *
14229 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14230 */
14231static VBOXSTRICTRC hmR0VmxExitXcptDB(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14232{
14233 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14234 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
14235
14236 /*
14237 * Get the DR6-like values from the Exit qualification and pass it to DBGF for processing.
14238 */
14239 hmR0VmxReadExitQualVmcs(pVmxTransient);
14240
14241 /* Refer Intel spec. Table 27-1. "Exit Qualifications for debug exceptions" for the format. */
14242 uint64_t const uDR6 = X86_DR6_INIT_VAL
14243 | (pVmxTransient->uExitQual & ( X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3
14244 | X86_DR6_BD | X86_DR6_BS));
14245
14246 int rc;
14247 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14248 if (!pVmxTransient->fIsNestedGuest)
14249 {
14250 rc = DBGFTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
14251
14252 /*
14253 * Prevents stepping twice over the same instruction when the guest is stepping using
14254 * EFLAGS.TF and the hypervisor debugger is stepping using MTF.
14255 * Testcase: DOSQEMM, break (using "ba x 1") at cs:rip 0x70:0x774 and step (using "t").
14256 */
14257 if ( rc == VINF_EM_DBG_STEPPED
14258 && (pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_MONITOR_TRAP_FLAG))
14259 {
14260 Assert(pVCpu->hm.s.fSingleInstruction);
14261 rc = VINF_EM_RAW_GUEST_TRAP;
14262 }
14263 }
14264 else
14265 rc = VINF_EM_RAW_GUEST_TRAP;
14266 Log6Func(("rc=%Rrc\n", rc));
14267 if (rc == VINF_EM_RAW_GUEST_TRAP)
14268 {
14269 /*
14270 * The exception was for the guest. Update DR6, DR7.GD and
14271 * IA32_DEBUGCTL.LBR before forwarding it.
14272 * See Intel spec. 27.1 "Architectural State before a VM-Exit".
14273 */
14274 VMMRZCallRing3Disable(pVCpu);
14275 HM_DISABLE_PREEMPT(pVCpu);
14276
14277 pCtx->dr[6] &= ~X86_DR6_B_MASK;
14278 pCtx->dr[6] |= uDR6;
14279 if (CPUMIsGuestDebugStateActive(pVCpu))
14280 ASMSetDR6(pCtx->dr[6]);
14281
14282 HM_RESTORE_PREEMPT();
14283 VMMRZCallRing3Enable(pVCpu);
14284
14285 rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_DR7);
14286 AssertRCReturn(rc, rc);
14287
14288 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
14289 pCtx->dr[7] &= ~(uint64_t)X86_DR7_GD;
14290
14291 /* Paranoia. */
14292 pCtx->dr[7] &= ~(uint64_t)X86_DR7_RAZ_MASK;
14293 pCtx->dr[7] |= X86_DR7_RA1_MASK;
14294
14295 rc = VMXWriteVmcsNw(VMX_VMCS_GUEST_DR7, pCtx->dr[7]);
14296 AssertRC(rc);
14297
14298 /*
14299 * Raise #DB in the guest.
14300 *
14301 * It is important to reflect exactly what the VM-exit gave us (preserving the
14302 * interruption-type) rather than use hmR0VmxSetPendingXcptDB() as the #DB could've
14303 * been raised while executing ICEBP (INT1) and not the regular #DB. Thus it may
14304 * trigger different handling in the CPU (like skipping DPL checks), see @bugref{6398}.
14305 *
14306 * Intel re-documented ICEBP/INT1 on May 2018 previously documented as part of
14307 * Intel 386, see Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
14308 */
14309 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14310 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14311 return VINF_SUCCESS;
14312 }
14313
14314 /*
14315 * Not a guest trap, must be a hypervisor related debug event then.
14316 * Update DR6 in case someone is interested in it.
14317 */
14318 AssertMsg(rc == VINF_EM_DBG_STEPPED || rc == VINF_EM_DBG_BREAKPOINT, ("%Rrc\n", rc));
14319 AssertReturn(pVmxTransient->fWasHyperDebugStateActive, VERR_HM_IPE_5);
14320 CPUMSetHyperDR6(pVCpu, uDR6);
14321
14322 return rc;
14323}
14324
14325
14326/**
14327 * Hacks its way around the lovely mesa driver's backdoor accesses.
14328 *
14329 * @sa hmR0SvmHandleMesaDrvGp.
14330 */
14331static int hmR0VmxHandleMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
14332{
14333 LogFunc(("cs:rip=%#04x:%#RX64 rcx=%#RX64 rbx=%#RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->rcx, pCtx->rbx));
14334 RT_NOREF(pCtx);
14335
14336 /* For now we'll just skip the instruction. */
14337 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14338}
14339
14340
14341/**
14342 * Checks if the \#GP'ing instruction is the mesa driver doing it's lovely
14343 * backdoor logging w/o checking what it is running inside.
14344 *
14345 * This recognizes an "IN EAX,DX" instruction executed in flat ring-3, with the
14346 * backdoor port and magic numbers loaded in registers.
14347 *
14348 * @returns true if it is, false if it isn't.
14349 * @sa hmR0SvmIsMesaDrvGp.
14350 */
14351DECLINLINE(bool) hmR0VmxIsMesaDrvGp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient, PCPUMCTX pCtx)
14352{
14353 /* 0xed: IN eAX,dx */
14354 uint8_t abInstr[1];
14355 if (pVmxTransient->cbExitInstr != sizeof(abInstr))
14356 return false;
14357
14358 /* Check that it is #GP(0). */
14359 if (pVmxTransient->uExitIntErrorCode != 0)
14360 return false;
14361
14362 /* Check magic and port. */
14363 Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RCX)));
14364 /*Log(("hmR0VmxIsMesaDrvGp: rax=%RX64 rdx=%RX64\n", pCtx->rax, pCtx->rdx));*/
14365 if (pCtx->rax != UINT32_C(0x564d5868))
14366 return false;
14367 if (pCtx->dx != UINT32_C(0x5658))
14368 return false;
14369
14370 /* Flat ring-3 CS. */
14371 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_CS);
14372 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_CS));
14373 /*Log(("hmR0VmxIsMesaDrvGp: cs.Attr.n.u2Dpl=%d base=%Rx64\n", pCtx->cs.Attr.n.u2Dpl, pCtx->cs.u64Base));*/
14374 if (pCtx->cs.Attr.n.u2Dpl != 3)
14375 return false;
14376 if (pCtx->cs.u64Base != 0)
14377 return false;
14378
14379 /* Check opcode. */
14380 AssertCompile(HMVMX_CPUMCTX_EXTRN_ALL & CPUMCTX_EXTRN_RIP);
14381 Assert(!(pCtx->fExtrn & CPUMCTX_EXTRN_RIP));
14382 int rc = PGMPhysSimpleReadGCPtr(pVCpu, abInstr, pCtx->rip, sizeof(abInstr));
14383 /*Log(("hmR0VmxIsMesaDrvGp: PGMPhysSimpleReadGCPtr -> %Rrc %#x\n", rc, abInstr[0]));*/
14384 if (RT_FAILURE(rc))
14385 return false;
14386 if (abInstr[0] != 0xed)
14387 return false;
14388
14389 return true;
14390}
14391
14392
14393/**
14394 * VM-exit exception handler for \#GP (General-protection exception).
14395 *
14396 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14397 */
14398static VBOXSTRICTRC hmR0VmxExitXcptGP(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14399{
14400 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14401 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
14402
14403 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14404 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14405 PVMXVMCSINFOSHARED pVmcsInfoShared = pVmcsInfo->pShared;
14406 if (pVmcsInfoShared->RealMode.fRealOnV86Active)
14407 { /* likely */ }
14408 else
14409 {
14410#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14411 Assert(pVCpu->hmr0.s.fUsingDebugLoop || pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv || pVmxTransient->fIsNestedGuest);
14412#endif
14413 /*
14414 * If the guest is not in real-mode or we have unrestricted guest execution support, or if we are
14415 * executing a nested-guest, reflect #GP to the guest or nested-guest.
14416 */
14417 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14418 AssertRCReturn(rc, rc);
14419 Log4Func(("Gst: cs:rip=%#04x:%#RX64 ErrorCode=%#x cr0=%#RX64 cpl=%u tr=%#04x\n", pCtx->cs.Sel, pCtx->rip,
14420 pVmxTransient->uExitIntErrorCode, pCtx->cr0, CPUMGetGuestCPL(pVCpu), pCtx->tr.Sel));
14421
14422 if ( pVmxTransient->fIsNestedGuest
14423 || !pVCpu->hm.s.fTrapXcptGpForLovelyMesaDrv
14424 || !hmR0VmxIsMesaDrvGp(pVCpu, pVmxTransient, pCtx))
14425 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14426 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14427 else
14428 rc = hmR0VmxHandleMesaDrvGp(pVCpu, pVmxTransient, pCtx);
14429 return rc;
14430 }
14431
14432 Assert(CPUMIsGuestInRealModeEx(pCtx));
14433 Assert(!pVCpu->CTX_SUFF(pVM)->hmr0.s.vmx.fUnrestrictedGuest);
14434 Assert(!pVmxTransient->fIsNestedGuest);
14435
14436 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14437 AssertRCReturn(rc, rc);
14438
14439 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
14440 if (rcStrict == VINF_SUCCESS)
14441 {
14442 if (!CPUMIsGuestInRealModeEx(pCtx))
14443 {
14444 /*
14445 * The guest is no longer in real-mode, check if we can continue executing the
14446 * guest using hardware-assisted VMX. Otherwise, fall back to emulation.
14447 */
14448 pVmcsInfoShared->RealMode.fRealOnV86Active = false;
14449 if (HMCanExecuteVmxGuest(pVCpu->pVMR0, pVCpu, pCtx))
14450 {
14451 Log4Func(("Mode changed but guest still suitable for executing using hardware-assisted VMX\n"));
14452 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14453 }
14454 else
14455 {
14456 Log4Func(("Mode changed -> VINF_EM_RESCHEDULE\n"));
14457 rcStrict = VINF_EM_RESCHEDULE;
14458 }
14459 }
14460 else
14461 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14462 }
14463 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14464 {
14465 rcStrict = VINF_SUCCESS;
14466 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14467 }
14468 return VBOXSTRICTRC_VAL(rcStrict);
14469}
14470
14471
14472/**
14473 * VM-exit exception handler wrapper for all other exceptions that are not handled
14474 * by a specific handler.
14475 *
14476 * This simply re-injects the exception back into the VM without any special
14477 * processing.
14478 *
14479 * @remarks Requires all fields in HMVMX_READ_XCPT_INFO to be read from the VMCS.
14480 */
14481static VBOXSTRICTRC hmR0VmxExitXcptOthers(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14482{
14483 HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14484
14485#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14486 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14487 AssertMsg(pVCpu->hmr0.s.fUsingDebugLoop || pVmcsInfo->pShared->RealMode.fRealOnV86Active || pVmxTransient->fIsNestedGuest,
14488 ("uVector=%#x u32XcptBitmap=%#X32\n",
14489 VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo), pVmcsInfo->u32XcptBitmap));
14490 NOREF(pVmcsInfo);
14491#endif
14492
14493 /*
14494 * Re-inject the exception into the guest. This cannot be a double-fault condition which
14495 * would have been handled while checking exits due to event delivery.
14496 */
14497 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14498
14499#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
14500 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_RIP);
14501 AssertRCReturn(rc, rc);
14502 Log4Func(("Reinjecting Xcpt. uVector=%#x cs:rip=%#04x:%#RX64\n", uVector, pCtx->cs.Sel, pCtx->rip));
14503#endif
14504
14505#ifdef VBOX_WITH_STATISTICS
14506 switch (uVector)
14507 {
14508 case X86_XCPT_DE: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE); break;
14509 case X86_XCPT_DB: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB); break;
14510 case X86_XCPT_BP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); break;
14511 case X86_XCPT_OF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
14512 case X86_XCPT_BR: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBR); break;
14513 case X86_XCPT_UD: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); break;
14514 case X86_XCPT_NM: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestOF); break;
14515 case X86_XCPT_DF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDF); break;
14516 case X86_XCPT_TS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestTS); break;
14517 case X86_XCPT_NP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP); break;
14518 case X86_XCPT_SS: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS); break;
14519 case X86_XCPT_GP: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP); break;
14520 case X86_XCPT_PF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); break;
14521 case X86_XCPT_MF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF); break;
14522 case X86_XCPT_AC: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestAC); break;
14523 case X86_XCPT_XF: STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXF); break;
14524 default:
14525 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestXcpUnk);
14526 break;
14527 }
14528#endif
14529
14530 /* We should never call this function for a page-fault, we'd need to pass on the fault address below otherwise. */
14531 Assert(!VMX_EXIT_INT_INFO_IS_XCPT_PF(pVmxTransient->uExitIntInfo));
14532 NOREF(uVector);
14533
14534 /* Re-inject the original exception into the guest. */
14535 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
14536 pVmxTransient->cbExitInstr, pVmxTransient->uExitIntErrorCode, 0 /* GCPtrFaultAddress */);
14537 return VINF_SUCCESS;
14538}
14539
14540
14541/**
14542 * VM-exit exception handler for all exceptions (except NMIs!).
14543 *
14544 * @remarks This may be called for both guests and nested-guests. Take care to not
14545 * make assumptions and avoid doing anything that is not relevant when
14546 * executing a nested-guest (e.g., Mesa driver hacks).
14547 */
14548static VBOXSTRICTRC hmR0VmxExitXcpt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14549{
14550 HMVMX_ASSERT_READ(pVmxTransient, HMVMX_READ_XCPT_INFO);
14551
14552 /*
14553 * If this VM-exit occurred while delivering an event through the guest IDT, take
14554 * action based on the return code and additional hints (e.g. for page-faults)
14555 * that will be updated in the VMX transient structure.
14556 */
14557 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
14558 if (rcStrict == VINF_SUCCESS)
14559 {
14560 /*
14561 * If an exception caused a VM-exit due to delivery of an event, the original
14562 * event may have to be re-injected into the guest. We shall reinject it and
14563 * continue guest execution. However, page-fault is a complicated case and
14564 * needs additional processing done in hmR0VmxExitXcptPF().
14565 */
14566 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14567 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14568 if ( !pVCpu->hm.s.Event.fPending
14569 || uVector == X86_XCPT_PF)
14570 {
14571 switch (uVector)
14572 {
14573 case X86_XCPT_PF: return hmR0VmxExitXcptPF(pVCpu, pVmxTransient);
14574 case X86_XCPT_GP: return hmR0VmxExitXcptGP(pVCpu, pVmxTransient);
14575 case X86_XCPT_MF: return hmR0VmxExitXcptMF(pVCpu, pVmxTransient);
14576 case X86_XCPT_DB: return hmR0VmxExitXcptDB(pVCpu, pVmxTransient);
14577 case X86_XCPT_BP: return hmR0VmxExitXcptBP(pVCpu, pVmxTransient);
14578 case X86_XCPT_AC: return hmR0VmxExitXcptAC(pVCpu, pVmxTransient);
14579 default:
14580 return hmR0VmxExitXcptOthers(pVCpu, pVmxTransient);
14581 }
14582 }
14583 /* else: inject pending event before resuming guest execution. */
14584 }
14585 else if (rcStrict == VINF_HM_DOUBLE_FAULT)
14586 {
14587 Assert(pVCpu->hm.s.Event.fPending);
14588 rcStrict = VINF_SUCCESS;
14589 }
14590
14591 return rcStrict;
14592}
14593/** @} */
14594
14595
14596/** @name VM-exit handlers.
14597 * @{
14598 */
14599/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
14600/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
14601/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
14602
14603/**
14604 * VM-exit handler for external interrupts (VMX_EXIT_EXT_INT).
14605 */
14606HMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14607{
14608 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14609 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
14610 /* Windows hosts (32-bit and 64-bit) have DPC latency issues. See @bugref{6853}. */
14611 if (VMMR0ThreadCtxHookIsEnabled(pVCpu))
14612 return VINF_SUCCESS;
14613 return VINF_EM_RAW_INTERRUPT;
14614}
14615
14616
14617/**
14618 * VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI). Conditional
14619 * VM-exit.
14620 */
14621HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmi(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14622{
14623 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14624 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
14625
14626 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
14627
14628 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(pVmxTransient->uExitIntInfo);
14629 uint8_t const uVector = VMX_EXIT_INT_INFO_VECTOR(pVmxTransient->uExitIntInfo);
14630 Assert(VMX_EXIT_INT_INFO_IS_VALID(pVmxTransient->uExitIntInfo));
14631
14632 PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14633 Assert( !(pVmcsInfo->u32ExitCtls & VMX_EXIT_CTLS_ACK_EXT_INT)
14634 && uExitIntType != VMX_EXIT_INT_INFO_TYPE_EXT_INT);
14635 NOREF(pVmcsInfo);
14636
14637 VBOXSTRICTRC rcStrict;
14638 switch (uExitIntType)
14639 {
14640 /*
14641 * Host physical NMIs:
14642 * This cannot be a guest NMI as the only way for the guest to receive an NMI is if we
14643 * injected it ourselves and anything we inject is not going to cause a VM-exit directly
14644 * for the event being injected[1]. Go ahead and dispatch the NMI to the host[2].
14645 *
14646 * See Intel spec. 27.2.3 "Information for VM Exits During Event Delivery".
14647 * See Intel spec. 27.5.5 "Updating Non-Register State".
14648 */
14649 case VMX_EXIT_INT_INFO_TYPE_NMI:
14650 {
14651 rcStrict = hmR0VmxExitHostNmi(pVCpu, pVmcsInfo);
14652 break;
14653 }
14654
14655 /*
14656 * Privileged software exceptions (#DB from ICEBP),
14657 * Software exceptions (#BP and #OF),
14658 * Hardware exceptions:
14659 * Process the required exceptions and resume guest execution if possible.
14660 */
14661 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
14662 Assert(uVector == X86_XCPT_DB);
14663 RT_FALL_THRU();
14664 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
14665 Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uExitIntType == VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT);
14666 RT_FALL_THRU();
14667 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
14668 {
14669 NOREF(uVector);
14670 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
14671 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14672 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
14673 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
14674
14675 rcStrict = hmR0VmxExitXcpt(pVCpu, pVmxTransient);
14676 break;
14677 }
14678
14679 default:
14680 {
14681 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
14682 rcStrict = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
14683 AssertMsgFailed(("Invalid/unexpected VM-exit interruption info %#x\n", pVmxTransient->uExitIntInfo));
14684 break;
14685 }
14686 }
14687
14688 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
14689 return rcStrict;
14690}
14691
14692
14693/**
14694 * VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
14695 */
14696HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14697{
14698 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14699
14700 /* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
14701 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14702 hmR0VmxClearIntWindowExitVmcs(pVmcsInfo);
14703
14704 /* Evaluate and deliver pending events and resume guest execution. */
14705 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
14706 return VINF_SUCCESS;
14707}
14708
14709
14710/**
14711 * VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
14712 */
14713HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindow(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14714{
14715 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14716
14717 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14718 if (RT_UNLIKELY(!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_NMI_WINDOW_EXIT))) /** @todo NSTVMX: Turn this into an assertion. */
14719 {
14720 AssertMsgFailed(("Unexpected NMI-window exit.\n"));
14721 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14722 }
14723
14724 Assert(!CPUMIsGuestNmiBlocking(pVCpu));
14725
14726 /*
14727 * If block-by-STI is set when we get this VM-exit, it means the CPU doesn't block NMIs following STI.
14728 * It is therefore safe to unblock STI and deliver the NMI ourselves. See @bugref{7445}.
14729 */
14730 uint32_t fIntrState;
14731 int rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState);
14732 AssertRC(rc);
14733 Assert(!(fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS));
14734 if (fIntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
14735 {
14736 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
14737 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
14738
14739 fIntrState &= ~VMX_VMCS_GUEST_INT_STATE_BLOCK_STI;
14740 rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_INT_STATE, fIntrState);
14741 AssertRC(rc);
14742 }
14743
14744 /* Indicate that we no longer need to VM-exit when the guest is ready to receive NMIs, it is now ready */
14745 hmR0VmxClearNmiWindowExitVmcs(pVmcsInfo);
14746
14747 /* Evaluate and deliver pending events and resume guest execution. */
14748 return VINF_SUCCESS;
14749}
14750
14751
14752/**
14753 * VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
14754 */
14755HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14756{
14757 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14758 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14759}
14760
14761
14762/**
14763 * VM-exit handler for INVD (VMX_EXIT_INVD). Unconditional VM-exit.
14764 */
14765HMVMX_EXIT_NSRC_DECL hmR0VmxExitInvd(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14766{
14767 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14768 return hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14769}
14770
14771
14772/**
14773 * VM-exit handler for CPUID (VMX_EXIT_CPUID). Unconditional VM-exit.
14774 */
14775HMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14776{
14777 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14778
14779 /*
14780 * Get the state we need and update the exit history entry.
14781 */
14782 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14783 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14784
14785 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
14786 AssertRCReturn(rc, rc);
14787
14788 VBOXSTRICTRC rcStrict;
14789 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
14790 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_CPUID),
14791 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
14792 if (!pExitRec)
14793 {
14794 /*
14795 * Regular CPUID instruction execution.
14796 */
14797 rcStrict = IEMExecDecodedCpuid(pVCpu, pVmxTransient->cbExitInstr);
14798 if (rcStrict == VINF_SUCCESS)
14799 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14800 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14801 {
14802 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14803 rcStrict = VINF_SUCCESS;
14804 }
14805 }
14806 else
14807 {
14808 /*
14809 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
14810 */
14811 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
14812 AssertRCReturn(rc2, rc2);
14813
14814 Log4(("CpuIdExit/%u: %04x:%08RX64: %#x/%#x -> EMHistoryExec\n",
14815 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx));
14816
14817 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
14818 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
14819
14820 Log4(("CpuIdExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
14821 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
14822 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
14823 }
14824 return rcStrict;
14825}
14826
14827
14828/**
14829 * VM-exit handler for GETSEC (VMX_EXIT_GETSEC). Unconditional VM-exit.
14830 */
14831HMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14832{
14833 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14834
14835 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14836 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
14837 AssertRCReturn(rc, rc);
14838
14839 if (pVCpu->cpum.GstCtx.cr4 & X86_CR4_SMXE)
14840 return VINF_EM_RAW_EMULATE_INSTR;
14841
14842 AssertMsgFailed(("hmR0VmxExitGetsec: Unexpected VM-exit when CR4.SMXE is 0.\n"));
14843 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
14844}
14845
14846
14847/**
14848 * VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
14849 */
14850HMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14851{
14852 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14853
14854 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14855 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14856 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
14857 AssertRCReturn(rc, rc);
14858
14859 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtsc(pVCpu, pVmxTransient->cbExitInstr);
14860 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14861 {
14862 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14863 we must reset offsetting on VM-entry. See @bugref{6634}. */
14864 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14865 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14866 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14867 }
14868 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14869 {
14870 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14871 rcStrict = VINF_SUCCESS;
14872 }
14873 return rcStrict;
14874}
14875
14876
14877/**
14878 * VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
14879 */
14880HMVMX_EXIT_DECL hmR0VmxExitRdtscp(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14881{
14882 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14883
14884 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14885 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14886 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
14887 AssertRCReturn(rc, rc);
14888
14889 VBOXSTRICTRC rcStrict = IEMExecDecodedRdtscp(pVCpu, pVmxTransient->cbExitInstr);
14890 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
14891 {
14892 /* If we get a spurious VM-exit when TSC offsetting is enabled,
14893 we must reset offsetting on VM-reentry. See @bugref{6634}. */
14894 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TSC_OFFSETTING)
14895 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
14896 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14897 }
14898 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14899 {
14900 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
14901 rcStrict = VINF_SUCCESS;
14902 }
14903 return rcStrict;
14904}
14905
14906
14907/**
14908 * VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
14909 */
14910HMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14911{
14912 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14913
14914 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14915 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_CR0
14916 | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
14917 AssertRCReturn(rc, rc);
14918
14919 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
14920 rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
14921 if (RT_LIKELY(rc == VINF_SUCCESS))
14922 {
14923 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14924 Assert(pVmxTransient->cbExitInstr == 2);
14925 }
14926 else
14927 {
14928 AssertMsgFailed(("hmR0VmxExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
14929 rc = VERR_EM_INTERPRETER;
14930 }
14931 return rc;
14932}
14933
14934
14935/**
14936 * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
14937 */
14938HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14939{
14940 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14941
14942 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
14943 if (EMAreHypercallInstructionsEnabled(pVCpu))
14944 {
14945 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14946 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
14947 | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_EFER);
14948 AssertRCReturn(rc, rc);
14949
14950 /* Perform the hypercall. */
14951 rcStrict = GIMHypercall(pVCpu, &pVCpu->cpum.GstCtx);
14952 if (rcStrict == VINF_SUCCESS)
14953 {
14954 rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
14955 AssertRCReturn(rc, rc);
14956 }
14957 else
14958 Assert( rcStrict == VINF_GIM_R3_HYPERCALL
14959 || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
14960 || RT_FAILURE(rcStrict));
14961
14962 /* If the hypercall changes anything other than guest's general-purpose registers,
14963 we would need to reload the guest changed bits here before VM-entry. */
14964 }
14965 else
14966 Log4Func(("Hypercalls not enabled\n"));
14967
14968 /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
14969 if (RT_FAILURE(rcStrict))
14970 {
14971 hmR0VmxSetPendingXcptUD(pVCpu);
14972 rcStrict = VINF_SUCCESS;
14973 }
14974
14975 return rcStrict;
14976}
14977
14978
14979/**
14980 * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
14981 */
14982HMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
14983{
14984 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
14985 Assert(!pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging || pVCpu->hmr0.s.fUsingDebugLoop);
14986
14987 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
14988 hmR0VmxReadExitQualVmcs(pVmxTransient);
14989 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
14990 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
14991 AssertRCReturn(rc, rc);
14992
14993 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->uExitQual);
14994
14995 if (rcStrict == VINF_SUCCESS || rcStrict == VINF_PGM_SYNC_CR3)
14996 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
14997 else if (rcStrict == VINF_IEM_RAISED_XCPT)
14998 {
14999 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15000 rcStrict = VINF_SUCCESS;
15001 }
15002 else
15003 AssertMsgFailed(("Unexpected IEMExecDecodedInvlpg(%#RX64) status: %Rrc\n", pVmxTransient->uExitQual,
15004 VBOXSTRICTRC_VAL(rcStrict)));
15005 return rcStrict;
15006}
15007
15008
15009/**
15010 * VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
15011 */
15012HMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15013{
15014 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15015
15016 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15017 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15018 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
15019 AssertRCReturn(rc, rc);
15020
15021 VBOXSTRICTRC rcStrict = IEMExecDecodedMonitor(pVCpu, pVmxTransient->cbExitInstr);
15022 if (rcStrict == VINF_SUCCESS)
15023 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15024 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15025 {
15026 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15027 rcStrict = VINF_SUCCESS;
15028 }
15029
15030 return rcStrict;
15031}
15032
15033
15034/**
15035 * VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
15036 */
15037HMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15038{
15039 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15040
15041 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15042 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15043 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
15044 AssertRCReturn(rc, rc);
15045
15046 VBOXSTRICTRC rcStrict = IEMExecDecodedMwait(pVCpu, pVmxTransient->cbExitInstr);
15047 if (RT_SUCCESS(rcStrict))
15048 {
15049 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15050 if (EMMonitorWaitShouldContinue(pVCpu, &pVCpu->cpum.GstCtx))
15051 rcStrict = VINF_SUCCESS;
15052 }
15053
15054 return rcStrict;
15055}
15056
15057
15058/**
15059 * VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT). Unconditional
15060 * VM-exit.
15061 */
15062HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15063{
15064 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15065 return VINF_EM_RESET;
15066}
15067
15068
15069/**
15070 * VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
15071 */
15072HMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15073{
15074 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15075
15076 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15077 AssertRCReturn(rc, rc);
15078
15079 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_RFLAGS); /* Advancing the RIP above should've imported eflags. */
15080 if (EMShouldContinueAfterHalt(pVCpu, &pVCpu->cpum.GstCtx)) /* Requires eflags. */
15081 rc = VINF_SUCCESS;
15082 else
15083 rc = VINF_EM_HALT;
15084
15085 if (rc != VINF_SUCCESS)
15086 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
15087 return rc;
15088}
15089
15090
15091/**
15092 * VM-exit handler for instructions that result in a \#UD exception delivered to
15093 * the guest.
15094 */
15095HMVMX_EXIT_NSRC_DECL hmR0VmxExitSetPendingXcptUD(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15096{
15097 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15098 hmR0VmxSetPendingXcptUD(pVCpu);
15099 return VINF_SUCCESS;
15100}
15101
15102
15103/**
15104 * VM-exit handler for expiry of the VMX-preemption timer.
15105 */
15106HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15107{
15108 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15109
15110 /* If the VMX-preemption timer has expired, reinitialize the preemption timer on next VM-entry. */
15111 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
15112Log12(("hmR0VmxExitPreemptTimer:\n"));
15113
15114 /* If there are any timer events pending, fall back to ring-3, otherwise resume guest execution. */
15115 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15116 bool fTimersPending = TMTimerPollBool(pVM, pVCpu);
15117 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitPreemptTimer);
15118 return fTimersPending ? VINF_EM_RAW_TIMER_PENDING : VINF_SUCCESS;
15119}
15120
15121
15122/**
15123 * VM-exit handler for XSETBV (VMX_EXIT_XSETBV). Unconditional VM-exit.
15124 */
15125HMVMX_EXIT_DECL hmR0VmxExitXsetbv(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15126{
15127 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15128
15129 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15130 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15131 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
15132 AssertRCReturn(rc, rc);
15133
15134 VBOXSTRICTRC rcStrict = IEMExecDecodedXsetbv(pVCpu, pVmxTransient->cbExitInstr);
15135 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, rcStrict != VINF_IEM_RAISED_XCPT ? HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS
15136 : HM_CHANGED_RAISED_XCPT_MASK);
15137
15138 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15139 bool const fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
15140 if (fLoadSaveGuestXcr0 != pVCpu->hmr0.s.fLoadSaveGuestXcr0)
15141 {
15142 pVCpu->hmr0.s.fLoadSaveGuestXcr0 = fLoadSaveGuestXcr0;
15143 hmR0VmxUpdateStartVmFunction(pVCpu);
15144 }
15145
15146 return rcStrict;
15147}
15148
15149
15150/**
15151 * VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
15152 */
15153HMVMX_EXIT_DECL hmR0VmxExitInvpcid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15154{
15155 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15156
15157 /** @todo Enable the new code after finding a reliably guest test-case. */
15158#if 1
15159 return VERR_EM_INTERPRETER;
15160#else
15161 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15162 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15163 hmR0VmxReadExitQualVmcs(pVmxTransient);
15164 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
15165 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
15166 AssertRCReturn(rc, rc);
15167
15168 /* Paranoia. Ensure this has a memory operand. */
15169 Assert(!pVmxTransient->ExitInstrInfo.Inv.u1Cleared0);
15170
15171 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
15172 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
15173 uint64_t const uType = CPUMIsGuestIn64BitCode(pVCpu) ? pVCpu->cpum.GstCtx.aGRegs[iGReg].u64
15174 : pVCpu->cpum.GstCtx.aGRegs[iGReg].u32;
15175
15176 RTGCPTR GCPtrDesc;
15177 HMVMX_DECODE_MEM_OPERAND(pVCpu, pVmxTransient->ExitInstrInfo.u, pVmxTransient->uExitQual, VMXMEMACCESS_READ, &GCPtrDesc);
15178
15179 VBOXSTRICTRC rcStrict = IEMExecDecodedInvpcid(pVCpu, pVmxTransient->cbExitInstr, pVmxTransient->ExitInstrInfo.Inv.iSegReg,
15180 GCPtrDesc, uType);
15181 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
15182 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15183 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15184 {
15185 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15186 rcStrict = VINF_SUCCESS;
15187 }
15188 return rcStrict;
15189#endif
15190}
15191
15192
15193/**
15194 * VM-exit handler for invalid-guest-state (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error
15195 * VM-exit.
15196 */
15197HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15198{
15199 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15200 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15201 AssertRCReturn(rc, rc);
15202
15203 rc = hmR0VmxCheckCachedVmcsCtls(pVCpu, pVmcsInfo, pVmxTransient->fIsNestedGuest);
15204 if (RT_FAILURE(rc))
15205 return rc;
15206
15207 uint32_t const uInvalidReason = hmR0VmxCheckGuestState(pVCpu, pVmcsInfo);
15208 NOREF(uInvalidReason);
15209
15210#ifdef VBOX_STRICT
15211 uint32_t fIntrState;
15212 uint64_t u64Val;
15213 hmR0VmxReadEntryIntInfoVmcs(pVmxTransient);
15214 hmR0VmxReadEntryXcptErrorCodeVmcs(pVmxTransient);
15215 hmR0VmxReadEntryInstrLenVmcs(pVmxTransient);
15216
15217 Log4(("uInvalidReason %u\n", uInvalidReason));
15218 Log4(("VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO %#RX32\n", pVmxTransient->uEntryIntInfo));
15219 Log4(("VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE %#RX32\n", pVmxTransient->uEntryXcptErrorCode));
15220 Log4(("VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH %#RX32\n", pVmxTransient->cbEntryInstr));
15221
15222 rc = VMXReadVmcs32(VMX_VMCS32_GUEST_INT_STATE, &fIntrState); AssertRC(rc);
15223 Log4(("VMX_VMCS32_GUEST_INT_STATE %#RX32\n", fIntrState));
15224 rc = VMXReadVmcsNw(VMX_VMCS_GUEST_CR0, &u64Val); AssertRC(rc);
15225 Log4(("VMX_VMCS_GUEST_CR0 %#RX64\n", u64Val));
15226 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_MASK, &u64Val); AssertRC(rc);
15227 Log4(("VMX_VMCS_CTRL_CR0_MASK %#RX64\n", u64Val));
15228 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR0_READ_SHADOW, &u64Val); AssertRC(rc);
15229 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
15230 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_MASK, &u64Val); AssertRC(rc);
15231 Log4(("VMX_VMCS_CTRL_CR4_MASK %#RX64\n", u64Val));
15232 rc = VMXReadVmcsNw(VMX_VMCS_CTRL_CR4_READ_SHADOW, &u64Val); AssertRC(rc);
15233 Log4(("VMX_VMCS_CTRL_CR4_READ_SHADOW %#RX64\n", u64Val));
15234 if (pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging)
15235 {
15236 rc = VMXReadVmcs64(VMX_VMCS64_CTRL_EPTP_FULL, &u64Val); AssertRC(rc);
15237 Log4(("VMX_VMCS64_CTRL_EPTP_FULL %#RX64\n", u64Val));
15238 }
15239 hmR0DumpRegs(pVCpu, HM_DUMP_REG_FLAGS_ALL);
15240#endif
15241
15242 return VERR_VMX_INVALID_GUEST_STATE;
15243}
15244
15245/**
15246 * VM-exit handler for all undefined/unexpected reasons. Should never happen.
15247 */
15248HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrUnexpected(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15249{
15250 /*
15251 * Cumulative notes of all recognized but unexpected VM-exits.
15252 *
15253 * 1. This does -not- cover scenarios like a page-fault VM-exit occurring when
15254 * nested-paging is used.
15255 *
15256 * 2. Any instruction that causes a VM-exit unconditionally (for e.g. VMXON) must be
15257 * emulated or a #UD must be raised in the guest. Therefore, we should -not- be using
15258 * this function (and thereby stop VM execution) for handling such instructions.
15259 *
15260 *
15261 * VMX_EXIT_INIT_SIGNAL:
15262 * INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM.
15263 * It is -NOT- blocked in VMX non-root operation so we can, in theory, still get these
15264 * VM-exits. However, we should not receive INIT signals VM-exit while executing a VM.
15265 *
15266 * See Intel spec. 33.14.1 Default Treatment of SMI Delivery"
15267 * See Intel spec. 29.3 "VMX Instructions" for "VMXON".
15268 * See Intel spec. "23.8 Restrictions on VMX operation".
15269 *
15270 * VMX_EXIT_SIPI:
15271 * SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest
15272 * activity state is used. We don't make use of it as our guests don't have direct
15273 * access to the host local APIC.
15274 *
15275 * See Intel spec. 25.3 "Other Causes of VM-exits".
15276 *
15277 * VMX_EXIT_IO_SMI:
15278 * VMX_EXIT_SMI:
15279 * This can only happen if we support dual-monitor treatment of SMI, which can be
15280 * activated by executing VMCALL in VMX root operation. Only an STM (SMM transfer
15281 * monitor) would get this VM-exit when we (the executive monitor) execute a VMCALL in
15282 * VMX root mode or receive an SMI. If we get here, something funny is going on.
15283 *
15284 * See Intel spec. 33.15.6 "Activating the Dual-Monitor Treatment"
15285 * See Intel spec. 25.3 "Other Causes of VM-Exits"
15286 *
15287 * VMX_EXIT_ERR_MSR_LOAD:
15288 * Failures while loading MSRs are part of the VM-entry MSR-load area are unexpected
15289 * and typically indicates a bug in the hypervisor code. We thus cannot not resume
15290 * execution.
15291 *
15292 * See Intel spec. 26.7 "VM-Entry Failures During Or After Loading Guest State".
15293 *
15294 * VMX_EXIT_ERR_MACHINE_CHECK:
15295 * Machine check exceptions indicates a fatal/unrecoverable hardware condition
15296 * including but not limited to system bus, ECC, parity, cache and TLB errors. A
15297 * #MC exception abort class exception is raised. We thus cannot assume a
15298 * reasonable chance of continuing any sort of execution and we bail.
15299 *
15300 * See Intel spec. 15.1 "Machine-check Architecture".
15301 * See Intel spec. 27.1 "Architectural State Before A VM Exit".
15302 *
15303 * VMX_EXIT_PML_FULL:
15304 * VMX_EXIT_VIRTUALIZED_EOI:
15305 * VMX_EXIT_APIC_WRITE:
15306 * We do not currently support any of these features and thus they are all unexpected
15307 * VM-exits.
15308 *
15309 * VMX_EXIT_GDTR_IDTR_ACCESS:
15310 * VMX_EXIT_LDTR_TR_ACCESS:
15311 * VMX_EXIT_RDRAND:
15312 * VMX_EXIT_RSM:
15313 * VMX_EXIT_VMFUNC:
15314 * VMX_EXIT_ENCLS:
15315 * VMX_EXIT_RDSEED:
15316 * VMX_EXIT_XSAVES:
15317 * VMX_EXIT_XRSTORS:
15318 * VMX_EXIT_UMWAIT:
15319 * VMX_EXIT_TPAUSE:
15320 * VMX_EXIT_LOADIWKEY:
15321 * These VM-exits are -not- caused unconditionally by execution of the corresponding
15322 * instruction. Any VM-exit for these instructions indicate a hardware problem,
15323 * unsupported CPU modes (like SMM) or potentially corrupt VMCS controls.
15324 *
15325 * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
15326 */
15327 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15328 AssertMsgFailed(("Unexpected VM-exit %u\n", pVmxTransient->uExitReason));
15329 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
15330}
15331
15332
15333/**
15334 * VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
15335 */
15336HMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15337{
15338 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15339
15340 /** @todo Optimize this: We currently drag in the whole MSR state
15341 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
15342 * MSRs required. That would require changes to IEM and possibly CPUM too.
15343 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
15344 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15345 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
15346 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
15347 switch (idMsr)
15348 {
15349 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
15350 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
15351 }
15352
15353 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15354 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
15355 AssertRCReturn(rc, rc);
15356
15357 Log4Func(("ecx=%#RX32\n", idMsr));
15358
15359#ifdef VBOX_STRICT
15360 Assert(!pVmxTransient->fIsNestedGuest);
15361 if (pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS)
15362 {
15363 if ( hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr)
15364 && idMsr != MSR_K6_EFER)
15365 {
15366 AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", idMsr));
15367 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15368 }
15369 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15370 {
15371 Assert(pVmcsInfo->pvMsrBitmap);
15372 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
15373 if (fMsrpm & VMXMSRPM_ALLOW_RD)
15374 {
15375 AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", idMsr));
15376 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15377 }
15378 }
15379 }
15380#endif
15381
15382 VBOXSTRICTRC rcStrict = IEMExecDecodedRdmsr(pVCpu, pVmxTransient->cbExitInstr);
15383 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
15384 if (rcStrict == VINF_SUCCESS)
15385 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15386 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15387 {
15388 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15389 rcStrict = VINF_SUCCESS;
15390 }
15391 else
15392 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_READ || rcStrict == VINF_EM_TRIPLE_FAULT,
15393 ("Unexpected IEMExecDecodedRdmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
15394
15395 return rcStrict;
15396}
15397
15398
15399/**
15400 * VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
15401 */
15402HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15403{
15404 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15405
15406 /** @todo Optimize this: We currently drag in the whole MSR state
15407 * (CPUMCTX_EXTRN_ALL_MSRS) here. We should optimize this to only get
15408 * MSRs required. That would require changes to IEM and possibly CPUM too.
15409 * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
15410 uint32_t const idMsr = pVCpu->cpum.GstCtx.ecx;
15411 uint64_t fImport = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
15412
15413 /*
15414 * The FS and GS base MSRs are not part of the above all-MSRs mask.
15415 * Although we don't need to fetch the base as it will be overwritten shortly, while
15416 * loading guest-state we would also load the entire segment register including limit
15417 * and attributes and thus we need to load them here.
15418 */
15419 switch (idMsr)
15420 {
15421 case MSR_K8_FS_BASE: fImport |= CPUMCTX_EXTRN_FS; break;
15422 case MSR_K8_GS_BASE: fImport |= CPUMCTX_EXTRN_GS; break;
15423 }
15424
15425 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15426 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15427 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
15428 AssertRCReturn(rc, rc);
15429
15430 Log4Func(("ecx=%#RX32 edx:eax=%#RX32:%#RX32\n", idMsr, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.eax));
15431
15432 VBOXSTRICTRC rcStrict = IEMExecDecodedWrmsr(pVCpu, pVmxTransient->cbExitInstr);
15433 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
15434
15435 if (rcStrict == VINF_SUCCESS)
15436 {
15437 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
15438
15439 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
15440 if ( idMsr == MSR_IA32_APICBASE
15441 || ( idMsr >= MSR_IA32_X2APIC_START
15442 && idMsr <= MSR_IA32_X2APIC_END))
15443 {
15444 /*
15445 * We've already saved the APIC related guest-state (TPR) in post-run phase.
15446 * When full APIC register virtualization is implemented we'll have to make
15447 * sure APIC state is saved from the VMCS before IEM changes it.
15448 */
15449 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
15450 }
15451 else if (idMsr == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
15452 pVmxTransient->fUpdatedTscOffsettingAndPreemptTimer = false;
15453 else if (idMsr == MSR_K6_EFER)
15454 {
15455 /*
15456 * If the guest touches the EFER MSR we need to update the VM-Entry and VM-Exit controls
15457 * as well, even if it is -not- touching bits that cause paging mode changes (LMA/LME).
15458 * We care about the other bits as well, SCE and NXE. See @bugref{7368}.
15459 */
15460 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_EFER_MSR | HM_CHANGED_VMX_ENTRY_EXIT_CTLS);
15461 }
15462
15463 /* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not used. */
15464 if (!(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_MSR_BITMAPS))
15465 {
15466 switch (idMsr)
15467 {
15468 case MSR_IA32_SYSENTER_CS: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
15469 case MSR_IA32_SYSENTER_EIP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
15470 case MSR_IA32_SYSENTER_ESP: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
15471 case MSR_K8_FS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_FS); break;
15472 case MSR_K8_GS_BASE: ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_GS); break;
15473 case MSR_K6_EFER: /* Nothing to do, already handled above. */ break;
15474 default:
15475 {
15476 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15477 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_LAZY_MSRS);
15478 else if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
15479 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_VMX_GUEST_AUTO_MSRS);
15480 break;
15481 }
15482 }
15483 }
15484#ifdef VBOX_STRICT
15485 else
15486 {
15487 /* Paranoia. Validate that MSRs in the MSR-bitmaps with write-passthru are not intercepted. */
15488 switch (idMsr)
15489 {
15490 case MSR_IA32_SYSENTER_CS:
15491 case MSR_IA32_SYSENTER_EIP:
15492 case MSR_IA32_SYSENTER_ESP:
15493 case MSR_K8_FS_BASE:
15494 case MSR_K8_GS_BASE:
15495 {
15496 AssertMsgFailed(("Unexpected WRMSR for an MSR in the VMCS. ecx=%#RX32\n", idMsr));
15497 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15498 }
15499
15500 /* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
15501 default:
15502 {
15503 if (hmR0VmxIsAutoLoadGuestMsr(pVmcsInfo, idMsr))
15504 {
15505 /* EFER MSR writes are always intercepted. */
15506 if (idMsr != MSR_K6_EFER)
15507 {
15508 AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
15509 idMsr));
15510 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15511 }
15512 }
15513
15514 if (hmR0VmxIsLazyGuestMsr(pVCpu, idMsr))
15515 {
15516 Assert(pVmcsInfo->pvMsrBitmap);
15517 uint32_t fMsrpm = CPUMGetVmxMsrPermission(pVmcsInfo->pvMsrBitmap, idMsr);
15518 if (fMsrpm & VMXMSRPM_ALLOW_WR)
15519 {
15520 AssertMsgFailed(("Unexpected WRMSR for passthru, lazy-restore MSR. ecx=%#RX32\n", idMsr));
15521 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, idMsr);
15522 }
15523 }
15524 break;
15525 }
15526 }
15527 }
15528#endif /* VBOX_STRICT */
15529 }
15530 else if (rcStrict == VINF_IEM_RAISED_XCPT)
15531 {
15532 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
15533 rcStrict = VINF_SUCCESS;
15534 }
15535 else
15536 AssertMsg(rcStrict == VINF_CPUM_R3_MSR_WRITE || rcStrict == VINF_EM_TRIPLE_FAULT,
15537 ("Unexpected IEMExecDecodedWrmsr rc (%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict)));
15538
15539 return rcStrict;
15540}
15541
15542
15543/**
15544 * VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
15545 */
15546HMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15547{
15548 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15549
15550 /** @todo The guest has likely hit a contended spinlock. We might want to
15551 * poke a schedule different guest VCPU. */
15552 int rc = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
15553 if (RT_SUCCESS(rc))
15554 return VINF_EM_RAW_INTERRUPT;
15555
15556 AssertMsgFailed(("hmR0VmxExitPause: Failed to increment RIP. rc=%Rrc\n", rc));
15557 return rc;
15558}
15559
15560
15561/**
15562 * VM-exit handler for when the TPR value is lowered below the specified
15563 * threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
15564 */
15565HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThreshold(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15566{
15567 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15568 Assert(pVmxTransient->pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
15569
15570 /*
15571 * The TPR shadow would've been synced with the APIC TPR in the post-run phase.
15572 * We'll re-evaluate pending interrupts and inject them before the next VM
15573 * entry so we can just continue execution here.
15574 */
15575 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTprBelowThreshold);
15576 return VINF_SUCCESS;
15577}
15578
15579
15580/**
15581 * VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX). Conditional
15582 * VM-exit.
15583 *
15584 * @retval VINF_SUCCESS when guest execution can continue.
15585 * @retval VINF_PGM_SYNC_CR3 CR3 sync is required, back to ring-3.
15586 * @retval VERR_EM_RESCHEDULE_REM when we need to return to ring-3 due to
15587 * incompatible guest state for VMX execution (real-on-v86 case).
15588 */
15589HMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15590{
15591 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15592 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
15593
15594 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15595 hmR0VmxReadExitQualVmcs(pVmxTransient);
15596 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15597
15598 VBOXSTRICTRC rcStrict;
15599 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15600 uint64_t const uExitQual = pVmxTransient->uExitQual;
15601 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(uExitQual);
15602 switch (uAccessType)
15603 {
15604 /*
15605 * MOV to CRx.
15606 */
15607 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
15608 {
15609 /*
15610 * When PAE paging is used, the CPU will reload PAE PDPTEs from CR3 when the guest
15611 * changes certain bits even in CR0, CR4 (and not just CR3). We are currently fine
15612 * since IEM_CPUMCTX_EXTRN_MUST_MASK (used below) includes CR3 which will import
15613 * PAE PDPTEs as well.
15614 */
15615 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
15616 AssertRCReturn(rc, rc);
15617
15618 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0);
15619 uint32_t const uOldCr0 = pVCpu->cpum.GstCtx.cr0;
15620 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15621 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15622
15623 /*
15624 * MOV to CR3 only cause a VM-exit when one or more of the following are true:
15625 * - When nested paging isn't used.
15626 * - If the guest doesn't have paging enabled (intercept CR3 to update shadow page tables).
15627 * - We are executing in the VM debug loop.
15628 */
15629 Assert( iCrReg != 3
15630 || !pVM->hmr0.s.fNestedPaging
15631 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15632 || pVCpu->hmr0.s.fUsingDebugLoop);
15633
15634 /* MOV to CR8 writes only cause VM-exits when TPR shadow is not used. */
15635 Assert( iCrReg != 8
15636 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15637
15638 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15639 AssertMsg( rcStrict == VINF_SUCCESS
15640 || rcStrict == VINF_PGM_SYNC_CR3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15641
15642 /*
15643 * This is a kludge for handling switches back to real mode when we try to use
15644 * V86 mode to run real mode code directly. Problem is that V86 mode cannot
15645 * deal with special selector values, so we have to return to ring-3 and run
15646 * there till the selector values are V86 mode compatible.
15647 *
15648 * Note! Using VINF_EM_RESCHEDULE_REM here rather than VINF_EM_RESCHEDULE since the
15649 * latter is an alias for VINF_IEM_RAISED_XCPT which is asserted at the end of
15650 * this function.
15651 */
15652 if ( iCrReg == 0
15653 && rcStrict == VINF_SUCCESS
15654 && !pVM->hmr0.s.vmx.fUnrestrictedGuest
15655 && CPUMIsGuestInRealModeEx(&pVCpu->cpum.GstCtx)
15656 && (uOldCr0 & X86_CR0_PE)
15657 && !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE))
15658 {
15659 /** @todo Check selectors rather than returning all the time. */
15660 Assert(!pVmxTransient->fIsNestedGuest);
15661 Log4Func(("CR0 write, back to real mode -> VINF_EM_RESCHEDULE_REM\n"));
15662 rcStrict = VINF_EM_RESCHEDULE_REM;
15663 }
15664 break;
15665 }
15666
15667 /*
15668 * MOV from CRx.
15669 */
15670 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
15671 {
15672 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(uExitQual);
15673 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(uExitQual);
15674
15675 /*
15676 * MOV from CR3 only cause a VM-exit when one or more of the following are true:
15677 * - When nested paging isn't used.
15678 * - If the guest doesn't have paging enabled (pass guest's CR3 rather than our identity mapped CR3).
15679 * - We are executing in the VM debug loop.
15680 */
15681 Assert( iCrReg != 3
15682 || !pVM->hmr0.s.fNestedPaging
15683 || !CPUMIsGuestPagingEnabledEx(&pVCpu->cpum.GstCtx)
15684 || pVCpu->hmr0.s.fLeaveDone);
15685
15686 /* MOV from CR8 reads only cause a VM-exit when the TPR shadow feature isn't enabled. */
15687 Assert( iCrReg != 8
15688 || !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW));
15689
15690 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
15691 break;
15692 }
15693
15694 /*
15695 * CLTS (Clear Task-Switch Flag in CR0).
15696 */
15697 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
15698 {
15699 rcStrict = hmR0VmxExitClts(pVCpu, pVmcsInfo, pVmxTransient->cbExitInstr);
15700 break;
15701 }
15702
15703 /*
15704 * LMSW (Load Machine-Status Word into CR0).
15705 * LMSW cannot clear CR0.PE, so no fRealOnV86Active kludge needed here.
15706 */
15707 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW:
15708 {
15709 RTGCPTR GCPtrEffDst;
15710 uint8_t const cbInstr = pVmxTransient->cbExitInstr;
15711 uint16_t const uMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(uExitQual);
15712 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(uExitQual);
15713 if (fMemOperand)
15714 {
15715 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
15716 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
15717 }
15718 else
15719 GCPtrEffDst = NIL_RTGCPTR;
15720 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmcsInfo, cbInstr, uMsw, GCPtrEffDst);
15721 break;
15722 }
15723
15724 default:
15725 {
15726 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
15727 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
15728 }
15729 }
15730
15731 Assert((pVCpu->hm.s.fCtxChanged & (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS))
15732 == (HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS));
15733 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
15734
15735 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitMovCRx, y2);
15736 NOREF(pVM);
15737 return rcStrict;
15738}
15739
15740
15741/**
15742 * VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR). Conditional
15743 * VM-exit.
15744 */
15745HMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15746{
15747 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15748 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitIO, y1);
15749
15750 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
15751 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
15752 hmR0VmxReadExitQualVmcs(pVmxTransient);
15753 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
15754 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_SREG_MASK
15755 | CPUMCTX_EXTRN_EFER);
15756 /* EFER MSR also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
15757 AssertRCReturn(rc, rc);
15758
15759 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
15760 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
15761 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
15762 bool const fIOWrite = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
15763 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
15764 bool const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
15765 bool const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
15766 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
15767
15768 /*
15769 * Update exit history to see if this exit can be optimized.
15770 */
15771 VBOXSTRICTRC rcStrict;
15772 PCEMEXITREC pExitRec = NULL;
15773 if ( !fGstStepping
15774 && !fDbgStepping)
15775 pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
15776 !fIOString
15777 ? !fIOWrite
15778 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_READ)
15779 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_WRITE)
15780 : !fIOWrite
15781 ? EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_READ)
15782 : EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_IO_PORT_STR_WRITE),
15783 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
15784 if (!pExitRec)
15785 {
15786 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
15787 static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving result in AL/AX/EAX. */
15788
15789 uint32_t const cbValue = s_aIOSizes[uIOSize];
15790 uint32_t const cbInstr = pVmxTransient->cbExitInstr;
15791 bool fUpdateRipAlready = false; /* ugly hack, should be temporary. */
15792 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
15793 if (fIOString)
15794 {
15795 /*
15796 * INS/OUTS - I/O String instruction.
15797 *
15798 * Use instruction-information if available, otherwise fall back on
15799 * interpreting the instruction.
15800 */
15801 Log4Func(("cs:rip=%#04x:%#RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15802 AssertReturn(pCtx->dx == uIOPort, VERR_VMX_IPE_2);
15803 bool const fInsOutsInfo = RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS);
15804 if (fInsOutsInfo)
15805 {
15806 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
15807 AssertReturn(pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize <= 2, VERR_VMX_IPE_3);
15808 AssertCompile(IEMMODE_16BIT == 0 && IEMMODE_32BIT == 1 && IEMMODE_64BIT == 2);
15809 IEMMODE const enmAddrMode = (IEMMODE)pVmxTransient->ExitInstrInfo.StrIo.u3AddrSize;
15810 bool const fRep = VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual);
15811 if (fIOWrite)
15812 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, fRep, cbInstr,
15813 pVmxTransient->ExitInstrInfo.StrIo.iSegReg, true /*fIoChecked*/);
15814 else
15815 {
15816 /*
15817 * The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
15818 * Hence "iSegReg" field is undefined in the instruction-information field in VT-x for INS.
15819 * See Intel Instruction spec. for "INS".
15820 * See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
15821 */
15822 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, fRep, cbInstr, true /*fIoChecked*/);
15823 }
15824 }
15825 else
15826 rcStrict = IEMExecOne(pVCpu);
15827
15828 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15829 fUpdateRipAlready = true;
15830 }
15831 else
15832 {
15833 /*
15834 * IN/OUT - I/O instruction.
15835 */
15836 Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
15837 uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
15838 Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
15839 if (fIOWrite)
15840 {
15841 rcStrict = IOMIOPortWrite(pVM, pVCpu, uIOPort, pCtx->eax & uAndVal, cbValue);
15842 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
15843 if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15844 && !pCtx->eflags.Bits.u1TF)
15845 rcStrict = EMRZSetPendingIoPortWrite(pVCpu, uIOPort, cbInstr, cbValue, pCtx->eax & uAndVal);
15846 }
15847 else
15848 {
15849 uint32_t u32Result = 0;
15850 rcStrict = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue);
15851 if (IOM_SUCCESS(rcStrict))
15852 {
15853 /* Save result of I/O IN instr. in AL/AX/EAX. */
15854 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Result & uAndVal);
15855 }
15856 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15857 && !pCtx->eflags.Bits.u1TF)
15858 rcStrict = EMRZSetPendingIoPortRead(pVCpu, uIOPort, cbInstr, cbValue);
15859 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
15860 }
15861 }
15862
15863 if (IOM_SUCCESS(rcStrict))
15864 {
15865 if (!fUpdateRipAlready)
15866 {
15867 hmR0VmxAdvanceGuestRipBy(pVCpu, cbInstr);
15868 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP);
15869 }
15870
15871 /*
15872 * INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru
15873 * while booting Fedora 17 64-bit guest.
15874 *
15875 * See Intel Instruction reference for REP/REPE/REPZ/REPNE/REPNZ.
15876 */
15877 if (fIOString)
15878 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RFLAGS);
15879
15880 /*
15881 * If any I/O breakpoints are armed, we need to check if one triggered
15882 * and take appropriate action.
15883 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
15884 */
15885 rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_DR7);
15886 AssertRCReturn(rc, rc);
15887
15888 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
15889 * execution engines about whether hyper BPs and such are pending. */
15890 uint32_t const uDr7 = pCtx->dr[7];
15891 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
15892 && X86_DR7_ANY_RW_IO(uDr7)
15893 && (pCtx->cr4 & X86_CR4_DE))
15894 || DBGFBpIsHwIoArmed(pVM)))
15895 {
15896 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
15897
15898 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
15899 VMMRZCallRing3Disable(pVCpu);
15900 HM_DISABLE_PREEMPT(pVCpu);
15901
15902 bool fIsGuestDbgActive = CPUMR0DebugStateMaybeSaveGuest(pVCpu, true /* fDr6 */);
15903
15904 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, uIOPort, cbValue);
15905 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
15906 {
15907 /* Raise #DB. */
15908 if (fIsGuestDbgActive)
15909 ASMSetDR6(pCtx->dr[6]);
15910 if (pCtx->dr[7] != uDr7)
15911 pVCpu->hm.s.fCtxChanged |= HM_CHANGED_GUEST_DR7;
15912
15913 hmR0VmxSetPendingXcptDB(pVCpu);
15914 }
15915 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
15916 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
15917 else if ( rcStrict2 != VINF_SUCCESS
15918 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
15919 rcStrict = rcStrict2;
15920 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
15921
15922 HM_RESTORE_PREEMPT();
15923 VMMRZCallRing3Enable(pVCpu);
15924 }
15925 }
15926
15927#ifdef VBOX_STRICT
15928 if ( rcStrict == VINF_IOM_R3_IOPORT_READ
15929 || rcStrict == VINF_EM_PENDING_R3_IOPORT_READ)
15930 Assert(!fIOWrite);
15931 else if ( rcStrict == VINF_IOM_R3_IOPORT_WRITE
15932 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
15933 || rcStrict == VINF_EM_PENDING_R3_IOPORT_WRITE)
15934 Assert(fIOWrite);
15935 else
15936 {
15937# if 0 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
15938 * statuses, that the VMM device and some others may return. See
15939 * IOM_SUCCESS() for guidance. */
15940 AssertMsg( RT_FAILURE(rcStrict)
15941 || rcStrict == VINF_SUCCESS
15942 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
15943 || rcStrict == VINF_EM_DBG_BREAKPOINT
15944 || rcStrict == VINF_EM_RAW_GUEST_TRAP
15945 || rcStrict == VINF_EM_RAW_TO_R3, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
15946# endif
15947 }
15948#endif
15949 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitIO, y1);
15950 }
15951 else
15952 {
15953 /*
15954 * Frequent exit or something needing probing. Get state and call EMHistoryExec.
15955 */
15956 int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
15957 AssertRCReturn(rc2, rc2);
15958 STAM_COUNTER_INC(!fIOString ? fIOWrite ? &pVCpu->hm.s.StatExitIOWrite : &pVCpu->hm.s.StatExitIORead
15959 : fIOWrite ? &pVCpu->hm.s.StatExitIOStringWrite : &pVCpu->hm.s.StatExitIOStringRead);
15960 Log4(("IOExit/%u: %04x:%08RX64: %s%s%s %#x LB %u -> EMHistoryExec\n",
15961 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15962 VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
15963 fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
15964
15965 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
15966 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
15967
15968 Log4(("IOExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
15969 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
15970 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
15971 }
15972 return rcStrict;
15973}
15974
15975
15976/**
15977 * VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH). Unconditional
15978 * VM-exit.
15979 */
15980HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
15981{
15982 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
15983
15984 /* Check if this task-switch occurred while delivery an event through the guest IDT. */
15985 hmR0VmxReadExitQualVmcs(pVmxTransient);
15986 if (VMX_EXIT_QUAL_TASK_SWITCH_TYPE(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT)
15987 {
15988 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
15989 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
15990 {
15991 uint32_t uErrCode;
15992 if (VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(pVmxTransient->uIdtVectoringInfo))
15993 {
15994 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
15995 uErrCode = pVmxTransient->uIdtVectoringErrorCode;
15996 }
15997 else
15998 uErrCode = 0;
15999
16000 RTGCUINTPTR GCPtrFaultAddress;
16001 if (VMX_IDT_VECTORING_INFO_IS_XCPT_PF(pVmxTransient->uIdtVectoringInfo))
16002 GCPtrFaultAddress = pVCpu->cpum.GstCtx.cr2;
16003 else
16004 GCPtrFaultAddress = 0;
16005
16006 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16007
16008 hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
16009 pVmxTransient->cbExitInstr, uErrCode, GCPtrFaultAddress);
16010
16011 Log4Func(("Pending event. uIntType=%#x uVector=%#x\n", VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo),
16012 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo)));
16013 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
16014 return VINF_EM_RAW_INJECT_TRPM_EVENT;
16015 }
16016 }
16017
16018 /* Fall back to the interpreter to emulate the task-switch. */
16019 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
16020 return VERR_EM_INTERPRETER;
16021}
16022
16023
16024/**
16025 * VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional VM-exit.
16026 */
16027HMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16028{
16029 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16030
16031 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16032 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MONITOR_TRAP_FLAG;
16033 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
16034 AssertRC(rc);
16035 return VINF_EM_DBG_STEPPED;
16036}
16037
16038
16039/**
16040 * VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional VM-exit.
16041 */
16042HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16043{
16044 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16045 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitApicAccess);
16046
16047 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16048 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16049 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16050 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16051 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16052
16053 /*
16054 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
16055 */
16056 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
16057 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16058 {
16059 /* For some crazy guest, if an event delivery causes an APIC-access VM-exit, go to instruction emulation. */
16060 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
16061 {
16062 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
16063 return VINF_EM_RAW_INJECT_TRPM_EVENT;
16064 }
16065 }
16066 else
16067 {
16068 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
16069 return rcStrict;
16070 }
16071
16072 /* IOMMIOPhysHandler() below may call into IEM, save the necessary state. */
16073 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16074 hmR0VmxReadExitQualVmcs(pVmxTransient);
16075 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
16076 AssertRCReturn(rc, rc);
16077
16078 /* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
16079 uint32_t const uAccessType = VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual);
16080 switch (uAccessType)
16081 {
16082 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
16083 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
16084 {
16085 AssertMsg( !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW)
16086 || VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual) != XAPIC_OFF_TPR,
16087 ("hmR0VmxExitApicAccess: can't access TPR offset while using TPR shadowing.\n"));
16088
16089 RTGCPHYS GCPhys = pVCpu->hm.s.vmx.u64GstMsrApicBase; /* Always up-to-date, as it is not part of the VMCS. */
16090 GCPhys &= PAGE_BASE_GC_MASK;
16091 GCPhys += VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual);
16092 Log4Func(("Linear access uAccessType=%#x GCPhys=%#RGp Off=%#x\n", uAccessType, GCPhys,
16093 VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual)));
16094
16095 rcStrict = IOMR0MmioPhysHandler(pVCpu->CTX_SUFF(pVM), pVCpu,
16096 uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ ? 0 : X86_TRAP_PF_RW, GCPhys);
16097 Log4Func(("IOMMMIOPhysHandler returned %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
16098 if ( rcStrict == VINF_SUCCESS
16099 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16100 || rcStrict == VERR_PAGE_NOT_PRESENT)
16101 {
16102 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
16103 | HM_CHANGED_GUEST_APIC_TPR);
16104 rcStrict = VINF_SUCCESS;
16105 }
16106 break;
16107 }
16108
16109 default:
16110 {
16111 Log4Func(("uAccessType=%#x\n", uAccessType));
16112 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
16113 break;
16114 }
16115 }
16116
16117 if (rcStrict != VINF_SUCCESS)
16118 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchApicAccessToR3);
16119 return rcStrict;
16120}
16121
16122
16123/**
16124 * VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX). Conditional
16125 * VM-exit.
16126 */
16127HMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16128{
16129 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16130 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16131
16132 /*
16133 * We might also get this VM-exit if the nested-guest isn't intercepting MOV DRx accesses.
16134 * In such a case, rather than disabling MOV DRx intercepts and resuming execution, we
16135 * must emulate the MOV DRx access.
16136 */
16137 if (!pVmxTransient->fIsNestedGuest)
16138 {
16139 /* We should -not- get this VM-exit if the guest's debug registers were active. */
16140 if (pVmxTransient->fWasGuestDebugStateActive)
16141 {
16142 AssertMsgFailed(("Unexpected MOV DRx exit\n"));
16143 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, pVmxTransient->uExitReason);
16144 }
16145
16146 if ( !pVCpu->hm.s.fSingleInstruction
16147 && !pVmxTransient->fWasHyperDebugStateActive)
16148 {
16149 Assert(!DBGFIsStepping(pVCpu));
16150 Assert(pVmcsInfo->u32XcptBitmap & RT_BIT(X86_XCPT_DB));
16151
16152 /* Don't intercept MOV DRx any more. */
16153 pVmcsInfo->u32ProcCtls &= ~VMX_PROC_CTLS_MOV_DR_EXIT;
16154 int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
16155 AssertRC(rc);
16156
16157 /* We're playing with the host CPU state here, make sure we can't preempt or longjmp. */
16158 VMMRZCallRing3Disable(pVCpu);
16159 HM_DISABLE_PREEMPT(pVCpu);
16160
16161 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
16162 CPUMR0LoadGuestDebugState(pVCpu, true /* include DR6 */);
16163 Assert(CPUMIsGuestDebugStateActive(pVCpu));
16164
16165 HM_RESTORE_PREEMPT();
16166 VMMRZCallRing3Enable(pVCpu);
16167
16168#ifdef VBOX_WITH_STATISTICS
16169 hmR0VmxReadExitQualVmcs(pVmxTransient);
16170 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
16171 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
16172 else
16173 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
16174#endif
16175 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
16176 return VINF_SUCCESS;
16177 }
16178 }
16179
16180 /*
16181 * EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER MSR, CS.
16182 * The EFER MSR is always up-to-date.
16183 * Update the segment registers and DR7 from the CPU.
16184 */
16185 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16186 hmR0VmxReadExitQualVmcs(pVmxTransient);
16187 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_DR7);
16188 AssertRCReturn(rc, rc);
16189 Log4Func(("cs:rip=%#04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
16190
16191 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16192 if (VMX_EXIT_QUAL_DRX_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_DRX_DIRECTION_WRITE)
16193 {
16194 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
16195 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual),
16196 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual));
16197 if (RT_SUCCESS(rc))
16198 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_DR7);
16199 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
16200 }
16201 else
16202 {
16203 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
16204 VMX_EXIT_QUAL_DRX_GENREG(pVmxTransient->uExitQual),
16205 VMX_EXIT_QUAL_DRX_REGISTER(pVmxTransient->uExitQual));
16206 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
16207 }
16208
16209 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
16210 if (RT_SUCCESS(rc))
16211 {
16212 int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pVmxTransient);
16213 AssertRCReturn(rc2, rc2);
16214 return VINF_SUCCESS;
16215 }
16216 return rc;
16217}
16218
16219
16220/**
16221 * VM-exit handler for EPT misconfiguration (VMX_EXIT_EPT_MISCONFIG).
16222 * Conditional VM-exit.
16223 */
16224HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16225{
16226 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16227 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16228
16229 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16230 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16231 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16232 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16233 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16234
16235 /*
16236 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
16237 */
16238 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
16239 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16240 {
16241 /*
16242 * In the unlikely case where delivering an event causes an EPT misconfig (MMIO), go back to
16243 * instruction emulation to inject the original event. Otherwise, injecting the original event
16244 * using hardware-assisted VMX would trigger the same EPT misconfig VM-exit again.
16245 */
16246 if (!pVCpu->hm.s.Event.fPending)
16247 { /* likely */ }
16248 else
16249 {
16250 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterpret);
16251#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16252 /** @todo NSTVMX: Think about how this should be handled. */
16253 if (pVmxTransient->fIsNestedGuest)
16254 return VERR_VMX_IPE_3;
16255#endif
16256 return VINF_EM_RAW_INJECT_TRPM_EVENT;
16257 }
16258 }
16259 else
16260 {
16261 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
16262 return rcStrict;
16263 }
16264
16265 /*
16266 * Get sufficient state and update the exit history entry.
16267 */
16268 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16269 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
16270 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
16271 AssertRCReturn(rc, rc);
16272
16273 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
16274 PCEMEXITREC pExitRec = EMHistoryUpdateFlagsAndTypeAndPC(pVCpu,
16275 EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM | EMEXIT_F_HM, EMEXITTYPE_MMIO),
16276 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base);
16277 if (!pExitRec)
16278 {
16279 /*
16280 * If we succeed, resume guest execution.
16281 * If we fail in interpreting the instruction because we couldn't get the guest physical address
16282 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
16283 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
16284 * weird case. See @bugref{6043}.
16285 */
16286 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16287 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16288/** @todo bird: We can probably just go straight to IOM here and assume that
16289 * it's MMIO, then fall back on PGM if that hunch didn't work out so
16290 * well. However, we need to address that aliasing workarounds that
16291 * PGMR0Trap0eHandlerNPMisconfig implements. So, some care is needed.
16292 *
16293 * Might also be interesting to see if we can get this done more or
16294 * less locklessly inside IOM. Need to consider the lookup table
16295 * updating and use a bit more carefully first (or do all updates via
16296 * rendezvous) */
16297 rcStrict = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
16298 Log4Func(("At %#RGp RIP=%#RX64 rc=%Rrc\n", GCPhys, pCtx->rip, VBOXSTRICTRC_VAL(rcStrict)));
16299 if ( rcStrict == VINF_SUCCESS
16300 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16301 || rcStrict == VERR_PAGE_NOT_PRESENT)
16302 {
16303 /* Successfully handled MMIO operation. */
16304 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
16305 | HM_CHANGED_GUEST_APIC_TPR);
16306 rcStrict = VINF_SUCCESS;
16307 }
16308 }
16309 else
16310 {
16311 /*
16312 * Frequent exit or something needing probing. Call EMHistoryExec.
16313 */
16314 Log4(("EptMisscfgExit/%u: %04x:%08RX64: %RGp -> EMHistoryExec\n",
16315 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, GCPhys));
16316
16317 rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
16318 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16319
16320 Log4(("EptMisscfgExit/%u: %04x:%08RX64: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
16321 pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
16322 VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
16323 }
16324 return rcStrict;
16325}
16326
16327
16328/**
16329 * VM-exit handler for EPT violation (VMX_EXIT_EPT_VIOLATION). Conditional
16330 * VM-exit.
16331 */
16332HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16333{
16334 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16335 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16336
16337 hmR0VmxReadExitQualVmcs(pVmxTransient);
16338 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16339 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16340 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16341 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16342 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16343
16344 /*
16345 * If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly.
16346 */
16347 VBOXSTRICTRC rcStrict = hmR0VmxCheckExitDueToEventDelivery(pVCpu, pVmxTransient);
16348 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16349 {
16350 /*
16351 * If delivery of an event causes an EPT violation (true nested #PF and not MMIO),
16352 * we shall resolve the nested #PF and re-inject the original event.
16353 */
16354 if (pVCpu->hm.s.Event.fPending)
16355 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectReflectNPF);
16356 }
16357 else
16358 {
16359 Assert(rcStrict != VINF_HM_DOUBLE_FAULT);
16360 return rcStrict;
16361 }
16362
16363 PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
16364 hmR0VmxReadGuestPhysicalAddrVmcs(pVmxTransient);
16365 int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
16366 AssertRCReturn(rc, rc);
16367
16368 RTGCPHYS const GCPhys = pVmxTransient->uGuestPhysicalAddr;
16369 uint64_t const uExitQual = pVmxTransient->uExitQual;
16370 AssertMsg(((pVmxTransient->uExitQual >> 7) & 3) != 2, ("%#RX64", uExitQual));
16371
16372 RTGCUINT uErrorCode = 0;
16373 if (uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH)
16374 uErrorCode |= X86_TRAP_PF_ID;
16375 if (uExitQual & VMX_EXIT_QUAL_EPT_ACCESS_WRITE)
16376 uErrorCode |= X86_TRAP_PF_RW;
16377 if (uExitQual & (VMX_EXIT_QUAL_EPT_ENTRY_READ | VMX_EXIT_QUAL_EPT_ENTRY_WRITE | VMX_EXIT_QUAL_EPT_ENTRY_EXECUTE))
16378 uErrorCode |= X86_TRAP_PF_P;
16379
16380 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
16381 PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16382 Log4Func(("at %#RX64 (%#RX64 errcode=%#x) cs:rip=%#04x:%#RX64\n", GCPhys, uExitQual, uErrorCode, pCtx->cs.Sel, pCtx->rip));
16383
16384 /*
16385 * Handle the pagefault trap for the nested shadow table.
16386 */
16387 TRPMAssertXcptPF(pVCpu, GCPhys, uErrorCode);
16388 rcStrict = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pCtx), GCPhys);
16389 TRPMResetTrap(pVCpu);
16390
16391 /* Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}. */
16392 if ( rcStrict == VINF_SUCCESS
16393 || rcStrict == VERR_PAGE_TABLE_NOT_PRESENT
16394 || rcStrict == VERR_PAGE_NOT_PRESENT)
16395 {
16396 /* Successfully synced our nested page tables. */
16397 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf);
16398 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS);
16399 return VINF_SUCCESS;
16400 }
16401
16402 Log4Func(("EPT return to ring-3 rcStrict2=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
16403 return rcStrict;
16404}
16405
16406
16407#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16408/**
16409 * VM-exit handler for VMCLEAR (VMX_EXIT_VMCLEAR). Unconditional VM-exit.
16410 */
16411HMVMX_EXIT_DECL hmR0VmxExitVmclear(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16412{
16413 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16414
16415 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16416 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16417 hmR0VmxReadExitQualVmcs(pVmxTransient);
16418 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16419 | CPUMCTX_EXTRN_HWVIRT
16420 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16421 AssertRCReturn(rc, rc);
16422
16423 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16424
16425 VMXVEXITINFO ExitInfo;
16426 RT_ZERO(ExitInfo);
16427 ExitInfo.uReason = pVmxTransient->uExitReason;
16428 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16429 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16430 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16431 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16432
16433 VBOXSTRICTRC rcStrict = IEMExecDecodedVmclear(pVCpu, &ExitInfo);
16434 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16435 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16436 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16437 {
16438 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16439 rcStrict = VINF_SUCCESS;
16440 }
16441 return rcStrict;
16442}
16443
16444
16445/**
16446 * VM-exit handler for VMLAUNCH (VMX_EXIT_VMLAUNCH). Unconditional VM-exit.
16447 */
16448HMVMX_EXIT_DECL hmR0VmxExitVmlaunch(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16449{
16450 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16451
16452 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMLAUNCH,
16453 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
16454 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16455 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16456 AssertRCReturn(rc, rc);
16457
16458 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16459
16460 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
16461 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMLAUNCH);
16462 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
16463 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16464 {
16465 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16466 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
16467 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
16468 }
16469 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
16470 return rcStrict;
16471}
16472
16473
16474/**
16475 * VM-exit handler for VMPTRLD (VMX_EXIT_VMPTRLD). Unconditional VM-exit.
16476 */
16477HMVMX_EXIT_DECL hmR0VmxExitVmptrld(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16478{
16479 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16480
16481 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16482 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16483 hmR0VmxReadExitQualVmcs(pVmxTransient);
16484 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16485 | CPUMCTX_EXTRN_HWVIRT
16486 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16487 AssertRCReturn(rc, rc);
16488
16489 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16490
16491 VMXVEXITINFO ExitInfo;
16492 RT_ZERO(ExitInfo);
16493 ExitInfo.uReason = pVmxTransient->uExitReason;
16494 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16495 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16496 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16497 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16498
16499 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrld(pVCpu, &ExitInfo);
16500 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16501 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16502 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16503 {
16504 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16505 rcStrict = VINF_SUCCESS;
16506 }
16507 return rcStrict;
16508}
16509
16510
16511/**
16512 * VM-exit handler for VMPTRST (VMX_EXIT_VMPTRST). Unconditional VM-exit.
16513 */
16514HMVMX_EXIT_DECL hmR0VmxExitVmptrst(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16515{
16516 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16517
16518 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16519 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16520 hmR0VmxReadExitQualVmcs(pVmxTransient);
16521 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16522 | CPUMCTX_EXTRN_HWVIRT
16523 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16524 AssertRCReturn(rc, rc);
16525
16526 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16527
16528 VMXVEXITINFO ExitInfo;
16529 RT_ZERO(ExitInfo);
16530 ExitInfo.uReason = pVmxTransient->uExitReason;
16531 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16532 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16533 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16534 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
16535
16536 VBOXSTRICTRC rcStrict = IEMExecDecodedVmptrst(pVCpu, &ExitInfo);
16537 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16538 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16539 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16540 {
16541 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16542 rcStrict = VINF_SUCCESS;
16543 }
16544 return rcStrict;
16545}
16546
16547
16548/**
16549 * VM-exit handler for VMREAD (VMX_EXIT_VMREAD). Conditional VM-exit.
16550 */
16551HMVMX_EXIT_DECL hmR0VmxExitVmread(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16552{
16553 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16554
16555 /*
16556 * Strictly speaking we should not get VMREAD VM-exits for shadow VMCS fields and
16557 * thus might not need to import the shadow VMCS state, it's safer just in case
16558 * code elsewhere dares look at unsynced VMCS fields.
16559 */
16560 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16561 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16562 hmR0VmxReadExitQualVmcs(pVmxTransient);
16563 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16564 | CPUMCTX_EXTRN_HWVIRT
16565 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16566 AssertRCReturn(rc, rc);
16567
16568 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16569
16570 VMXVEXITINFO ExitInfo;
16571 RT_ZERO(ExitInfo);
16572 ExitInfo.uReason = pVmxTransient->uExitReason;
16573 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16574 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16575 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16576 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
16577 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_WRITE, &ExitInfo.GCPtrEffAddr);
16578
16579 VBOXSTRICTRC rcStrict = IEMExecDecodedVmread(pVCpu, &ExitInfo);
16580 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16581 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16582 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16583 {
16584 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16585 rcStrict = VINF_SUCCESS;
16586 }
16587 return rcStrict;
16588}
16589
16590
16591/**
16592 * VM-exit handler for VMRESUME (VMX_EXIT_VMRESUME). Unconditional VM-exit.
16593 */
16594HMVMX_EXIT_DECL hmR0VmxExitVmresume(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16595{
16596 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16597
16598 /* Import the entire VMCS state for now as we would be switching VMCS on successful VMRESUME,
16599 otherwise we could import just IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK. */
16600 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16601 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16602 AssertRCReturn(rc, rc);
16603
16604 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16605
16606 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitVmentry, z);
16607 VBOXSTRICTRC rcStrict = IEMExecDecodedVmlaunchVmresume(pVCpu, pVmxTransient->cbExitInstr, VMXINSTRID_VMRESUME);
16608 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitVmentry, z);
16609 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16610 {
16611 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
16612 if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
16613 rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
16614 }
16615 Assert(rcStrict != VINF_IEM_RAISED_XCPT);
16616 return rcStrict;
16617}
16618
16619
16620/**
16621 * VM-exit handler for VMWRITE (VMX_EXIT_VMWRITE). Conditional VM-exit.
16622 */
16623HMVMX_EXIT_DECL hmR0VmxExitVmwrite(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16624{
16625 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16626
16627 /*
16628 * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since our HM hook
16629 * gets invoked when IEM's VMWRITE instruction emulation modifies the current VMCS and it
16630 * flags re-loading the entire shadow VMCS, we should save the entire shadow VMCS here.
16631 */
16632 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16633 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16634 hmR0VmxReadExitQualVmcs(pVmxTransient);
16635 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16636 | CPUMCTX_EXTRN_HWVIRT
16637 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16638 AssertRCReturn(rc, rc);
16639
16640 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16641
16642 VMXVEXITINFO ExitInfo;
16643 RT_ZERO(ExitInfo);
16644 ExitInfo.uReason = pVmxTransient->uExitReason;
16645 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16646 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16647 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16648 if (!ExitInfo.InstrInfo.VmreadVmwrite.fIsRegOperand)
16649 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16650
16651 VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
16652 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16653 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16654 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16655 {
16656 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16657 rcStrict = VINF_SUCCESS;
16658 }
16659 return rcStrict;
16660}
16661
16662
16663/**
16664 * VM-exit handler for VMXOFF (VMX_EXIT_VMXOFF). Unconditional VM-exit.
16665 */
16666HMVMX_EXIT_DECL hmR0VmxExitVmxoff(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16667{
16668 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16669
16670 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16671 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
16672 | CPUMCTX_EXTRN_HWVIRT
16673 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
16674 AssertRCReturn(rc, rc);
16675
16676 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16677
16678 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxoff(pVCpu, pVmxTransient->cbExitInstr);
16679 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16680 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_HWVIRT);
16681 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16682 {
16683 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16684 rcStrict = VINF_SUCCESS;
16685 }
16686 return rcStrict;
16687}
16688
16689
16690/**
16691 * VM-exit handler for VMXON (VMX_EXIT_VMXON). Unconditional VM-exit.
16692 */
16693HMVMX_EXIT_DECL hmR0VmxExitVmxon(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16694{
16695 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16696
16697 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16698 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16699 hmR0VmxReadExitQualVmcs(pVmxTransient);
16700 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16701 | CPUMCTX_EXTRN_HWVIRT
16702 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16703 AssertRCReturn(rc, rc);
16704
16705 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16706
16707 VMXVEXITINFO ExitInfo;
16708 RT_ZERO(ExitInfo);
16709 ExitInfo.uReason = pVmxTransient->uExitReason;
16710 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16711 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16712 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16713 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16714
16715 VBOXSTRICTRC rcStrict = IEMExecDecodedVmxon(pVCpu, &ExitInfo);
16716 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16717 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS | HM_CHANGED_GUEST_HWVIRT);
16718 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16719 {
16720 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16721 rcStrict = VINF_SUCCESS;
16722 }
16723 return rcStrict;
16724}
16725
16726
16727/**
16728 * VM-exit handler for INVVPID (VMX_EXIT_INVVPID). Unconditional VM-exit.
16729 */
16730HMVMX_EXIT_DECL hmR0VmxExitInvvpid(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16731{
16732 HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16733
16734 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16735 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
16736 hmR0VmxReadExitQualVmcs(pVmxTransient);
16737 int rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
16738 | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
16739 AssertRCReturn(rc, rc);
16740
16741 HMVMX_CHECK_EXIT_DUE_TO_VMX_INSTR(pVCpu, pVmxTransient->uExitReason);
16742
16743 VMXVEXITINFO ExitInfo;
16744 RT_ZERO(ExitInfo);
16745 ExitInfo.uReason = pVmxTransient->uExitReason;
16746 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16747 ExitInfo.InstrInfo.u = pVmxTransient->ExitInstrInfo.u;
16748 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16749 HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
16750
16751 VBOXSTRICTRC rcStrict = IEMExecDecodedInvvpid(pVCpu, &ExitInfo);
16752 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
16753 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
16754 else if (rcStrict == VINF_IEM_RAISED_XCPT)
16755 {
16756 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
16757 rcStrict = VINF_SUCCESS;
16758 }
16759 return rcStrict;
16760}
16761#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
16762/** @} */
16763
16764
16765#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
16766/** @name Nested-guest VM-exit handlers.
16767 * @{
16768 */
16769/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16770/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Nested-guest VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16771/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
16772
16773/**
16774 * Nested-guest VM-exit handler for exceptions or NMIs (VMX_EXIT_XCPT_OR_NMI).
16775 * Conditional VM-exit.
16776 */
16777HMVMX_EXIT_DECL hmR0VmxExitXcptOrNmiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16778{
16779 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16780
16781 hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
16782
16783 uint64_t const uExitIntInfo = pVmxTransient->uExitIntInfo;
16784 uint32_t const uExitIntType = VMX_EXIT_INT_INFO_TYPE(uExitIntInfo);
16785 Assert(VMX_EXIT_INT_INFO_IS_VALID(uExitIntInfo));
16786
16787 switch (uExitIntType)
16788 {
16789 /*
16790 * Physical NMIs:
16791 * We shouldn't direct host physical NMIs to the nested-guest. Dispatch it to the host.
16792 */
16793 case VMX_EXIT_INT_INFO_TYPE_NMI:
16794 return hmR0VmxExitHostNmi(pVCpu, pVmxTransient->pVmcsInfo);
16795
16796 /*
16797 * Hardware exceptions,
16798 * Software exceptions,
16799 * Privileged software exceptions:
16800 * Figure out if the exception must be delivered to the guest or the nested-guest.
16801 */
16802 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT:
16803 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT:
16804 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT:
16805 {
16806 hmR0VmxReadExitIntErrorCodeVmcs(pVmxTransient);
16807 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16808 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16809 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16810
16811 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
16812 bool const fIntercept = CPUMIsGuestVmxXcptInterceptSet(pCtx, VMX_EXIT_INT_INFO_VECTOR(uExitIntInfo),
16813 pVmxTransient->uExitIntErrorCode);
16814 if (fIntercept)
16815 {
16816 /* Exit qualification is required for debug and page-fault exceptions. */
16817 hmR0VmxReadExitQualVmcs(pVmxTransient);
16818
16819 /*
16820 * For VM-exits due to software exceptions (those generated by INT3 or INTO) and privileged
16821 * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
16822 * length. However, if delivery of a software interrupt, software exception or privileged
16823 * software exception causes a VM-exit, that too provides the VM-exit instruction length.
16824 */
16825 VMXVEXITINFO ExitInfo;
16826 RT_ZERO(ExitInfo);
16827 ExitInfo.uReason = pVmxTransient->uExitReason;
16828 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16829 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16830
16831 VMXVEXITEVENTINFO ExitEventInfo;
16832 RT_ZERO(ExitEventInfo);
16833 ExitEventInfo.uExitIntInfo = pVmxTransient->uExitIntInfo;
16834 ExitEventInfo.uExitIntErrCode = pVmxTransient->uExitIntErrorCode;
16835 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16836 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16837
16838#ifdef DEBUG_ramshankar
16839 hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
16840 Log4Func(("exit_int_info=%#RX32 err_code=%#RX32 exit_qual=%#RX64\n", pVmxTransient->uExitIntInfo,
16841 pVmxTransient->uExitIntErrorCode, pVmxTransient->uExitQual));
16842 if (VMX_IDT_VECTORING_INFO_IS_VALID(pVmxTransient->uIdtVectoringInfo))
16843 {
16844 Log4Func(("idt_info=%#RX32 idt_errcode=%#RX32 cr2=%#RX64\n", pVmxTransient->uIdtVectoringInfo,
16845 pVmxTransient->uIdtVectoringErrorCode, pCtx->cr2));
16846 }
16847#endif
16848 return IEMExecVmxVmexitXcpt(pVCpu, &ExitInfo, &ExitEventInfo);
16849 }
16850
16851 /* Nested paging is currently a requirement, otherwise we would need to handle shadow #PFs in hmR0VmxExitXcptPF. */
16852 Assert(pVCpu->CTX_SUFF(pVM)->hmr0.s.fNestedPaging);
16853 return hmR0VmxExitXcpt(pVCpu, pVmxTransient);
16854 }
16855
16856 /*
16857 * Software interrupts:
16858 * VM-exits cannot be caused by software interrupts.
16859 *
16860 * External interrupts:
16861 * This should only happen when "acknowledge external interrupts on VM-exit"
16862 * control is set. However, we never set this when executing a guest or
16863 * nested-guest. For nested-guests it is emulated while injecting interrupts into
16864 * the guest.
16865 */
16866 case VMX_EXIT_INT_INFO_TYPE_SW_INT:
16867 case VMX_EXIT_INT_INFO_TYPE_EXT_INT:
16868 default:
16869 {
16870 pVCpu->hm.s.u32HMError = pVmxTransient->uExitIntInfo;
16871 return VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE;
16872 }
16873 }
16874}
16875
16876
16877/**
16878 * Nested-guest VM-exit handler for triple faults (VMX_EXIT_TRIPLE_FAULT).
16879 * Unconditional VM-exit.
16880 */
16881HMVMX_EXIT_DECL hmR0VmxExitTripleFaultNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16882{
16883 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16884 return IEMExecVmxVmexitTripleFault(pVCpu);
16885}
16886
16887
16888/**
16889 * Nested-guest VM-exit handler for interrupt-window exiting (VMX_EXIT_INT_WINDOW).
16890 */
16891HMVMX_EXIT_NSRC_DECL hmR0VmxExitIntWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16892{
16893 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16894
16895 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INT_WINDOW_EXIT))
16896 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16897 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16898}
16899
16900
16901/**
16902 * Nested-guest VM-exit handler for NMI-window exiting (VMX_EXIT_NMI_WINDOW).
16903 */
16904HMVMX_EXIT_NSRC_DECL hmR0VmxExitNmiWindowNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16905{
16906 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16907
16908 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_NMI_WINDOW_EXIT))
16909 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, 0 /* uExitQual */);
16910 return hmR0VmxExitIntWindow(pVCpu, pVmxTransient);
16911}
16912
16913
16914/**
16915 * Nested-guest VM-exit handler for task switches (VMX_EXIT_TASK_SWITCH).
16916 * Unconditional VM-exit.
16917 */
16918HMVMX_EXIT_DECL hmR0VmxExitTaskSwitchNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16919{
16920 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16921
16922 hmR0VmxReadExitQualVmcs(pVmxTransient);
16923 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16924 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
16925 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
16926
16927 VMXVEXITINFO ExitInfo;
16928 RT_ZERO(ExitInfo);
16929 ExitInfo.uReason = pVmxTransient->uExitReason;
16930 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16931 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16932
16933 VMXVEXITEVENTINFO ExitEventInfo;
16934 RT_ZERO(ExitEventInfo);
16935 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
16936 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
16937 return IEMExecVmxVmexitTaskSwitch(pVCpu, &ExitInfo, &ExitEventInfo);
16938}
16939
16940
16941/**
16942 * Nested-guest VM-exit handler for HLT (VMX_EXIT_HLT). Conditional VM-exit.
16943 */
16944HMVMX_EXIT_DECL hmR0VmxExitHltNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16945{
16946 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16947
16948 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_HLT_EXIT))
16949 {
16950 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16951 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16952 }
16953 return hmR0VmxExitHlt(pVCpu, pVmxTransient);
16954}
16955
16956
16957/**
16958 * Nested-guest VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
16959 */
16960HMVMX_EXIT_DECL hmR0VmxExitInvlpgNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16961{
16962 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16963
16964 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
16965 {
16966 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16967 hmR0VmxReadExitQualVmcs(pVmxTransient);
16968
16969 VMXVEXITINFO ExitInfo;
16970 RT_ZERO(ExitInfo);
16971 ExitInfo.uReason = pVmxTransient->uExitReason;
16972 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
16973 ExitInfo.u64Qual = pVmxTransient->uExitQual;
16974 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
16975 }
16976 return hmR0VmxExitInvlpg(pVCpu, pVmxTransient);
16977}
16978
16979
16980/**
16981 * Nested-guest VM-exit handler for RDPMC (VMX_EXIT_RDPMC). Conditional VM-exit.
16982 */
16983HMVMX_EXIT_DECL hmR0VmxExitRdpmcNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
16984{
16985 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
16986
16987 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDPMC_EXIT))
16988 {
16989 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
16990 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
16991 }
16992 return hmR0VmxExitRdpmc(pVCpu, pVmxTransient);
16993}
16994
16995
16996/**
16997 * Nested-guest VM-exit handler for VMREAD (VMX_EXIT_VMREAD) and VMWRITE
16998 * (VMX_EXIT_VMWRITE). Conditional VM-exit.
16999 */
17000HMVMX_EXIT_DECL hmR0VmxExitVmreadVmwriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17001{
17002 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17003
17004 Assert( pVmxTransient->uExitReason == VMX_EXIT_VMREAD
17005 || pVmxTransient->uExitReason == VMX_EXIT_VMWRITE);
17006
17007 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17008
17009 uint8_t const iGReg = pVmxTransient->ExitInstrInfo.VmreadVmwrite.iReg2;
17010 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
17011 uint64_t u64VmcsField = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
17012
17013 HMVMX_CPUMCTX_ASSERT(pVCpu, CPUMCTX_EXTRN_EFER);
17014 if (!CPUMIsGuestInLongModeEx(&pVCpu->cpum.GstCtx))
17015 u64VmcsField &= UINT64_C(0xffffffff);
17016
17017 if (CPUMIsGuestVmxVmreadVmwriteInterceptSet(pVCpu, pVmxTransient->uExitReason, u64VmcsField))
17018 {
17019 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17020 hmR0VmxReadExitQualVmcs(pVmxTransient);
17021
17022 VMXVEXITINFO ExitInfo;
17023 RT_ZERO(ExitInfo);
17024 ExitInfo.uReason = pVmxTransient->uExitReason;
17025 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17026 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17027 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17028 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17029 }
17030
17031 if (pVmxTransient->uExitReason == VMX_EXIT_VMREAD)
17032 return hmR0VmxExitVmread(pVCpu, pVmxTransient);
17033 return hmR0VmxExitVmwrite(pVCpu, pVmxTransient);
17034}
17035
17036
17037/**
17038 * Nested-guest VM-exit handler for RDTSC (VMX_EXIT_RDTSC). Conditional VM-exit.
17039 */
17040HMVMX_EXIT_DECL hmR0VmxExitRdtscNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17041{
17042 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17043
17044 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
17045 {
17046 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17047 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17048 }
17049
17050 return hmR0VmxExitRdtsc(pVCpu, pVmxTransient);
17051}
17052
17053
17054/**
17055 * Nested-guest VM-exit handler for control-register accesses (VMX_EXIT_MOV_CRX).
17056 * Conditional VM-exit.
17057 */
17058HMVMX_EXIT_DECL hmR0VmxExitMovCRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17059{
17060 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17061
17062 hmR0VmxReadExitQualVmcs(pVmxTransient);
17063 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17064
17065 VBOXSTRICTRC rcStrict;
17066 uint32_t const uAccessType = VMX_EXIT_QUAL_CRX_ACCESS(pVmxTransient->uExitQual);
17067 switch (uAccessType)
17068 {
17069 case VMX_EXIT_QUAL_CRX_ACCESS_WRITE:
17070 {
17071 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
17072 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
17073 Assert(iGReg < RT_ELEMENTS(pVCpu->cpum.GstCtx.aGRegs));
17074 uint64_t const uNewCrX = pVCpu->cpum.GstCtx.aGRegs[iGReg].u64;
17075
17076 bool fIntercept;
17077 switch (iCrReg)
17078 {
17079 case 0:
17080 case 4:
17081 fIntercept = CPUMIsGuestVmxMovToCr0Cr4InterceptSet(&pVCpu->cpum.GstCtx, iCrReg, uNewCrX);
17082 break;
17083
17084 case 3:
17085 fIntercept = CPUMIsGuestVmxMovToCr3InterceptSet(pVCpu, uNewCrX);
17086 break;
17087
17088 case 8:
17089 fIntercept = CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_CR8_LOAD_EXIT);
17090 break;
17091
17092 default:
17093 fIntercept = false;
17094 break;
17095 }
17096 if (fIntercept)
17097 {
17098 VMXVEXITINFO ExitInfo;
17099 RT_ZERO(ExitInfo);
17100 ExitInfo.uReason = pVmxTransient->uExitReason;
17101 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17102 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17103 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17104 }
17105 else
17106 {
17107 int const rc = hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
17108 AssertRCReturn(rc, rc);
17109 rcStrict = hmR0VmxExitMovToCrX(pVCpu, pVmxTransient->cbExitInstr, iGReg, iCrReg);
17110 }
17111 break;
17112 }
17113
17114 case VMX_EXIT_QUAL_CRX_ACCESS_READ:
17115 {
17116 /*
17117 * CR0/CR4 reads do not cause VM-exits, the read-shadow is used (subject to masking).
17118 * CR2 reads do not cause a VM-exit.
17119 * CR3 reads cause a VM-exit depending on the "CR3 store exiting" control.
17120 * CR8 reads cause a VM-exit depending on the "CR8 store exiting" control.
17121 */
17122 uint8_t const iCrReg = VMX_EXIT_QUAL_CRX_REGISTER(pVmxTransient->uExitQual);
17123 if ( iCrReg == 3
17124 || iCrReg == 8)
17125 {
17126 static const uint32_t s_auCrXReadIntercepts[] = { 0, 0, 0, VMX_PROC_CTLS_CR3_STORE_EXIT, 0,
17127 0, 0, 0, VMX_PROC_CTLS_CR8_STORE_EXIT };
17128 uint32_t const uIntercept = s_auCrXReadIntercepts[iCrReg];
17129 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, uIntercept))
17130 {
17131 VMXVEXITINFO ExitInfo;
17132 RT_ZERO(ExitInfo);
17133 ExitInfo.uReason = pVmxTransient->uExitReason;
17134 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17135 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17136 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17137 }
17138 else
17139 {
17140 uint8_t const iGReg = VMX_EXIT_QUAL_CRX_GENREG(pVmxTransient->uExitQual);
17141 rcStrict = hmR0VmxExitMovFromCrX(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, iGReg, iCrReg);
17142 }
17143 }
17144 else
17145 {
17146 AssertMsgFailed(("MOV from CR%d VM-exit must not happen\n", iCrReg));
17147 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, iCrReg);
17148 }
17149 break;
17150 }
17151
17152 case VMX_EXIT_QUAL_CRX_ACCESS_CLTS:
17153 {
17154 PCVMXVVMCS const pVmcsNstGst = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs;
17155 uint64_t const uGstHostMask = pVmcsNstGst->u64Cr0Mask.u;
17156 uint64_t const uReadShadow = pVmcsNstGst->u64Cr0ReadShadow.u;
17157 if ( (uGstHostMask & X86_CR0_TS)
17158 && (uReadShadow & X86_CR0_TS))
17159 {
17160 VMXVEXITINFO ExitInfo;
17161 RT_ZERO(ExitInfo);
17162 ExitInfo.uReason = pVmxTransient->uExitReason;
17163 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17164 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17165 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17166 }
17167 else
17168 rcStrict = hmR0VmxExitClts(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr);
17169 break;
17170 }
17171
17172 case VMX_EXIT_QUAL_CRX_ACCESS_LMSW: /* LMSW (Load Machine-Status Word into CR0) */
17173 {
17174 RTGCPTR GCPtrEffDst;
17175 uint16_t const uNewMsw = VMX_EXIT_QUAL_CRX_LMSW_DATA(pVmxTransient->uExitQual);
17176 bool const fMemOperand = VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(pVmxTransient->uExitQual);
17177 if (fMemOperand)
17178 {
17179 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
17180 GCPtrEffDst = pVmxTransient->uGuestLinearAddr;
17181 }
17182 else
17183 GCPtrEffDst = NIL_RTGCPTR;
17184
17185 if (CPUMIsGuestVmxLmswInterceptSet(&pVCpu->cpum.GstCtx, uNewMsw))
17186 {
17187 VMXVEXITINFO ExitInfo;
17188 RT_ZERO(ExitInfo);
17189 ExitInfo.uReason = pVmxTransient->uExitReason;
17190 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17191 ExitInfo.u64GuestLinearAddr = GCPtrEffDst;
17192 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17193 rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17194 }
17195 else
17196 rcStrict = hmR0VmxExitLmsw(pVCpu, pVmxTransient->pVmcsInfo, pVmxTransient->cbExitInstr, uNewMsw, GCPtrEffDst);
17197 break;
17198 }
17199
17200 default:
17201 {
17202 AssertMsgFailed(("Unrecognized Mov CRX access type %#x\n", uAccessType));
17203 HMVMX_UNEXPECTED_EXIT_RET(pVCpu, uAccessType);
17204 }
17205 }
17206
17207 if (rcStrict == VINF_IEM_RAISED_XCPT)
17208 {
17209 ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_RAISED_XCPT_MASK);
17210 rcStrict = VINF_SUCCESS;
17211 }
17212 return rcStrict;
17213}
17214
17215
17216/**
17217 * Nested-guest VM-exit handler for debug-register accesses (VMX_EXIT_MOV_DRX).
17218 * Conditional VM-exit.
17219 */
17220HMVMX_EXIT_DECL hmR0VmxExitMovDRxNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17221{
17222 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17223
17224 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MOV_DR_EXIT))
17225 {
17226 hmR0VmxReadExitQualVmcs(pVmxTransient);
17227 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17228
17229 VMXVEXITINFO ExitInfo;
17230 RT_ZERO(ExitInfo);
17231 ExitInfo.uReason = pVmxTransient->uExitReason;
17232 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17233 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17234 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17235 }
17236 return hmR0VmxExitMovDRx(pVCpu, pVmxTransient);
17237}
17238
17239
17240/**
17241 * Nested-guest VM-exit handler for I/O instructions (VMX_EXIT_IO_INSTR).
17242 * Conditional VM-exit.
17243 */
17244HMVMX_EXIT_DECL hmR0VmxExitIoInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17245{
17246 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17247
17248 hmR0VmxReadExitQualVmcs(pVmxTransient);
17249
17250 uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
17251 uint8_t const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
17252 AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
17253
17254 static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses in bytes. */
17255 uint8_t const cbAccess = s_aIOSizes[uIOSize];
17256 if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
17257 {
17258 /*
17259 * IN/OUT instruction:
17260 * - Provides VM-exit instruction length.
17261 *
17262 * INS/OUTS instruction:
17263 * - Provides VM-exit instruction length.
17264 * - Provides Guest-linear address.
17265 * - Optionally provides VM-exit instruction info (depends on CPU feature).
17266 */
17267 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
17268 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17269
17270 /* Make sure we don't use stale/uninitialized VMX-transient info. below. */
17271 pVmxTransient->ExitInstrInfo.u = 0;
17272 pVmxTransient->uGuestLinearAddr = 0;
17273
17274 bool const fVmxInsOutsInfo = pVM->cpum.ro.GuestFeatures.fVmxInsOutInfo;
17275 bool const fIOString = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
17276 if (fIOString)
17277 {
17278 hmR0VmxReadGuestLinearAddrVmcs(pVmxTransient);
17279 if (fVmxInsOutsInfo)
17280 {
17281 Assert(RT_BF_GET(g_HmMsrs.u.vmx.u64Basic, VMX_BF_BASIC_VMCS_INS_OUTS)); /* Paranoia. */
17282 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17283 }
17284 }
17285
17286 VMXVEXITINFO ExitInfo;
17287 RT_ZERO(ExitInfo);
17288 ExitInfo.uReason = pVmxTransient->uExitReason;
17289 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17290 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17291 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17292 ExitInfo.u64GuestLinearAddr = pVmxTransient->uGuestLinearAddr;
17293 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17294 }
17295 return hmR0VmxExitIoInstr(pVCpu, pVmxTransient);
17296}
17297
17298
17299/**
17300 * Nested-guest VM-exit handler for RDMSR (VMX_EXIT_RDMSR).
17301 */
17302HMVMX_EXIT_DECL hmR0VmxExitRdmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17303{
17304 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17305
17306 uint32_t fMsrpm;
17307 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
17308 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap, pVCpu->cpum.GstCtx.ecx);
17309 else
17310 fMsrpm = VMXMSRPM_EXIT_RD;
17311
17312 if (fMsrpm & VMXMSRPM_EXIT_RD)
17313 {
17314 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17315 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17316 }
17317 return hmR0VmxExitRdmsr(pVCpu, pVmxTransient);
17318}
17319
17320
17321/**
17322 * Nested-guest VM-exit handler for WRMSR (VMX_EXIT_WRMSR).
17323 */
17324HMVMX_EXIT_DECL hmR0VmxExitWrmsrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17325{
17326 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17327
17328 uint32_t fMsrpm;
17329 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_MSR_BITMAPS))
17330 fMsrpm = CPUMGetVmxMsrPermission(pVCpu->cpum.GstCtx.hwvirt.vmx.abMsrBitmap, pVCpu->cpum.GstCtx.ecx);
17331 else
17332 fMsrpm = VMXMSRPM_EXIT_WR;
17333
17334 if (fMsrpm & VMXMSRPM_EXIT_WR)
17335 {
17336 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17337 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17338 }
17339 return hmR0VmxExitWrmsr(pVCpu, pVmxTransient);
17340}
17341
17342
17343/**
17344 * Nested-guest VM-exit handler for MWAIT (VMX_EXIT_MWAIT). Conditional VM-exit.
17345 */
17346HMVMX_EXIT_DECL hmR0VmxExitMwaitNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17347{
17348 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17349
17350 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MWAIT_EXIT))
17351 {
17352 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17353 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17354 }
17355 return hmR0VmxExitMwait(pVCpu, pVmxTransient);
17356}
17357
17358
17359/**
17360 * Nested-guest VM-exit handler for monitor-trap-flag (VMX_EXIT_MTF). Conditional
17361 * VM-exit.
17362 */
17363HMVMX_EXIT_DECL hmR0VmxExitMtfNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17364{
17365 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17366
17367 /** @todo NSTVMX: Should consider debugging nested-guests using VM debugger. */
17368 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
17369 VMXVEXITINFO ExitInfo;
17370 RT_ZERO(ExitInfo);
17371 ExitInfo.uReason = pVmxTransient->uExitReason;
17372 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
17373 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
17374}
17375
17376
17377/**
17378 * Nested-guest VM-exit handler for MONITOR (VMX_EXIT_MONITOR). Conditional VM-exit.
17379 */
17380HMVMX_EXIT_DECL hmR0VmxExitMonitorNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17381{
17382 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17383
17384 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_MONITOR_EXIT))
17385 {
17386 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17387 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17388 }
17389 return hmR0VmxExitMonitor(pVCpu, pVmxTransient);
17390}
17391
17392
17393/**
17394 * Nested-guest VM-exit handler for PAUSE (VMX_EXIT_PAUSE). Conditional VM-exit.
17395 */
17396HMVMX_EXIT_DECL hmR0VmxExitPauseNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17397{
17398 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17399
17400 /** @todo NSTVMX: Think about this more. Does the outer guest need to intercept
17401 * PAUSE when executing a nested-guest? If it does not, we would not need
17402 * to check for the intercepts here. Just call VM-exit... */
17403
17404 /* The CPU would have already performed the necessary CPL checks for PAUSE-loop exiting. */
17405 if ( CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_PAUSE_EXIT)
17406 || CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_PAUSE_LOOP_EXIT))
17407 {
17408 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17409 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17410 }
17411 return hmR0VmxExitPause(pVCpu, pVmxTransient);
17412}
17413
17414
17415/**
17416 * Nested-guest VM-exit handler for when the TPR value is lowered below the
17417 * specified threshold (VMX_EXIT_TPR_BELOW_THRESHOLD). Conditional VM-exit.
17418 */
17419HMVMX_EXIT_NSRC_DECL hmR0VmxExitTprBelowThresholdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17420{
17421 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17422
17423 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_USE_TPR_SHADOW))
17424 {
17425 hmR0VmxReadGuestPendingDbgXctps(pVmxTransient);
17426 VMXVEXITINFO ExitInfo;
17427 RT_ZERO(ExitInfo);
17428 ExitInfo.uReason = pVmxTransient->uExitReason;
17429 ExitInfo.u64GuestPendingDbgXcpts = pVmxTransient->uGuestPendingDbgXcpts;
17430 return IEMExecVmxVmexitTrapLike(pVCpu, &ExitInfo);
17431 }
17432 return hmR0VmxExitTprBelowThreshold(pVCpu, pVmxTransient);
17433}
17434
17435
17436/**
17437 * Nested-guest VM-exit handler for APIC access (VMX_EXIT_APIC_ACCESS). Conditional
17438 * VM-exit.
17439 */
17440HMVMX_EXIT_DECL hmR0VmxExitApicAccessNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17441{
17442 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17443
17444 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17445 hmR0VmxReadIdtVectoringInfoVmcs(pVmxTransient);
17446 hmR0VmxReadIdtVectoringErrorCodeVmcs(pVmxTransient);
17447 hmR0VmxReadExitQualVmcs(pVmxTransient);
17448
17449 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
17450
17451 Log4Func(("at offset %#x type=%u\n", VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(pVmxTransient->uExitQual),
17452 VMX_EXIT_QUAL_APIC_ACCESS_TYPE(pVmxTransient->uExitQual)));
17453
17454 VMXVEXITINFO ExitInfo;
17455 RT_ZERO(ExitInfo);
17456 ExitInfo.uReason = pVmxTransient->uExitReason;
17457 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17458 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17459
17460 VMXVEXITEVENTINFO ExitEventInfo;
17461 RT_ZERO(ExitEventInfo);
17462 ExitEventInfo.uIdtVectoringInfo = pVmxTransient->uIdtVectoringInfo;
17463 ExitEventInfo.uIdtVectoringErrCode = pVmxTransient->uIdtVectoringErrorCode;
17464 return IEMExecVmxVmexitApicAccess(pVCpu, &ExitInfo, &ExitEventInfo);
17465}
17466
17467
17468/**
17469 * Nested-guest VM-exit handler for APIC write emulation (VMX_EXIT_APIC_WRITE).
17470 * Conditional VM-exit.
17471 */
17472HMVMX_EXIT_DECL hmR0VmxExitApicWriteNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17473{
17474 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17475
17476 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_APIC_REG_VIRT));
17477 hmR0VmxReadExitQualVmcs(pVmxTransient);
17478 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
17479}
17480
17481
17482/**
17483 * Nested-guest VM-exit handler for virtualized EOI (VMX_EXIT_VIRTUALIZED_EOI).
17484 * Conditional VM-exit.
17485 */
17486HMVMX_EXIT_DECL hmR0VmxExitVirtEoiNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17487{
17488 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17489
17490 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_VIRT_INT_DELIVERY));
17491 hmR0VmxReadExitQualVmcs(pVmxTransient);
17492 return IEMExecVmxVmexit(pVCpu, pVmxTransient->uExitReason, pVmxTransient->uExitQual);
17493}
17494
17495
17496/**
17497 * Nested-guest VM-exit handler for RDTSCP (VMX_EXIT_RDTSCP). Conditional VM-exit.
17498 */
17499HMVMX_EXIT_DECL hmR0VmxExitRdtscpNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17500{
17501 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17502
17503 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT))
17504 {
17505 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_RDTSCP));
17506 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17507 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17508 }
17509 return hmR0VmxExitRdtscp(pVCpu, pVmxTransient);
17510}
17511
17512
17513/**
17514 * Nested-guest VM-exit handler for WBINVD (VMX_EXIT_WBINVD). Conditional VM-exit.
17515 */
17516HMVMX_EXIT_NSRC_DECL hmR0VmxExitWbinvdNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17517{
17518 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17519
17520 if (CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_WBINVD_EXIT))
17521 {
17522 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17523 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17524 }
17525 return hmR0VmxExitWbinvd(pVCpu, pVmxTransient);
17526}
17527
17528
17529/**
17530 * Nested-guest VM-exit handler for INVPCID (VMX_EXIT_INVPCID). Conditional VM-exit.
17531 */
17532HMVMX_EXIT_DECL hmR0VmxExitInvpcidNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17533{
17534 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17535
17536 if (CPUMIsGuestVmxProcCtlsSet(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS_INVLPG_EXIT))
17537 {
17538 Assert(CPUMIsGuestVmxProcCtls2Set(&pVCpu->cpum.GstCtx, VMX_PROC_CTLS2_INVPCID));
17539 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17540 hmR0VmxReadExitQualVmcs(pVmxTransient);
17541 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17542
17543 VMXVEXITINFO ExitInfo;
17544 RT_ZERO(ExitInfo);
17545 ExitInfo.uReason = pVmxTransient->uExitReason;
17546 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17547 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17548 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17549 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17550 }
17551 return hmR0VmxExitInvpcid(pVCpu, pVmxTransient);
17552}
17553
17554
17555/**
17556 * Nested-guest VM-exit handler for invalid-guest state
17557 * (VMX_EXIT_ERR_INVALID_GUEST_STATE). Error VM-exit.
17558 */
17559HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestStateNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17560{
17561 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17562
17563 /*
17564 * Currently this should never happen because we fully emulate VMLAUNCH/VMRESUME in IEM.
17565 * So if it does happen, it indicates a bug possibly in the hardware-assisted VMX code.
17566 * Handle it like it's in an invalid guest state of the outer guest.
17567 *
17568 * When the fast path is implemented, this should be changed to cause the corresponding
17569 * nested-guest VM-exit.
17570 */
17571 return hmR0VmxExitErrInvalidGuestState(pVCpu, pVmxTransient);
17572}
17573
17574
17575/**
17576 * Nested-guest VM-exit handler for instructions that cause VM-exits uncondtionally
17577 * and only provide the instruction length.
17578 *
17579 * Unconditional VM-exit.
17580 */
17581HMVMX_EXIT_DECL hmR0VmxExitInstrNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17582{
17583 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17584
17585#ifdef VBOX_STRICT
17586 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
17587 switch (pVmxTransient->uExitReason)
17588 {
17589 case VMX_EXIT_ENCLS:
17590 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_ENCLS_EXIT));
17591 break;
17592
17593 case VMX_EXIT_VMFUNC:
17594 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_VMFUNC));
17595 break;
17596 }
17597#endif
17598
17599 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17600 return IEMExecVmxVmexitInstr(pVCpu, pVmxTransient->uExitReason, pVmxTransient->cbExitInstr);
17601}
17602
17603
17604/**
17605 * Nested-guest VM-exit handler for instructions that provide instruction length as
17606 * well as more information.
17607 *
17608 * Unconditional VM-exit.
17609 */
17610HMVMX_EXIT_DECL hmR0VmxExitInstrWithInfoNested(PVMCPUCC pVCpu, PVMXTRANSIENT pVmxTransient)
17611{
17612 HMVMX_VALIDATE_NESTED_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
17613
17614#ifdef VBOX_STRICT
17615 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
17616 switch (pVmxTransient->uExitReason)
17617 {
17618 case VMX_EXIT_GDTR_IDTR_ACCESS:
17619 case VMX_EXIT_LDTR_TR_ACCESS:
17620 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_DESC_TABLE_EXIT));
17621 break;
17622
17623 case VMX_EXIT_RDRAND:
17624 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDRAND_EXIT));
17625 break;
17626
17627 case VMX_EXIT_RDSEED:
17628 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_RDSEED_EXIT));
17629 break;
17630
17631 case VMX_EXIT_XSAVES:
17632 case VMX_EXIT_XRSTORS:
17633 /** @todo NSTVMX: Verify XSS-bitmap. */
17634 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_XSAVES_XRSTORS));
17635 break;
17636
17637 case VMX_EXIT_UMWAIT:
17638 case VMX_EXIT_TPAUSE:
17639 Assert(CPUMIsGuestVmxProcCtlsSet(pCtx, VMX_PROC_CTLS_RDTSC_EXIT));
17640 Assert(CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_USER_WAIT_PAUSE));
17641 break;
17642
17643 case VMX_EXIT_LOADIWKEY:
17644 Assert(CPUMIsGuestVmxProcCtls3Set(pCtx, VMX_PROC_CTLS3_LOADIWKEY_EXIT));
17645 break;
17646 }
17647#endif
17648
17649 hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
17650 hmR0VmxReadExitQualVmcs(pVmxTransient);
17651 hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
17652
17653 VMXVEXITINFO ExitInfo;
17654 RT_ZERO(ExitInfo);
17655 ExitInfo.uReason = pVmxTransient->uExitReason;
17656 ExitInfo.cbInstr = pVmxTransient->cbExitInstr;
17657 ExitInfo.u64Qual = pVmxTransient->uExitQual;
17658 ExitInfo.InstrInfo = pVmxTransient->ExitInstrInfo;
17659 return IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
17660}
17661
17662/** @} */
17663#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
17664
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